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 return nullptr;
208}
209
210QObject *QAccessibleMenuItem::object() const
211{
212 return m_action;
213}
214
215/*! \reimp */
216QWindow *QAccessibleMenuItem::window() const
217{
218 return m_owner.isNull()
219 ? nullptr
220 : qt_widget_private(m_owner.data())->windowHandle(QWidgetPrivate::WindowHandleMode::Closest);
221}
222
223QRect QAccessibleMenuItem::rect() const
224{
225 QRect rect;
226 QWidget *own = owner();
227#if QT_CONFIG(menubar)
228 if (QMenuBar *menuBar = qobject_cast<QMenuBar*>(own)) {
229 rect = menuBar->actionGeometry(m_action);
230 QPoint globalPos = menuBar->mapToGlobal(QPoint(0,0));
231 rect = rect.translated(globalPos);
232 } else
233#endif // QT_CONFIG(menubar)
234 if (QMenu *menu = qobject_cast<QMenu*>(own)) {
235 rect = menu->actionGeometry(m_action);
236 QPoint globalPos = menu->mapToGlobal(QPoint(0,0));
237 rect = rect.translated(globalPos);
238 }
239 return rect;
240}
241
242QAccessible::Role QAccessibleMenuItem::role() const
243{
244 return m_action->isSeparator() ? QAccessible::Separator : QAccessible::MenuItem;
245}
246
247void QAccessibleMenuItem::setText(QAccessible::Text /*t*/, const QString & /*text */)
248{
249}
250
251QAccessible::State QAccessibleMenuItem::state() const
252{
253 QAccessible::State s;
254 QWidget *own = owner();
255
256 if (own && (own->testAttribute(Qt::WA_WState_Visible) == false || m_action->isVisible() == false)) {
257 s.invisible = true;
258 }
259
260 if (QMenu *menu = qobject_cast<QMenu*>(own)) {
261 if (menu->activeAction() == m_action)
262 s.focused = true;
263#if QT_CONFIG(menubar)
264 } else if (QMenuBar *menuBar = qobject_cast<QMenuBar*>(own)) {
265 if (menuBar->activeAction() == m_action)
266 s.focused = true;
267#endif
268 }
269 if (own && own->style()->styleHint(QStyle::SH_Menu_MouseTracking, nullptr, own))
270 s.hotTracked = true;
271 if (m_action->isSeparator() || !m_action->isEnabled())
272 s.disabled = true;
273 if (m_action->isChecked())
274 s.checked = true;
275 if (m_action->isCheckable())
276 s.checkable = true;
277
278 return s;
279}
280
281QString QAccessibleMenuItem::text(QAccessible::Text t) const
282{
283 QString str;
284 switch (t) {
285 case QAccessible::Name:
286 str = qt_accStripAmp(m_action->text());
287 break;
288 case QAccessible::Accelerator: {
289#ifndef QT_NO_SHORTCUT
290 QKeySequence key = m_action->shortcut();
291 if (!key.isEmpty()) {
292 str = key.toString();
293 } else
294#endif
295 {
296 str = qt_accHotKey(m_action->text());
297 }
298 break;
299 }
300 default:
301 break;
302 }
303 return str;
304}
305
306QStringList QAccessibleMenuItem::actionNames() const
307{
308 QStringList actions;
309 if (!m_action || m_action->isSeparator())
310 return actions;
311
312 if (m_action->menu()) {
313 actions << showMenuAction();
314 } else {
315 actions << pressAction();
316 }
317 return actions;
318}
319
320void QAccessibleMenuItem::doAction(const QString &actionName)
321{
322 if (!m_action->isEnabled())
323 return;
324
325 if (actionName == pressAction()) {
326 m_action->trigger();
327 } else if (actionName == showMenuAction()) {
328#if QT_CONFIG(menubar)
329 if (QMenuBar *bar = qobject_cast<QMenuBar*>(owner())) {
330 if (m_action->menu() && m_action->menu()->isVisible()) {
331 m_action->menu()->hide();
332 } else {
333 bar->setActiveAction(m_action);
334 }
335 } else
336#endif
337 if (QMenu *menu = qobject_cast<QMenu*>(owner())){
338 if (m_action->menu() && m_action->menu()->isVisible()) {
339 m_action->menu()->hide();
340 } else {
341 menu->setActiveAction(m_action);
342 }
343 }
344 }
345}
346
347QStringList QAccessibleMenuItem::keyBindingsForAction(const QString &) const
348{
349 return QStringList();
350}
351
352
353QAction *QAccessibleMenuItem::action() const
354{
355 return m_action;
356}
357
358QWidget *QAccessibleMenuItem::owner() const
359{
360 return m_owner;
361}
362
363#endif // QT_CONFIG(menu)
364
365QT_END_NAMESPACE
366
367#endif // QT_CONFIG(accessibility)