Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qaccessiblemenu.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// Qt-Security score:significant reason:default
4
6
7#if QT_CONFIG(menu)
8#include <qmenu.h>
9#endif
10#if QT_CONFIG(menubar)
11#include <qmenubar.h>
12#endif
13#include <qstyle.h>
14#include <private/qwidget_p.h>
15
16#if QT_CONFIG(accessibility)
17
18#include <QtGui/private/qaccessiblehelper_p.h>
19
20QT_BEGIN_NAMESPACE
21
22#if QT_CONFIG(menu)
23
24QString qt_accHotKey(const QString &text);
25
26QAccessibleInterface *getOrCreateMenu(QWidget *menu, QAction *action)
27{
28 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(action);
29 if (!iface) {
30 iface = new QAccessibleMenuItem(menu, action);
31 QAccessible::registerAccessibleInterface(iface);
32 }
33 return iface;
34}
35
36QAccessibleMenu::QAccessibleMenu(QWidget *w)
37: QAccessibleWidgetV2(w)
38{
39 Q_ASSERT(menu());
40}
41
42QMenu *QAccessibleMenu::menu() const
43{
44 return qobject_cast<QMenu*>(object());
45}
46
47int QAccessibleMenu::childCount() const
48{
49 return menu()->actions().size();
50}
51
52QAccessibleInterface *QAccessibleMenu::childAt(int x, int y) const
53{
54 QAction *act = menu()->actionAt(menu()->mapFromGlobal(QPoint(x,y)));
55 if (act && act->isSeparator())
56 act = nullptr;
57 return act ? getOrCreateMenu(menu(), act) : nullptr;
58}
59
60QString QAccessibleMenu::text(QAccessible::Text t) const
61{
62 QString tx = QAccessibleWidgetV2::text(t);
63 if (!tx.isEmpty())
64 return tx;
65
66 if (t == QAccessible::Name)
67 return menu()->windowTitle();
68 return tx;
69}
70
71QAccessible::Role QAccessibleMenu::role() const
72{
73 return QAccessible::PopupMenu;
74}
75
76QAccessibleInterface *QAccessibleMenu::child(int index) const
77{
78 if (index < childCount())
79 return getOrCreateMenu(menu(), menu()->actions().at(index));
80 return nullptr;
81}
82
83QAccessibleInterface *QAccessibleMenu::parent() const
84{
85 if (QAction *menuAction = menu()->menuAction()) {
86 QList<QObject *> parentCandidates;
87 const QList<QObject *> associatedObjects = menuAction->associatedObjects();
88 parentCandidates.reserve(associatedObjects.size() + 1);
89 parentCandidates << menu()->parentWidget() << associatedObjects;
90 for (QObject *object : std::as_const(parentCandidates)) {
91 if (qobject_cast<QMenu*>(object)
92#if QT_CONFIG(menubar)
93 || qobject_cast<QMenuBar*>(object)
94#endif
95 ) {
96 QWidget *widget = static_cast<QWidget*>(object);
97 if (widget->actions().indexOf(menuAction) != -1)
98 return getOrCreateMenu(widget, menuAction);
99 }
100 }
101 }
102 return QAccessibleWidgetV2::parent();
103}
104
105int QAccessibleMenu::indexOfChild( const QAccessibleInterface *child) const
106{
107 QAccessible::Role r = child->role();
108 if ((r == QAccessible::MenuItem || r == QAccessible::Separator) && menu()) {
109 return menu()->actions().indexOf(qobject_cast<QAction*>(child->object()));
110 }
111 return -1;
112}
113
114#if QT_CONFIG(menubar)
115QAccessibleMenuBar::QAccessibleMenuBar(QWidget *w)
116 : QAccessibleWidgetV2(w, QAccessible::MenuBar)
117{
118 Q_ASSERT(menuBar());
119}
120
121QMenuBar *QAccessibleMenuBar::menuBar() const
122{
123 return qobject_cast<QMenuBar*>(object());
124}
125
126int QAccessibleMenuBar::childCount() const
127{
128 return menuBar()->actions().size();
129}
130
131QAccessibleInterface *QAccessibleMenuBar::child(int index) const
132{
133 if (index < childCount()) {
134 return getOrCreateMenu(menuBar(), menuBar()->actions().at(index));
135 }
136 return nullptr;
137}
138
139int QAccessibleMenuBar::indexOfChild(const QAccessibleInterface *child) const
140{
141 QAccessible::Role r = child->role();
142 if ((r == QAccessible::MenuItem || r == QAccessible::Separator) && menuBar()) {
143 return menuBar()->actions().indexOf(qobject_cast<QAction*>(child->object()));
144 }
145 return -1;
146}
147
148#endif // QT_CONFIG(menubar)
149
150/*!
151 \class QAccessibleMenuItem
152 \inmodule QtWidgets
153 \internal
154*/
155QAccessibleMenuItem::QAccessibleMenuItem(QWidget *owner, QAction *action)
156: m_action(action), m_owner(owner)
157{
158}
159
160QAccessibleMenuItem::~QAccessibleMenuItem()
161{}
162
163QAccessibleInterface *QAccessibleMenuItem::childAt(int x, int y ) const
164{
165 for (int i = childCount() - 1; i >= 0; --i) {
166 QAccessibleInterface *childInterface = child(i);
167 if (childInterface->rect().contains(x,y)) {
168 return childInterface;
169 }
170 }
171 return nullptr;
172}
173
174int QAccessibleMenuItem::childCount() const
175{
176 return m_action->menu() ? 1 : 0;
177}
178
179int QAccessibleMenuItem::indexOfChild(const QAccessibleInterface * child) const
180{
181 if (child && child->role() == QAccessible::PopupMenu && child->object() == m_action->menu())
182 return 0;
183 return -1;
184}
185
186bool QAccessibleMenuItem::isValid() const
187{
188 return m_action && m_owner;
189}
190
191QAccessibleInterface *QAccessibleMenuItem::parent() const
192{
193 return QAccessible::queryAccessibleInterface(owner());
194}
195
196QAccessibleInterface *QAccessibleMenuItem::child(int index) const
197{
198 if (index == 0 && action()->menu())
199 return QAccessible::queryAccessibleInterface(action()->menu());
200 return nullptr;
201}
202
203void *QAccessibleMenuItem::interface_cast(QAccessible::InterfaceType t)
204{
205 if (t == QAccessible::ActionInterface)
206 return static_cast<QAccessibleActionInterface*>(this);
207 // A separator is not one of the items of the menu.
208 if (t == QAccessible::AttributesInterface && m_action && !m_action->isSeparator())
209 return static_cast<QAccessibleAttributesInterface *>(this);
210 return nullptr;
211}
212
213QList<QAccessible::Attribute> QAccessibleMenuItem::attributeKeys() const
214{
215 return { QAccessible::Attribute::PositionInSet, QAccessible::Attribute::SizeOfSet };
216}
217
218QVariant QAccessibleMenuItem::attributeValue(QAccessible::Attribute key) const
219{
220 if (key != QAccessible::Attribute::PositionInSet && key != QAccessible::Attribute::SizeOfSet)
221 return QVariant();
222
223 // The set is what the user sees: the visible items of the menu, without
224 // its separators.
225 int size = 0;
226 const auto actions = owner()->actions();
227 for (QAction *action : actions) {
228 if (action->isSeparator() || !action->isVisible())
229 continue;
230 ++size;
231 if (key == QAccessible::Attribute::PositionInSet && action == m_action)
232 return size;
233 }
234 return (key == QAccessible::Attribute::SizeOfSet) ? QVariant(size) : QVariant();
235}
236
237QObject *QAccessibleMenuItem::object() const
238{
239 return m_action;
240}
241
242/*! \reimp */
243QWindow *QAccessibleMenuItem::window() const
244{
245 return m_owner.isNull()
246 ? nullptr
247 : qt_widget_private(m_owner.data())->windowHandle(QWidgetPrivate::WindowHandleMode::Closest);
248}
249
250QRect QAccessibleMenuItem::rect() const
251{
252 QRect rect;
253 QWidget *own = owner();
254#if QT_CONFIG(menubar)
255 if (QMenuBar *menuBar = qobject_cast<QMenuBar*>(own)) {
256 rect = menuBar->actionGeometry(m_action);
257 QPoint globalPos = menuBar->mapToGlobal(QPoint(0,0));
258 rect = rect.translated(globalPos);
259 } else
260#endif // QT_CONFIG(menubar)
261 if (QMenu *menu = qobject_cast<QMenu*>(own)) {
262 rect = menu->actionGeometry(m_action);
263 QPoint globalPos = menu->mapToGlobal(QPoint(0,0));
264 rect = rect.translated(globalPos);
265 }
266 return rect;
267}
268
269QAccessible::Role QAccessibleMenuItem::role() const
270{
271 return m_action->isSeparator() ? QAccessible::Separator : QAccessible::MenuItem;
272}
273
274void QAccessibleMenuItem::setText(QAccessible::Text /*t*/, const QString & /*text */)
275{
276}
277
278QAccessible::State QAccessibleMenuItem::state() const
279{
280 QAccessible::State s;
281 QWidget *own = owner();
282
283 if (own && (own->testAttribute(Qt::WA_WState_Visible) == false || m_action->isVisible() == false)) {
284 s.invisible = true;
285 }
286
287 if (QMenu *menu = qobject_cast<QMenu*>(own)) {
288 if (menu->activeAction() == m_action)
289 s.focused = true;
290#if QT_CONFIG(menubar)
291 } else if (QMenuBar *menuBar = qobject_cast<QMenuBar*>(own)) {
292 if (menuBar->activeAction() == m_action)
293 s.focused = true;
294#endif
295 }
296 if (own && own->style()->styleHint(QStyle::SH_Menu_MouseTracking, nullptr, own))
297 s.hotTracked = true;
298 if (m_action->isSeparator() || !m_action->isEnabled())
299 s.disabled = true;
300 if (m_action->isChecked())
301 s.checked = true;
302 if (m_action->isCheckable())
303 s.checkable = true;
304
305 return s;
306}
307
308QString QAccessibleMenuItem::text(QAccessible::Text t) const
309{
310 QString str;
311 switch (t) {
312 case QAccessible::Name:
313 str = qt_accStripAmp(m_action->text());
314 break;
315 case QAccessible::Accelerator: {
316#ifndef QT_NO_SHORTCUT
317 QKeySequence key = m_action->shortcut();
318 if (!key.isEmpty()) {
319 str = key.toString();
320 } else
321#endif
322 {
323 str = qt_accHotKey(m_action->text());
324 }
325 break;
326 }
327 default:
328 break;
329 }
330 return str;
331}
332
333QStringList QAccessibleMenuItem::actionNames() const
334{
335 QStringList actions;
336 if (!m_action || m_action->isSeparator())
337 return actions;
338
339 if (m_action->menu()) {
340 actions << showMenuAction();
341 } else {
342 actions << pressAction();
343 }
344 return actions;
345}
346
347void QAccessibleMenuItem::doAction(const QString &actionName)
348{
349 if (!m_action->isEnabled())
350 return;
351
352 if (actionName == pressAction()) {
353 m_action->trigger();
354 } else if (actionName == showMenuAction()) {
355#if QT_CONFIG(menubar)
356 if (QMenuBar *bar = qobject_cast<QMenuBar*>(owner())) {
357 if (m_action->menu() && m_action->menu()->isVisible()) {
358 m_action->menu()->hide();
359 } else {
360 bar->setActiveAction(m_action);
361 }
362 } else
363#endif
364 if (QMenu *menu = qobject_cast<QMenu*>(owner())){
365 if (m_action->menu() && m_action->menu()->isVisible()) {
366 m_action->menu()->hide();
367 } else {
368 menu->setActiveAction(m_action);
369 }
370 }
371 }
372}
373
374QStringList QAccessibleMenuItem::keyBindingsForAction(const QString &) const
375{
376 return QStringList();
377}
378
379
380QAction *QAccessibleMenuItem::action() const
381{
382 return m_action;
383}
384
385QWidget *QAccessibleMenuItem::owner() const
386{
387 return m_owner;
388}
389
390#endif // QT_CONFIG(menu)
391
392QT_END_NAMESPACE
393
394#endif // QT_CONFIG(accessibility)