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