1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the plugins of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qaccessiblemenu_p.h"
41
42#if QT_CONFIG(menu)
43#include <qmenu.h>
44#endif
45#if QT_CONFIG(menubar)
46#include <qmenubar.h>
47#endif
48#include <QtWidgets/QAction>
49#include <qstyle.h>
50#include <private/qwidget_p.h>
51
52#ifndef QT_NO_ACCESSIBILITY
53
54QT_BEGIN_NAMESPACE
55
56#if QT_CONFIG(menu)
57
58QString qt_accStripAmp(const QString &text);
59QString qt_accHotKey(const QString &text);
60
61QAccessibleInterface *getOrCreateMenu(QWidget *menu, QAction *action)
62{
63 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(action);
64 if (!iface) {
65 iface = new QAccessibleMenuItem(menu, action);
66 QAccessible::registerAccessibleInterface(iface);
67 }
68 return iface;
69}
70
71QAccessibleMenu::QAccessibleMenu(QWidget *w)
72: QAccessibleWidget(w)
73{
74 Q_ASSERT(menu());
75}
76
77QMenu *QAccessibleMenu::menu() const
78{
79 return qobject_cast<QMenu*>(object: object());
80}
81
82int QAccessibleMenu::childCount() const
83{
84 return menu()->actions().count();
85}
86
87QAccessibleInterface *QAccessibleMenu::childAt(int x, int y) const
88{
89 QAction *act = menu()->actionAt(menu()->mapFromGlobal(QPoint(x,y)));
90 if(act && act->isSeparator())
91 act = nullptr;
92 return act ? getOrCreateMenu(menu: menu(), action: act) : nullptr;
93}
94
95QString QAccessibleMenu::text(QAccessible::Text t) const
96{
97 QString tx = QAccessibleWidget::text(t);
98 if (!tx.isEmpty())
99 return tx;
100
101 if (t == QAccessible::Name)
102 return menu()->windowTitle();
103 return tx;
104}
105
106QAccessible::Role QAccessibleMenu::role() const
107{
108 return QAccessible::PopupMenu;
109}
110
111QAccessibleInterface *QAccessibleMenu::child(int index) const
112{
113 if (index < childCount())
114 return getOrCreateMenu(menu: menu(), action: menu()->actions().at(i: index));
115 return nullptr;
116}
117
118QAccessibleInterface *QAccessibleMenu::parent() const
119{
120 if (QAction *menuAction = menu()->menuAction()) {
121 const QList<QWidget*> parentCandidates =
122 QList<QWidget*>() << menu()->parentWidget() << menuAction->associatedWidgets();
123 for (QWidget *w : parentCandidates) {
124 if (qobject_cast<QMenu*>(object: w)
125#if QT_CONFIG(menubar)
126 || qobject_cast<QMenuBar*>(object: w)
127#endif
128 ) {
129 if (w->actions().indexOf(t: menuAction) != -1)
130 return getOrCreateMenu(menu: w, action: menuAction);
131 }
132 }
133 }
134 return QAccessibleWidget::parent();
135}
136
137int QAccessibleMenu::indexOfChild( const QAccessibleInterface *child) const
138{
139 QAccessible::Role r = child->role();
140 if ((r == QAccessible::MenuItem || r == QAccessible::Separator) && menu()) {
141 return menu()->actions().indexOf(t: qobject_cast<QAction*>(object: child->object()));
142 }
143 return -1;
144}
145
146#if QT_CONFIG(menubar)
147QAccessibleMenuBar::QAccessibleMenuBar(QWidget *w)
148 : QAccessibleWidget(w, QAccessible::MenuBar)
149{
150 Q_ASSERT(menuBar());
151}
152
153QMenuBar *QAccessibleMenuBar::menuBar() const
154{
155 return qobject_cast<QMenuBar*>(object: object());
156}
157
158int QAccessibleMenuBar::childCount() const
159{
160 return menuBar()->actions().count();
161}
162
163QAccessibleInterface *QAccessibleMenuBar::child(int index) const
164{
165 if (index < childCount()) {
166 return getOrCreateMenu(menu: menuBar(), action: menuBar()->actions().at(i: index));
167 }
168 return nullptr;
169}
170
171int QAccessibleMenuBar::indexOfChild(const QAccessibleInterface *child) const
172{
173 QAccessible::Role r = child->role();
174 if ((r == QAccessible::MenuItem || r == QAccessible::Separator) && menuBar()) {
175 return menuBar()->actions().indexOf(t: qobject_cast<QAction*>(object: child->object()));
176 }
177 return -1;
178}
179
180#endif // QT_CONFIG(menubar)
181
182QAccessibleMenuItem::QAccessibleMenuItem(QWidget *owner, QAction *action)
183: m_action(action), m_owner(owner)
184{
185}
186
187QAccessibleMenuItem::~QAccessibleMenuItem()
188{}
189
190QAccessibleInterface *QAccessibleMenuItem::childAt(int x, int y ) const
191{
192 for (int i = childCount() - 1; i >= 0; --i) {
193 QAccessibleInterface *childInterface = child(index: i);
194 if (childInterface->rect().contains(ax: x,ay: y)) {
195 return childInterface;
196 }
197 }
198 return nullptr;
199}
200
201int QAccessibleMenuItem::childCount() const
202{
203 return m_action->menu() ? 1 : 0;
204}
205
206int QAccessibleMenuItem::indexOfChild(const QAccessibleInterface * child) const
207{
208 if (child && child->role() == QAccessible::PopupMenu && child->object() == m_action->menu())
209 return 0;
210 return -1;
211}
212
213bool QAccessibleMenuItem::isValid() const
214{
215 return m_action && m_owner;
216}
217
218QAccessibleInterface *QAccessibleMenuItem::parent() const
219{
220 return QAccessible::queryAccessibleInterface(owner());
221}
222
223QAccessibleInterface *QAccessibleMenuItem::child(int index) const
224{
225 if (index == 0 && action()->menu())
226 return QAccessible::queryAccessibleInterface(action()->menu());
227 return nullptr;
228}
229
230void *QAccessibleMenuItem::interface_cast(QAccessible::InterfaceType t)
231{
232 if (t == QAccessible::ActionInterface)
233 return static_cast<QAccessibleActionInterface*>(this);
234 return nullptr;
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(widget: m_owner.data())->windowHandle(mode: 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*>(object: own)) {
256 rect = menuBar->actionGeometry(m_action);
257 QPoint globalPos = menuBar->mapToGlobal(QPoint(0,0));
258 rect = rect.translated(p: globalPos);
259 } else
260#endif // QT_CONFIG(menubar)
261 if (QMenu *menu = qobject_cast<QMenu*>(object: own)) {
262 rect = menu->actionGeometry(m_action);
263 QPoint globalPos = menu->mapToGlobal(QPoint(0,0));
264 rect = rect.translated(p: 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(attribute: Qt::WA_WState_Visible) == false || m_action->isVisible() == false)) {
284 s.invisible = true;
285 }
286
287 if (QMenu *menu = qobject_cast<QMenu*>(object: own)) {
288 if (menu->activeAction() == m_action)
289 s.focused = true;
290#if QT_CONFIG(menubar)
291 } else if (QMenuBar *menuBar = qobject_cast<QMenuBar*>(object: own)) {
292 if (menuBar->activeAction() == m_action)
293 s.focused = true;
294#endif
295 }
296 if (own && own->style()->styleHint(stylehint: QStyle::SH_Menu_MouseTracking))
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(text: 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(text: 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*>(object: 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*>(object: 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_NO_ACCESSIBILITY
395
396

source code of qtbase/src/widgets/accessible/qaccessiblemenu.cpp