From eaee2bd0d048367f6bd331fdb4a177004848d77e Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Wed, 5 Feb 2014 11:44:42 +0100 Subject: Accessibility: Use factory function instead of plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This simplifies deployment and makes instantiating accessible interfaces faster since no plugin needs to be loaded. [ChangeLog][QtWidgets] Accessibility for widgets is now included in the widget library instead of being a separate plugin. For static builds this means that libqtaccessiblewidgets is no longer required. Task-number: QTBUG-32888 Change-Id: Ie7347898868fd67c1fc568f0d251cbd2ef71e041 Reviewed-by: Jan Arve Sæther --- src/widgets/accessible/complexwidgets.cpp | 459 ++++++++++++++++++++++++++++++ 1 file changed, 459 insertions(+) create mode 100644 src/widgets/accessible/complexwidgets.cpp (limited to 'src/widgets/accessible/complexwidgets.cpp') diff --git a/src/widgets/accessible/complexwidgets.cpp b/src/widgets/accessible/complexwidgets.cpp new file mode 100644 index 0000000000..5d76ecafbc --- /dev/null +++ b/src/widgets/accessible/complexwidgets.cpp @@ -0,0 +1,459 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "complexwidgets.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef QT_NO_ACCESSIBILITY + +QT_BEGIN_NAMESPACE + +QString qt_accStripAmp(const QString &text); + +#ifndef QT_NO_TABBAR +/*! + \class QAccessibleTabBar + \brief The QAccessibleTabBar class implements the QAccessibleInterface for tab bars. + \internal + + \ingroup accessibility +*/ + +class QAccessibleTabButton: public QAccessibleInterface, public QAccessibleActionInterface +{ +public: + QAccessibleTabButton(QTabBar *parent, int index) + : m_parent(parent), m_index(index) + {} + + void *interface_cast(QAccessible::InterfaceType t) { + if (t == QAccessible::ActionInterface) { + return static_cast(this); + } + return 0; + } + + QObject *object() const { return 0; } + QAccessible::Role role() const { return QAccessible::PageTab; } + QAccessible::State state() const { + QAccessibleInterface *parentInterface = parent(); + QAccessible::State state = parentInterface->state(); + return state; + } + QRect rect() const { + if (!isValid()) + return QRect(); + + QPoint tp = m_parent->mapToGlobal(QPoint(0,0)); + QRect rec = m_parent->tabRect(m_index); + rec = QRect(tp.x() + rec.x(), tp.y() + rec.y(), rec.width(), rec.height()); + return rec; + } + + bool isValid() const { return true; }// (!m_parent.isNull()) && m_parent->count() > m_index; } + + QAccessibleInterface *childAt(int, int) const { return 0; } + int childCount() const { return 0; } + int indexOfChild(const QAccessibleInterface *) const { return -1; } + + QString text(QAccessible::Text) const { return qt_accStripAmp(m_parent->tabText(m_index)); } + void setText(QAccessible::Text, const QString &) {} + + QAccessibleInterface *parent() const { + return QAccessible::queryAccessibleInterface(m_parent); + } + QAccessibleInterface *child(int) const { return 0; } + // action interface + QStringList actionNames() const + { + return QStringList(pressAction()); + } + + void doAction(const QString &actionName) + { + if (actionName == pressAction()) + m_parent->setCurrentIndex(m_index); + } + + QStringList keyBindingsForAction(const QString &) const + { + return QStringList(); + } + + int index() const { return m_index; } + +private: + QPointer m_parent; + int m_index; + +}; + +/*! + Constructs a QAccessibleTabBar object for \a w. +*/ +QAccessibleTabBar::QAccessibleTabBar(QWidget *w) +: QAccessibleWidget(w, QAccessible::PageTabList) +{ + Q_ASSERT(tabBar()); +} + +QAccessibleTabBar::~QAccessibleTabBar() +{ + foreach (QAccessible::Id id, m_childInterfaces.values()) + QAccessible::deleteAccessibleInterface(id); +} + +/*! Returns the QTabBar. */ +QTabBar *QAccessibleTabBar::tabBar() const +{ + return qobject_cast(object()); +} + +QAccessibleInterface* QAccessibleTabBar::child(int index) const +{ + if (QAccessible::Id id = m_childInterfaces.value(index)) + return QAccessible::accessibleInterface(id); + + // first the tabs, then 2 buttons + if (index < tabBar()->count()) { + QAccessibleTabButton *button = new QAccessibleTabButton(tabBar(), index); + QAccessible::registerAccessibleInterface(button); + m_childInterfaces.insert(index, QAccessible::uniqueId(button)); + return button; + } else if (index >= tabBar()->count()) { + // left button + if (index - tabBar()->count() == 0) { + return QAccessible::queryAccessibleInterface(tabBar()->d_func()->leftB); + } + // right button + if (index - tabBar()->count() == 1) { + return QAccessible::queryAccessibleInterface(tabBar()->d_func()->rightB); + } + } + return 0; +} + +int QAccessibleTabBar::indexOfChild(const QAccessibleInterface *child) const +{ + if (child->object() && child->object() == tabBar()->d_func()->leftB) + return tabBar()->count(); + if (child->object() && child->object() == tabBar()->d_func()->rightB) + return tabBar()->count() + 1; + if (child->role() == QAccessible::PageTab) { + QAccessibleInterface *parent = child->parent(); + if (parent == this) { + const QAccessibleTabButton *tabButton = static_cast(child); + return tabButton->index(); + } + } + return -1; +} + +int QAccessibleTabBar::childCount() const +{ + // tabs + scroll buttons + return tabBar()->count() + 2; +} + +QString QAccessibleTabBar::text(QAccessible::Text t) const +{ + if (t == QAccessible::Name) { + return qt_accStripAmp(tabBar()->tabText(tabBar()->currentIndex())); + } + return QString(); +} + +#endif // QT_NO_TABBAR + +#ifndef QT_NO_COMBOBOX +/*! + \class QAccessibleComboBox + \brief The QAccessibleComboBox class implements the QAccessibleInterface for editable and read-only combo boxes. + \internal + + \ingroup accessibility +*/ + +/*! + Constructs a QAccessibleComboBox object for \a w. +*/ +QAccessibleComboBox::QAccessibleComboBox(QWidget *w) +: QAccessibleWidget(w, QAccessible::ComboBox) +{ + Q_ASSERT(comboBox()); +} + +/*! + Returns the combobox. +*/ +QComboBox *QAccessibleComboBox::comboBox() const +{ + return qobject_cast(object()); +} + +QAccessibleInterface *QAccessibleComboBox::child(int index) const +{ + if (index == 0) { + QAbstractItemView *view = comboBox()->view(); + //QWidget *parent = view ? view->parentWidget() : 0; + return QAccessible::queryAccessibleInterface(view); + } else if (index == 1 && comboBox()->isEditable()) { + return QAccessible::queryAccessibleInterface(comboBox()->lineEdit()); + } + return 0; +} + +int QAccessibleComboBox::childCount() const +{ + // list and text edit + return comboBox()->isEditable() ? 2 : 1; +} + +QAccessibleInterface *QAccessibleComboBox::childAt(int x, int y) const +{ + if (comboBox()->isEditable() && comboBox()->lineEdit()->rect().contains(x, y)) + return child(1); + return 0; +} + +int QAccessibleComboBox::indexOfChild(const QAccessibleInterface *child) const +{ + if (comboBox()->view() == child->object()) + return 0; + if (comboBox()->isEditable() && comboBox()->lineEdit() == child->object()) + return 1; + return -1; +} + +/*! \reimp */ +QString QAccessibleComboBox::text(QAccessible::Text t) const +{ + QString str; + + switch (t) { + case QAccessible::Name: +#ifndef Q_OS_UNIX // on Linux we use relations for this, name is text (fall through to Value) + str = QAccessibleWidget::text(t); + break; +#endif + case QAccessible::Value: + if (comboBox()->isEditable()) + str = comboBox()->lineEdit()->text(); + else + str = comboBox()->currentText(); + break; +#ifndef QT_NO_SHORTCUT + case QAccessible::Accelerator: + str = QKeySequence(Qt::Key_Down).toString(QKeySequence::NativeText); + break; +#endif + default: + break; + } + if (str.isEmpty()) + str = QAccessibleWidget::text(t); + return str; +} + +QStringList QAccessibleComboBox::actionNames() const +{ + return QStringList(showMenuAction()); +} + +QString QAccessibleComboBox::localizedActionDescription(const QString &actionName) const +{ + if (actionName == showMenuAction()) + return QComboBox::tr("Open the combo box selection popup"); + return QString(); +} + +void QAccessibleComboBox::doAction(const QString &actionName) +{ + if (actionName == showMenuAction()) { + if (comboBox()->view()->isVisible()) { + comboBox()->hidePopup(); + } else { + comboBox()->showPopup(); + } + } +} + +QStringList QAccessibleComboBox::keyBindingsForAction(const QString &/*actionName*/) const +{ + return QStringList(); +} + +#endif // QT_NO_COMBOBOX + +#ifndef QT_NO_SCROLLAREA +// ======================= QAccessibleAbstractScrollArea ======================= +QAccessibleAbstractScrollArea::QAccessibleAbstractScrollArea(QWidget *widget) + : QAccessibleWidget(widget, QAccessible::Client) +{ + Q_ASSERT(qobject_cast(widget)); +} + +QAccessibleInterface *QAccessibleAbstractScrollArea::child(int index) const +{ + return QAccessible::queryAccessibleInterface(accessibleChildren().at(index)); +} + +int QAccessibleAbstractScrollArea::childCount() const +{ + return accessibleChildren().count(); +} + +int QAccessibleAbstractScrollArea::indexOfChild(const QAccessibleInterface *child) const +{ + if (!child || !child->object()) + return -1; + return accessibleChildren().indexOf(qobject_cast(child->object())); +} + +bool QAccessibleAbstractScrollArea::isValid() const +{ + return (QAccessibleWidget::isValid() && abstractScrollArea() && abstractScrollArea()->viewport()); +} + +QAccessibleInterface *QAccessibleAbstractScrollArea::childAt(int x, int y) const +{ + if (!abstractScrollArea()->isVisible()) + return 0; + + for (int i = 0; i < childCount(); ++i) { + QPoint wpos = accessibleChildren().at(i)->mapToGlobal(QPoint(0, 0)); + QRect rect = QRect(wpos, accessibleChildren().at(i)->size()); + if (rect.contains(x, y)) + return child(i); + } + return 0; +} + +QAbstractScrollArea *QAccessibleAbstractScrollArea::abstractScrollArea() const +{ + return static_cast(object()); +} + +QWidgetList QAccessibleAbstractScrollArea::accessibleChildren() const +{ + QWidgetList children; + + // Viewport. + QWidget * viewport = abstractScrollArea()->viewport(); + if (viewport) + children.append(viewport); + + // Horizontal scrollBar container. + QScrollBar *horizontalScrollBar = abstractScrollArea()->horizontalScrollBar(); + if (horizontalScrollBar && horizontalScrollBar->isVisible()) { + children.append(horizontalScrollBar->parentWidget()); + } + + // Vertical scrollBar container. + QScrollBar *verticalScrollBar = abstractScrollArea()->verticalScrollBar(); + if (verticalScrollBar && verticalScrollBar->isVisible()) { + children.append(verticalScrollBar->parentWidget()); + } + + // CornerWidget. + QWidget *cornerWidget = abstractScrollArea()->cornerWidget(); + if (cornerWidget && cornerWidget->isVisible()) + children.append(cornerWidget); + + return children; +} + +QAccessibleAbstractScrollArea::AbstractScrollAreaElement +QAccessibleAbstractScrollArea::elementType(QWidget *widget) const +{ + if (!widget) + return Undefined; + + if (widget == abstractScrollArea()) + return Self; + if (widget == abstractScrollArea()->viewport()) + return Viewport; + if (widget->objectName() == QLatin1String("qt_scrollarea_hcontainer")) + return HorizontalContainer; + if (widget->objectName() == QLatin1String("qt_scrollarea_vcontainer")) + return VerticalContainer; + if (widget == abstractScrollArea()->cornerWidget()) + return CornerWidget; + + return Undefined; +} + +bool QAccessibleAbstractScrollArea::isLeftToRight() const +{ + return abstractScrollArea()->isLeftToRight(); +} + +// ======================= QAccessibleScrollArea =========================== +QAccessibleScrollArea::QAccessibleScrollArea(QWidget *widget) + : QAccessibleAbstractScrollArea(widget) +{ + Q_ASSERT(qobject_cast(widget)); +} +#endif // QT_NO_SCROLLAREA + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY -- cgit v1.2.3