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