src/plugins/accessible/widgets/qaccessiblemenu.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/plugins/accessible/widgets/qaccessiblemenu.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,678 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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
+