source: trunk/src/plugins/accessible/widgets/qaccessiblemenu.cpp@ 561

Last change on this file since 561 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 17.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the plugins of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qaccessiblemenu.h"
43
44#include <qmenu.h>
45#include <qmenubar.h>
46#include <QtGui/QAction>
47#include <qstyle.h>
48
49#ifndef QT_NO_ACCESSIBILITY
50
51QT_BEGIN_NAMESPACE
52
53#ifndef QT_NO_MENU
54
55QString Q_GUI_EXPORT qt_accStripAmp(const QString &text);
56QString Q_GUI_EXPORT qt_accHotKey(const QString &text);
57
58QAccessibleMenu::QAccessibleMenu(QWidget *w)
59: QAccessibleWidgetEx(w)
60{
61 Q_ASSERT(menu());
62}
63
64QMenu *QAccessibleMenu::menu() const
65{
66 return qobject_cast<QMenu*>(object());
67}
68
69int QAccessibleMenu::childCount() const
70{
71 return menu()->actions().count();
72}
73
74QRect QAccessibleMenu::rect(int child) const
75{
76 if (!child || child > childCount())
77 return QAccessibleWidgetEx::rect(child);
78
79 QRect r = menu()->actionGeometry(menu()->actions()[child - 1]);
80 QPoint tlp = menu()->mapToGlobal(QPoint(0,0));
81
82 return QRect(tlp.x() + r.x(), tlp.y() + r.y(), r.width(), r.height());
83}
84
85int QAccessibleMenu::childAt(int x, int y) const
86{
87 QAction *act = menu()->actionAt(menu()->mapFromGlobal(QPoint(x,y)));
88 if(act && act->isSeparator())
89 act = 0;
90 return menu()->actions().indexOf(act) + 1;
91}
92
93QString QAccessibleMenu::text(Text t, int child) const
94{
95 QString tx = QAccessibleWidgetEx::text(t, child);
96 if (tx.size())
97 return tx;
98
99 switch (t) {
100 case Name:
101 if (!child)
102 return menu()->windowTitle();
103 return qt_accStripAmp(menu()->actions().at(child-1)->text());
104 case Help:
105 return child ? menu()->actions().at(child-1)->whatsThis() : tx;
106#ifndef QT_NO_SHORTCUT
107 case Accelerator:
108 return child ? static_cast<QString>(menu()->actions().at(child-1)->shortcut()) : tx;
109#endif
110 default:
111 break;
112 }
113 return tx;
114}
115
116QAccessible::Role QAccessibleMenu::role(int child) const
117{
118 if (!child)
119 return PopupMenu;
120
121 QAction *action = menu()->actions()[child-1];
122 if (action && action->isSeparator())
123 return Separator;
124 return MenuItem;
125}
126
127QAccessible::State QAccessibleMenu::state(int child) const
128{
129 State s = QAccessibleWidgetEx::state(child);
130 if (!child)
131 return s;
132
133 QAction *action = menu()->actions()[child-1];
134 if (!action)
135 return s;
136
137 if (menu()->style()->styleHint(QStyle::SH_Menu_MouseTracking))
138 s |= HotTracked;
139 if (action->isSeparator() || !action->isEnabled())
140 s |= Unavailable;
141 if (action->isChecked())
142 s |= Checked;
143 if (menu()->activeAction() == action)
144 s |= Focused;
145
146 return s;
147}
148
149QString QAccessibleMenu::actionText(int action, QAccessible::Text text, int child) const
150{
151 if (action == QAccessible::DefaultAction && child && text == QAccessible::Name) {
152 QAction *a = menu()->actions().value(child-1, 0);
153 if (!a || a->isSeparator())
154 return QString();
155 if (a->menu()) {
156 if (a->menu()->isVisible())
157 return QMenu::tr("Close");
158 return QMenu::tr("Open");
159 }
160 return QMenu::tr("Execute");
161 }
162
163 return QAccessibleWidgetEx::actionText(action, text, child);
164}
165
166bool QAccessibleMenu::doAction(int act, int child, const QVariantList &)
167{
168 if (!child || act != QAccessible::DefaultAction)
169 return false;
170
171 QAction *action = menu()->actions().value(child-1, 0);
172 if (!action || !action->isEnabled())
173 return false;
174
175 if (action->menu() && action->menu()->isVisible())
176 action->menu()->hide();
177 else
178 menu()->setActiveAction(action);
179 return true;
180}
181
182int QAccessibleMenu::navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const
183{
184 int ret = -1;
185 if (entry < 0) {
186 *target = 0;
187 return ret;
188 }
189
190 if (relation == Self || entry == 0) {
191 *target = new QAccessibleMenu(menu());
192 return 0;
193 }
194
195 switch (relation) {
196 case Child:
197 if (entry <= childCount()) {
198 *target = new QAccessibleMenuItem(menu(), menu()->actions().at( entry - 1 ));
199 ret = 0;
200 }
201 break;
202 case Ancestor: {
203 QAccessibleInterface *iface;
204 QWidget *parent = menu()->parentWidget();
205 if (qobject_cast<QMenu*>(parent) || qobject_cast<QMenuBar*>(parent)) {
206 iface = new QAccessibleMenuItem(parent, menu()->menuAction());
207 if (entry == 1) {
208 *target = iface;
209 ret = 0;
210 } else {
211 ret = iface->navigate(Ancestor, entry - 1, target);
212 delete iface;
213 }
214 } else {
215 return QAccessibleWidgetEx::navigate(relation, entry, target);
216 }
217 break;}
218 default:
219 return QAccessibleWidgetEx::navigate(relation, entry, target);
220 }
221
222
223 if (ret == -1)
224 *target = 0;
225
226 return ret;
227
228}
229
230int QAccessibleMenu::indexOfChild( const QAccessibleInterface *child ) const
231{
232 int index = -1;
233 Role r = child->role(0);
234 if ((r == MenuItem || r == Separator) && menu()) {
235 index = menu()->actions().indexOf(qobject_cast<QAction*>(child->object()));
236 if (index != -1)
237 ++index;
238 }
239 return index;
240}
241
242#ifndef QT_NO_MENUBAR
243QAccessibleMenuBar::QAccessibleMenuBar(QWidget *w)
244: QAccessibleWidgetEx(w)
245{
246 Q_ASSERT(menuBar());
247}
248
249QMenuBar *QAccessibleMenuBar::menuBar() const
250{
251 return qobject_cast<QMenuBar*>(object());
252}
253
254int QAccessibleMenuBar::childCount() const
255{
256 return menuBar()->actions().count();
257}
258
259QRect QAccessibleMenuBar::rect(int child) const
260{
261 if (!child)
262 return QAccessibleWidgetEx::rect(child);
263
264 QRect r = menuBar()->actionGeometry(menuBar()->actions()[child - 1]);
265 QPoint tlp = menuBar()->mapToGlobal(QPoint(0,0));
266 return QRect(tlp.x() + r.x(), tlp.y() + r.y(), r.width(), r.height());
267}
268
269int QAccessibleMenuBar::childAt(int x, int y) const
270{
271 for (int i = childCount(); i >= 0; --i) {
272 if (rect(i).contains(x,y))
273 return i;
274 }
275 return -1;
276}
277
278int QAccessibleMenuBar::navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const
279{
280 int ret = -1;
281 if (entry < 0) {
282 *target = 0;
283 return ret;
284 }
285
286 if (relation == Self || entry == 0) {
287 *target = new QAccessibleMenuBar(menuBar());
288 return 0;
289 }
290
291 switch (relation) {
292 case Child:
293 if (entry <= childCount()) {
294 *target = new QAccessibleMenuItem(menuBar(), menuBar()->actions().at( entry - 1 ));
295 ret = 0;
296 }
297 break;
298 default:
299 return QAccessibleWidgetEx::navigate(relation, entry, target);
300 }
301
302
303 if (ret == -1)
304 *target = 0;
305
306 return ret;
307}
308
309int QAccessibleMenuBar::indexOfChild( const QAccessibleInterface *child ) const
310{
311 int index = -1;
312 Role r = child->role(0);
313 if ((r == MenuItem || r == Separator) && menuBar()) {
314 index = menuBar()->actions().indexOf(qobject_cast<QAction*>(child->object()));
315 if (index != -1)
316 ++index;
317 }
318 return index;
319}
320
321QString QAccessibleMenuBar::text(Text t, int child) const
322{
323 QString str;
324
325 if (child) {
326 if (QAction *action = menuBar()->actions().value(child - 1, 0)) {
327 switch (t) {
328 case Name:
329 return qt_accStripAmp(action->text());
330 case Accelerator:
331 str = qt_accHotKey(action->text());
332 break;
333 default:
334 break;
335 }
336 }
337 }
338 if (str.isEmpty())
339 str = QAccessibleWidgetEx::text(t, child);
340 return str;
341}
342
343QAccessible::Role QAccessibleMenuBar::role(int child) const
344{
345 if (!child)
346 return MenuBar;
347
348 QAction *action = menuBar()->actions()[child-1];
349 if (action && action->isSeparator())
350 return Separator;
351 return MenuItem;
352}
353
354QAccessible::State QAccessibleMenuBar::state(int child) const
355{
356 State s = QAccessibleWidgetEx::state(child);
357 if (!child)
358 return s;
359
360 QAction *action = menuBar()->actions().value(child-1, 0);
361 if (!action)
362 return s;
363
364 if (menuBar()->style()->styleHint(QStyle::SH_Menu_MouseTracking))
365 s |= HotTracked;
366 if (action->isSeparator() || !action->isEnabled())
367 s |= Unavailable;
368 if (menuBar()->activeAction() == action)
369 s |= Focused;
370
371 return s;
372}
373
374QString QAccessibleMenuBar::actionText(int action, QAccessible::Text text, int child) const
375{
376 if (action == QAccessible::DefaultAction && child && text == QAccessible::Name) {
377 QAction *a = menuBar()->actions().value(child-1, 0);
378 if (!a || a->isSeparator())
379 return QString();
380 if (a->menu()) {
381 if (a->menu()->isVisible())
382 return QMenu::tr("Close");
383 return QMenu::tr("Open");
384 }
385 return QMenu::tr("Execute");
386 }
387
388 return QAccessibleWidgetEx::actionText(action, text, child);
389}
390
391bool QAccessibleMenuBar::doAction(int act, int child, const QVariantList &)
392{
393 if (act != !child)
394 return false;
395
396 QAction *action = menuBar()->actions().value(child-1, 0);
397 if (!action || !action->isEnabled())
398 return false;
399 if (action->menu() && action->menu()->isVisible())
400 action->menu()->hide();
401 else
402 menuBar()->setActiveAction(action);
403 return true;
404}
405
406#endif // QT_NO_MENUBAR
407
408QAccessibleMenuItem::QAccessibleMenuItem(QWidget *owner, QAction *action) : m_action(action), m_owner(owner)
409{
410}
411
412
413QAccessibleMenuItem::~QAccessibleMenuItem()
414{}
415
416int QAccessibleMenuItem::childAt(int x, int y ) const
417{
418 for (int i = childCount(); i >= 0; --i) {
419 if (rect(i).contains(x,y))
420 return i;
421 }
422 return -1;
423}
424
425int QAccessibleMenuItem::childCount() const
426{
427 return m_action->menu() ? 1 : 0;
428}
429
430QString QAccessibleMenuItem::actionText(int action, Text text, int child ) const
431{
432 if (text == Name && child == 0) {
433 switch (action) {
434 case Press:
435 case DefaultAction:
436 return QMenu::tr("Execute");
437 break;
438 default:
439 break;
440 }
441 }
442 return QString();
443}
444
445bool QAccessibleMenuItem::doAction(int action, int child, const QVariantList & /*params = QVariantList()*/ )
446{
447 if ((action == Press || action == DefaultAction) && child == 0) {
448 m_action->trigger();
449 return true;
450 }
451 return false;
452}
453
454int QAccessibleMenuItem::indexOfChild( const QAccessibleInterface * child ) const
455{
456 if (child->role(0) == PopupMenu && child->object() == m_action->menu())
457 return 1;
458
459 return -1;
460}
461
462bool QAccessibleMenuItem::isValid() const
463{
464 return m_action ? true : false;
465}
466
467int QAccessibleMenuItem::navigate(RelationFlag relation, int entry, QAccessibleInterface ** target ) const
468{
469 int ret = -1;
470 if (entry < 0) {
471 *target = 0;
472 return ret;
473 }
474
475 if (relation == Self || entry == 0) {
476 *target = new QAccessibleMenuItem(owner(), action());
477 return 0;
478 }
479
480 switch (relation) {
481 case Child:
482 if (entry <= childCount()) {
483 *target = new QAccessibleMenu(action()->menu());
484 ret = 0;
485 }
486 break;
487
488 case Ancestor:{
489 QWidget *parent = owner();
490 QAccessibleInterface *ancestor = parent ? QAccessible::queryAccessibleInterface(parent) : 0;
491 if (ancestor) {
492 if (entry == 1) {
493 *target = ancestor;
494 ret = 0;
495 } else {
496 ret = ancestor->navigate(Ancestor, entry - 1, target);
497 delete ancestor;
498 }
499 }
500 break;}
501 case Up:
502 case Down:{
503 QAccessibleInterface *parent = 0;
504 int ent = navigate(Ancestor, 1, &parent);
505 if (ent == 0) {
506 int index = parent->indexOfChild(this);
507 if (index != -1) {
508 index += (relation == Down ? +1 : -1);
509 ret = parent->navigate(Child, index, target);
510 }
511 }
512 delete parent;
513 break;}
514 case Sibling: {
515 QAccessibleInterface *parent = 0;
516 int ent = navigate(Ancestor, 1, &parent);
517 if (ent == 0) {
518 ret = parent->navigate(Child, entry, target);
519 }
520 delete parent;
521 break;}
522 default:
523 break;
524
525 }
526 if (ret == -1)
527 *target = 0;
528 return ret;
529}
530
531QObject *QAccessibleMenuItem::object() const
532{
533 return m_action;
534}
535
536QRect QAccessibleMenuItem::rect (int child ) const
537{
538 QRect rect;
539 if (child == 0) {
540 QWidget *own = owner();
541#ifndef QT_NO_MENUBAR
542 if (QMenuBar *menuBar = qobject_cast<QMenuBar*>(own)) {
543 rect = menuBar->actionGeometry(m_action);
544 QPoint globalPos = menuBar->mapToGlobal(QPoint(0,0));
545 rect = rect.translated(globalPos);
546 } else
547#endif // QT_NO_MENUBAR
548 if (QMenu *menu = qobject_cast<QMenu*>(own)) {
549 rect = menu->actionGeometry(m_action);
550 QPoint globalPos = menu->mapToGlobal(QPoint(0,0));
551 rect = rect.translated(globalPos);
552 }
553 } else if (child == 1) {
554 QMenu *menu = m_action->menu();
555 if (menu) {
556 rect = menu->rect();
557 QPoint globalPos = menu->mapToGlobal(QPoint(0,0));
558 rect = rect.translated(globalPos);
559 }
560 }
561 return rect;
562}
563
564QAccessible::Relation QAccessibleMenuItem::relationTo ( int child, const QAccessibleInterface * other, int otherChild ) const
565{
566 if (other->object() == owner()) {
567 return Child;
568 }
569 Q_UNUSED(child)
570 Q_UNUSED(other)
571 Q_UNUSED(otherChild)
572 // ###
573 return Unrelated;
574}
575
576QAccessible::Role QAccessibleMenuItem::role(int /*child*/ ) const
577{
578 return m_action->isSeparator() ? Separator :MenuItem;
579}
580
581void QAccessibleMenuItem::setText ( Text /*t*/, int /*child*/, const QString & /*text */)
582{
583
584}
585
586QAccessible::State QAccessibleMenuItem::state(int child ) const
587{
588 QAccessible::State s = Unavailable;
589
590 if (child == 0) {
591 s = Normal;
592 QWidget *own = owner();
593
594 if (own->testAttribute(Qt::WA_WState_Visible) == false || m_action->isVisible() == false) {
595 s |= Invisible;
596 }
597
598 if (QMenu *menu = qobject_cast<QMenu*>(own)) {
599 if (menu->activeAction() == m_action)
600 s |= Focused;
601#ifndef QT_NO_MENUBAR
602 } else if (QMenuBar *menuBar = qobject_cast<QMenuBar*>(own)) {
603 if (menuBar->activeAction() == m_action)
604 s |= Focused;
605#endif
606 }
607 if (own->style()->styleHint(QStyle::SH_Menu_MouseTracking))
608 s |= HotTracked;
609 if (m_action->isSeparator() || !m_action->isEnabled())
610 s |= Unavailable;
611 if (m_action->isChecked())
612 s |= Checked;
613 } else if (child == 1) {
614 QMenu *menu = m_action->menu();
615 if (menu) {
616 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(menu);
617 s = iface->state(0);
618 delete iface;
619 }
620 }
621 return s;
622}
623
624QString QAccessibleMenuItem::text ( Text t, int child ) const
625{
626 QString str;
627 switch (t) {
628 case Name:
629 if (child == 0) {
630 str = m_action->text();
631 } else if (child == 1) {
632 QMenu *m = m_action->menu();
633 if (m)
634 str = m->title();
635 }
636 str = qt_accStripAmp(str);
637 break;
638 case Accelerator:
639 if (child == 0) {
640#ifndef QT_NO_SHORTCUT
641 QKeySequence key = m_action->shortcut();
642 if (!key.isEmpty()) {
643 str = key.toString();
644 } else
645#endif
646 {
647 str = qt_accHotKey(m_action->text());
648 }
649 }
650 break;
651 default:
652 break;
653 }
654 return str;
655}
656
657int QAccessibleMenuItem::userActionCount ( int /*child*/ ) const
658{
659 return 0;
660}
661
662
663QAction *QAccessibleMenuItem::action() const
664{
665 return m_action;
666}
667
668QWidget *QAccessibleMenuItem::owner() const
669{
670 return m_owner;
671}
672
673#endif // QT_NO_MENU
674
675QT_END_NAMESPACE
676
677#endif // QT_NO_ACCESSIBILITY
678
Note: See TracBrowser for help on using the repository browser.