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