| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the plugins of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qaccessiblemenu_p.h" |
| |
| #if QT_CONFIG(menu) |
| #include <qmenu.h> |
| #endif |
| #if QT_CONFIG(menubar) |
| #include <qmenubar.h> |
| #endif |
| #include <QtWidgets/QAction> |
| #include <qstyle.h> |
| #include <private/qwidget_p.h> |
| |
| #ifndef QT_NO_ACCESSIBILITY |
| |
| QT_BEGIN_NAMESPACE |
| |
| #if QT_CONFIG(menu) |
| |
| QString qt_accStripAmp(const QString &text); |
| QString qt_accHotKey(const QString &text); |
| |
| QAccessibleInterface *getOrCreateMenu(QWidget *menu, QAction *action) |
| { |
| QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(action); |
| if (!iface) { |
| iface = new QAccessibleMenuItem(menu, action); |
| QAccessible::registerAccessibleInterface(iface); |
| } |
| return iface; |
| } |
| |
| QAccessibleMenu::QAccessibleMenu(QWidget *w) |
| : QAccessibleWidget(w) |
| { |
| Q_ASSERT(menu()); |
| } |
| |
| QMenu *QAccessibleMenu::menu() const |
| { |
| return qobject_cast<QMenu*>(object()); |
| } |
| |
| int QAccessibleMenu::childCount() const |
| { |
| return menu()->actions().count(); |
| } |
| |
| QAccessibleInterface *QAccessibleMenu::childAt(int x, int y) const |
| { |
| QAction *act = menu()->actionAt(menu()->mapFromGlobal(QPoint(x,y))); |
| if(act && act->isSeparator()) |
| act = nullptr; |
| return act ? getOrCreateMenu(menu(), act) : nullptr; |
| } |
| |
| QString QAccessibleMenu::text(QAccessible::Text t) const |
| { |
| QString tx = QAccessibleWidget::text(t); |
| if (!tx.isEmpty()) |
| return tx; |
| |
| if (t == QAccessible::Name) |
| return menu()->windowTitle(); |
| return tx; |
| } |
| |
| QAccessible::Role QAccessibleMenu::role() const |
| { |
| return QAccessible::PopupMenu; |
| } |
| |
| QAccessibleInterface *QAccessibleMenu::child(int index) const |
| { |
| if (index < childCount()) |
| return getOrCreateMenu(menu(), menu()->actions().at(index)); |
| return nullptr; |
| } |
| |
| QAccessibleInterface *QAccessibleMenu::parent() const |
| { |
| if (QAction *menuAction = menu()->menuAction()) { |
| const QList<QWidget*> parentCandidates = |
| QList<QWidget*>() << menu()->parentWidget() << menuAction->associatedWidgets(); |
| for (QWidget *w : parentCandidates) { |
| if (qobject_cast<QMenu*>(w) |
| #if QT_CONFIG(menubar) |
| || qobject_cast<QMenuBar*>(w) |
| #endif |
| ) { |
| if (w->actions().indexOf(menuAction) != -1) |
| return getOrCreateMenu(w, menuAction); |
| } |
| } |
| } |
| return QAccessibleWidget::parent(); |
| } |
| |
| int QAccessibleMenu::indexOfChild( const QAccessibleInterface *child) const |
| { |
| QAccessible::Role r = child->role(); |
| if ((r == QAccessible::MenuItem || r == QAccessible::Separator) && menu()) { |
| return menu()->actions().indexOf(qobject_cast<QAction*>(child->object())); |
| } |
| return -1; |
| } |
| |
| #if QT_CONFIG(menubar) |
| QAccessibleMenuBar::QAccessibleMenuBar(QWidget *w) |
| : QAccessibleWidget(w, QAccessible::MenuBar) |
| { |
| Q_ASSERT(menuBar()); |
| } |
| |
| QMenuBar *QAccessibleMenuBar::menuBar() const |
| { |
| return qobject_cast<QMenuBar*>(object()); |
| } |
| |
| int QAccessibleMenuBar::childCount() const |
| { |
| return menuBar()->actions().count(); |
| } |
| |
| QAccessibleInterface *QAccessibleMenuBar::child(int index) const |
| { |
| if (index < childCount()) { |
| return getOrCreateMenu(menuBar(), menuBar()->actions().at(index)); |
| } |
| return nullptr; |
| } |
| |
| int QAccessibleMenuBar::indexOfChild(const QAccessibleInterface *child) const |
| { |
| QAccessible::Role r = child->role(); |
| if ((r == QAccessible::MenuItem || r == QAccessible::Separator) && menuBar()) { |
| return menuBar()->actions().indexOf(qobject_cast<QAction*>(child->object())); |
| } |
| return -1; |
| } |
| |
| #endif // QT_CONFIG(menubar) |
| |
| QAccessibleMenuItem::QAccessibleMenuItem(QWidget *owner, QAction *action) |
| : m_action(action), m_owner(owner) |
| { |
| } |
| |
| QAccessibleMenuItem::~QAccessibleMenuItem() |
| {} |
| |
| QAccessibleInterface *QAccessibleMenuItem::childAt(int x, int y ) const |
| { |
| for (int i = childCount() - 1; i >= 0; --i) { |
| QAccessibleInterface *childInterface = child(i); |
| if (childInterface->rect().contains(x,y)) { |
| return childInterface; |
| } |
| } |
| return nullptr; |
| } |
| |
| int QAccessibleMenuItem::childCount() const |
| { |
| return m_action->menu() ? 1 : 0; |
| } |
| |
| int QAccessibleMenuItem::indexOfChild(const QAccessibleInterface * child) const |
| { |
| if (child && child->role() == QAccessible::PopupMenu && child->object() == m_action->menu()) |
| return 0; |
| return -1; |
| } |
| |
| bool QAccessibleMenuItem::isValid() const |
| { |
| return m_action && m_owner; |
| } |
| |
| QAccessibleInterface *QAccessibleMenuItem::parent() const |
| { |
| return QAccessible::queryAccessibleInterface(owner()); |
| } |
| |
| QAccessibleInterface *QAccessibleMenuItem::child(int index) const |
| { |
| if (index == 0 && action()->menu()) |
| return QAccessible::queryAccessibleInterface(action()->menu()); |
| return nullptr; |
| } |
| |
| void *QAccessibleMenuItem::interface_cast(QAccessible::InterfaceType t) |
| { |
| if (t == QAccessible::ActionInterface) |
| return static_cast<QAccessibleActionInterface*>(this); |
| return nullptr; |
| } |
| |
| QObject *QAccessibleMenuItem::object() const |
| { |
| return m_action; |
| } |
| |
| /*! \reimp */ |
| QWindow *QAccessibleMenuItem::window() const |
| { |
| return m_owner.isNull() |
| ? nullptr |
| : qt_widget_private(m_owner.data())->windowHandle(QWidgetPrivate::WindowHandleMode::Closest); |
| } |
| |
| QRect QAccessibleMenuItem::rect() const |
| { |
| QRect rect; |
| QWidget *own = owner(); |
| #if QT_CONFIG(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_CONFIG(menubar) |
| if (QMenu *menu = qobject_cast<QMenu*>(own)) { |
| rect = menu->actionGeometry(m_action); |
| QPoint globalPos = menu->mapToGlobal(QPoint(0,0)); |
| rect = rect.translated(globalPos); |
| } |
| return rect; |
| } |
| |
| QAccessible::Role QAccessibleMenuItem::role() const |
| { |
| return m_action->isSeparator() ? QAccessible::Separator : QAccessible::MenuItem; |
| } |
| |
| void QAccessibleMenuItem::setText(QAccessible::Text /*t*/, const QString & /*text */) |
| { |
| } |
| |
| QAccessible::State QAccessibleMenuItem::state() const |
| { |
| QAccessible::State s; |
| QWidget *own = owner(); |
| |
| if (own && (own->testAttribute(Qt::WA_WState_Visible) == false || m_action->isVisible() == false)) { |
| s.invisible = true; |
| } |
| |
| if (QMenu *menu = qobject_cast<QMenu*>(own)) { |
| if (menu->activeAction() == m_action) |
| s.focused = true; |
| #if QT_CONFIG(menubar) |
| } else if (QMenuBar *menuBar = qobject_cast<QMenuBar*>(own)) { |
| if (menuBar->activeAction() == m_action) |
| s.focused = true; |
| #endif |
| } |
| if (own && own->style()->styleHint(QStyle::SH_Menu_MouseTracking)) |
| s.hotTracked = true; |
| if (m_action->isSeparator() || !m_action->isEnabled()) |
| s.disabled = true; |
| if (m_action->isChecked()) |
| s.checked = true; |
| if (m_action->isCheckable()) |
| s.checkable = true; |
| |
| return s; |
| } |
| |
| QString QAccessibleMenuItem::text(QAccessible::Text t) const |
| { |
| QString str; |
| switch (t) { |
| case QAccessible::Name: |
| str = qt_accStripAmp(m_action->text()); |
| break; |
| case QAccessible::Accelerator: { |
| #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; |
| } |
| |
| QStringList QAccessibleMenuItem::actionNames() const |
| { |
| QStringList actions; |
| if (!m_action || m_action->isSeparator()) |
| return actions; |
| |
| if (m_action->menu()) { |
| actions << showMenuAction(); |
| } else { |
| actions << pressAction(); |
| } |
| return actions; |
| } |
| |
| void QAccessibleMenuItem::doAction(const QString &actionName) |
| { |
| if (!m_action->isEnabled()) |
| return; |
| |
| if (actionName == pressAction()) { |
| m_action->trigger(); |
| } else if (actionName == showMenuAction()) { |
| #if QT_CONFIG(menubar) |
| if (QMenuBar *bar = qobject_cast<QMenuBar*>(owner())) { |
| if (m_action->menu() && m_action->menu()->isVisible()) { |
| m_action->menu()->hide(); |
| } else { |
| bar->setActiveAction(m_action); |
| } |
| } else |
| #endif |
| if (QMenu *menu = qobject_cast<QMenu*>(owner())){ |
| if (m_action->menu() && m_action->menu()->isVisible()) { |
| m_action->menu()->hide(); |
| } else { |
| menu->setActiveAction(m_action); |
| } |
| } |
| } |
| } |
| |
| QStringList QAccessibleMenuItem::keyBindingsForAction(const QString &) const |
| { |
| return QStringList(); |
| } |
| |
| |
| QAction *QAccessibleMenuItem::action() const |
| { |
| return m_action; |
| } |
| |
| QWidget *QAccessibleMenuItem::owner() const |
| { |
| return m_owner; |
| } |
| |
| #endif // QT_CONFIG(menu) |
| |
| QT_END_NAMESPACE |
| |
| #endif // QT_NO_ACCESSIBILITY |
| |