blob: 1454c7c80b34d25144e5a4be69d7a297a13b8428 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qaccessiblemenu.h"
#include <qmenu.h>
#include <qmenubar.h>
#include <QtGui/QAction>
#include <qstyle.h>
#ifndef QT_NO_ACCESSIBILITY
QT_BEGIN_NAMESPACE
#ifndef QT_NO_MENU
QString Q_GUI_EXPORT qt_accStripAmp(const QString &text);
QString Q_GUI_EXPORT qt_accHotKey(const QString &text);
QAccessibleMenu::QAccessibleMenu(QWidget *w)
: QAccessibleWidgetEx(w)
{
Q_ASSERT(menu());
}
QMenu *QAccessibleMenu::menu() const
{
return qobject_cast<QMenu*>(object());
}
int QAccessibleMenu::childCount() const
{
return menu()->actions().count();
}
QRect QAccessibleMenu::rect(int child) const
{
if (!child || child > childCount())
return QAccessibleWidgetEx::rect(child);
QRect r = menu()->actionGeometry(menu()->actions()[child - 1]);
QPoint tlp = menu()->mapToGlobal(QPoint(0,0));
return QRect(tlp.x() + r.x(), tlp.y() + r.y(), r.width(), r.height());
}
int QAccessibleMenu::childAt(int x, int y) const
{
QAction *act = menu()->actionAt(menu()->mapFromGlobal(QPoint(x,y)));
if(act && act->isSeparator())
act = 0;
return menu()->actions().indexOf(act) + 1;
}
QString QAccessibleMenu::text(Text t, int child) const
{
QString tx = QAccessibleWidgetEx::text(t, child);
if (tx.size())
return tx;
switch (t) {
case Name:
if (!child)
return menu()->windowTitle();
return qt_accStripAmp(menu()->actions().at(child-1)->text());
case Help:
return child ? menu()->actions().at(child-1)->whatsThis() : tx;
#ifndef QT_NO_SHORTCUT
case Accelerator:
return child ? static_cast<QString>(menu()->actions().at(child-1)->shortcut()) : tx;
#endif
default:
break;
}
return tx;
}
QAccessible::Role QAccessibleMenu::role(int child) const
{
if (!child)
return PopupMenu;
QAction *action = menu()->actions()[child-1];
if (action && action->isSeparator())
return Separator;
return MenuItem;
}
QAccessible::State QAccessibleMenu::state(int child) const
{
State s = QAccessibleWidgetEx::state(child);
if (!child)
return s;
QAction *action = menu()->actions()[child-1];
if (!action)
return s;
if (menu()->style()->styleHint(QStyle::SH_Menu_MouseTracking))
s |= HotTracked;
if (action->isSeparator() || !action->isEnabled())
s |= Unavailable;
if (action->isChecked())
s |= Checked;
if (menu()->activeAction() == action)
s |= Focused;
return s;
}
QString QAccessibleMenu::actionText(int action, QAccessible::Text text, int child) const
{
if (action == QAccessible::DefaultAction && child && text == QAccessible::Name) {
QAction *a = menu()->actions().value(child-1, 0);
if (!a || a->isSeparator())
return QString();
if (a->menu()) {
if (a->menu()->isVisible())
return QMenu::tr("Close");
return QMenu::tr("Open");
}
return QMenu::tr("Execute");
}
return QAccessibleWidgetEx::actionText(action, text, child);
}
bool QAccessibleMenu::doAction(int act, int child, const QVariantList &)
{
if (!child || act != QAccessible::DefaultAction)
return false;
QAction *action = menu()->actions().value(child-1, 0);
if (!action || !action->isEnabled())
return false;
if (action->menu() && action->menu()->isVisible())
action->menu()->hide();
else
menu()->setActiveAction(action);
return true;
}
int QAccessibleMenu::navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const
{
int ret = -1;
if (entry < 0) {
*target = 0;
return ret;
}
if (relation == Self || entry == 0) {
*target = new QAccessibleMenu(menu());
return 0;
}
switch (relation) {
case Child:
if (entry <= childCount()) {
*target = new QAccessibleMenuItem(menu(), menu()->actions().at( entry - 1 ));
ret = 0;
}
break;
case Ancestor: {
QAccessibleInterface *iface;
QWidget *parent = menu()->parentWidget();
if (qobject_cast<QMenu*>(parent) || qobject_cast<QMenuBar*>(parent)) {
iface = new QAccessibleMenuItem(parent, menu()->menuAction());
if (entry == 1) {
*target = iface;
ret = 0;
} else {
ret = iface->navigate(Ancestor, entry - 1, target);
delete iface;
}
} else {
return QAccessibleWidgetEx::navigate(relation, entry, target);
}
break;}
default:
return QAccessibleWidgetEx::navigate(relation, entry, target);
}
if (ret == -1)
*target = 0;
return ret;
}
int QAccessibleMenu::indexOfChild( const QAccessibleInterface *child ) const
{
int index = -1;
Role r = child->role(0);
if ((r == MenuItem || r == Separator) && menu()) {
index = menu()->actions().indexOf(qobject_cast<QAction*>(child->object()));
if (index != -1)
++index;
}
return index;
}
#ifndef QT_NO_MENUBAR
QAccessibleMenuBar::QAccessibleMenuBar(QWidget *w)
: QAccessibleWidgetEx(w)
{
Q_ASSERT(menuBar());
}
QMenuBar *QAccessibleMenuBar::menuBar() const
{
return qobject_cast<QMenuBar*>(object());
}
int QAccessibleMenuBar::childCount() const
{
return menuBar()->actions().count();
}
QRect QAccessibleMenuBar::rect(int child) const
{
if (!child)
return QAccessibleWidgetEx::rect(child);
QRect r = menuBar()->actionGeometry(menuBar()->actions()[child - 1]);
QPoint tlp = menuBar()->mapToGlobal(QPoint(0,0));
return QRect(tlp.x() + r.x(), tlp.y() + r.y(), r.width(), r.height());
}
int QAccessibleMenuBar::childAt(int x, int y) const
{
for (int i = childCount(); i >= 0; --i) {
if (rect(i).contains(x,y))
return i;
}
return -1;
}
int QAccessibleMenuBar::navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const
{
int ret = -1;
if (entry < 0) {
*target = 0;
return ret;
}
if (relation == Self || entry == 0) {
*target = new QAccessibleMenuBar(menuBar());
return 0;
}
switch (relation) {
case Child:
if (entry <= childCount()) {
*target = new QAccessibleMenuItem(menuBar(), menuBar()->actions().at( entry - 1 ));
ret = 0;
}
break;
default:
return QAccessibleWidgetEx::navigate(relation, entry, target);
}
if (ret == -1)
*target = 0;
return ret;
}
int QAccessibleMenuBar::indexOfChild( const QAccessibleInterface *child ) const
{
int index = -1;
Role r = child->role(0);
if ((r == MenuItem || r == Separator) && menuBar()) {
index = menuBar()->actions().indexOf(qobject_cast<QAction*>(child->object()));
if (index != -1)
++index;
}
return index;
}
QString QAccessibleMenuBar::text(Text t, int child) const
{
QString str;
if (child) {
if (QAction *action = menuBar()->actions().value(child - 1, 0)) {
switch (t) {
case Name:
return qt_accStripAmp(action->text());
case Accelerator:
str = qt_accHotKey(action->text());
break;
default:
break;
}
}
}
if (str.isEmpty())
str = QAccessibleWidgetEx::text(t, child);
return str;
}
QAccessible::Role QAccessibleMenuBar::role(int child) const
{
if (!child)
return MenuBar;
QAction *action = menuBar()->actions()[child-1];
if (action && action->isSeparator())
return Separator;
return MenuItem;
}
QAccessible::State QAccessibleMenuBar::state(int child) const
{
State s = QAccessibleWidgetEx::state(child);
if (!child)
return s;
QAction *action = menuBar()->actions().value(child-1, 0);
if (!action)
return s;
if (menuBar()->style()->styleHint(QStyle::SH_Menu_MouseTracking))
s |= HotTracked;
if (action->isSeparator() || !action->isEnabled())
s |= Unavailable;
if (menuBar()->activeAction() == action)
s |= Focused;
return s;
}
QString QAccessibleMenuBar::actionText(int action, QAccessible::Text text, int child) const
{
if (action == QAccessible::DefaultAction && child && text == QAccessible::Name) {
QAction *a = menuBar()->actions().value(child-1, 0);
if (!a || a->isSeparator())
return QString();
if (a->menu()) {
if (a->menu()->isVisible())
return QMenu::tr("Close");
return QMenu::tr("Open");
}
return QMenu::tr("Execute");
}
return QAccessibleWidgetEx::actionText(action, text, child);
}
bool QAccessibleMenuBar::doAction(int act, int child, const QVariantList &)
{
if (act != !child)
return false;
QAction *action = menuBar()->actions().value(child-1, 0);
if (!action || !action->isEnabled())
return false;
if (action->menu() && action->menu()->isVisible())
action->menu()->hide();
else
menuBar()->setActiveAction(action);
return true;
}
#endif // QT_NO_MENUBAR
QAccessibleMenuItem::QAccessibleMenuItem(QWidget *owner, QAction *action) : m_action(action), m_owner(owner)
{
}
QAccessibleMenuItem::~QAccessibleMenuItem()
{}
int QAccessibleMenuItem::childAt(int x, int y ) const
{
for (int i = childCount(); i >= 0; --i) {
if (rect(i).contains(x,y))
return i;
}
return -1;
}
int QAccessibleMenuItem::childCount() const
{
return m_action->menu() ? 1 : 0;
}
QString QAccessibleMenuItem::actionText(int action, Text text, int child ) const
{
if (text == Name && child == 0) {
switch (action) {
case Press:
case DefaultAction:
return QMenu::tr("Execute");
break;
default:
break;
}
}
return QString();
}
bool QAccessibleMenuItem::doAction(int action, int child, const QVariantList & /*params = QVariantList()*/ )
{
if ((action == Press || action == DefaultAction) && child == 0) {
m_action->trigger();
return true;
}
return false;
}
int QAccessibleMenuItem::indexOfChild( const QAccessibleInterface * child ) const
{
if (child->role(0) == PopupMenu && child->object() == m_action->menu())
return 1;
return -1;
}
bool QAccessibleMenuItem::isValid() const
{
return m_action ? true : false;
}
int QAccessibleMenuItem::navigate(RelationFlag relation, int entry, QAccessibleInterface ** target ) const
{
int ret = -1;
if (entry < 0) {
*target = 0;
return ret;
}
if (relation == Self || entry == 0) {
*target = new QAccessibleMenuItem(owner(), action());
return 0;
}
switch (relation) {
case Child:
if (entry <= childCount()) {
*target = new QAccessibleMenu(action()->menu());
ret = 0;
}
break;
case Ancestor:{
QWidget *parent = owner();
QAccessibleInterface *ancestor = parent ? QAccessible::queryAccessibleInterface(parent) : 0;
if (ancestor) {
if (entry == 1) {
*target = ancestor;
ret = 0;
} else {
ret = ancestor->navigate(Ancestor, entry - 1, target);
delete ancestor;
}
}
break;}
case Up:
case Down:{
QAccessibleInterface *parent = 0;
int ent = navigate(Ancestor, 1, &parent);
if (ent == 0) {
int index = parent->indexOfChild(this);
if (index != -1) {
index += (relation == Down ? +1 : -1);
ret = parent->navigate(Child, index, target);
}
}
delete parent;
break;}
case Sibling: {
QAccessibleInterface *parent = 0;
int ent = navigate(Ancestor, 1, &parent);
if (ent == 0) {
ret = parent->navigate(Child, entry, target);
}
delete parent;
break;}
default:
break;
}
if (ret == -1)
*target = 0;
return ret;
}
QObject *QAccessibleMenuItem::object() const
{
return m_action;
}
QRect QAccessibleMenuItem::rect (int child ) const
{
QRect rect;
if (child == 0) {
QWidget *own = owner();
#ifndef QT_NO_MENUBAR
if (QMenuBar *menuBar = qobject_cast<QMenuBar*>(own)) {
rect = menuBar->actionGeometry(m_action);
QPoint globalPos = menuBar->mapToGlobal(QPoint(0,0));
rect = rect.translated(globalPos);
} else
#endif // QT_NO_MENUBAR
if (QMenu *menu = qobject_cast<QMenu*>(own)) {
rect = menu->actionGeometry(m_action);
QPoint globalPos = menu->mapToGlobal(QPoint(0,0));
rect = rect.translated(globalPos);
}
} else if (child == 1) {
QMenu *menu = m_action->menu();
if (menu) {
rect = menu->rect();
QPoint globalPos = menu->mapToGlobal(QPoint(0,0));
rect = rect.translated(globalPos);
}
}
return rect;
}
QAccessible::Relation QAccessibleMenuItem::relationTo ( int child, const QAccessibleInterface * other, int otherChild ) const
{
if (other->object() == owner()) {
return Child;
}
Q_UNUSED(child)
Q_UNUSED(other)
Q_UNUSED(otherChild)
// ###
return Unrelated;
}
QAccessible::Role QAccessibleMenuItem::role(int /*child*/ ) const
{
return m_action->isSeparator() ? Separator :MenuItem;
}
void QAccessibleMenuItem::setText ( Text /*t*/, int /*child*/, const QString & /*text */)
{
}
QAccessible::State QAccessibleMenuItem::state(int child ) const
{
QAccessible::State s = Unavailable;
if (child == 0) {
s = Normal;
QWidget *own = owner();
if (own->testAttribute(Qt::WA_WState_Visible) == false || m_action->isVisible() == false) {
s |= Invisible;
}
if (QMenu *menu = qobject_cast<QMenu*>(own)) {
if (menu->activeAction() == m_action)
s |= Focused;
#ifndef QT_NO_MENUBAR
} else if (QMenuBar *menuBar = qobject_cast<QMenuBar*>(own)) {
if (menuBar->activeAction() == m_action)
s |= Focused;
#endif
}
if (own->style()->styleHint(QStyle::SH_Menu_MouseTracking))
s |= HotTracked;
if (m_action->isSeparator() || !m_action->isEnabled())
s |= Unavailable;
if (m_action->isChecked())
s |= Checked;
} else if (child == 1) {
QMenu *menu = m_action->menu();
if (menu) {
QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(menu);
s = iface->state(0);
delete iface;
}
}
return s;
}
QString QAccessibleMenuItem::text ( Text t, int child ) const
{
QString str;
switch (t) {
case Name:
if (child == 0) {
str = m_action->text();
} else if (child == 1) {
QMenu *m = m_action->menu();
if (m)
str = m->title();
}
str = qt_accStripAmp(str);
break;
case Accelerator:
if (child == 0) {
#ifndef QT_NO_SHORTCUT
QKeySequence key = m_action->shortcut();
if (!key.isEmpty()) {
str = key.toString();
} else
#endif
{
str = qt_accHotKey(m_action->text());
}
}
break;
default:
break;
}
return str;
}
int QAccessibleMenuItem::userActionCount ( int /*child*/ ) const
{
return 0;
}
QAction *QAccessibleMenuItem::action() const
{
return m_action;
}
QWidget *QAccessibleMenuItem::owner() const
{
return m_owner;
}
#endif // QT_NO_MENU
QT_END_NAMESPACE
#endif // QT_NO_ACCESSIBILITY