diff options
Diffstat (limited to 'src/plugins/accessible/widgets')
-rw-r--r-- | src/plugins/accessible/widgets/complexwidgets.cpp | 2163 | ||||
-rw-r--r-- | src/plugins/accessible/widgets/complexwidgets.h | 293 | ||||
-rw-r--r-- | src/plugins/accessible/widgets/main.cpp | 339 | ||||
-rw-r--r-- | src/plugins/accessible/widgets/qaccessiblemenu.cpp | 678 | ||||
-rw-r--r-- | src/plugins/accessible/widgets/qaccessiblemenu.h | 140 | ||||
-rw-r--r-- | src/plugins/accessible/widgets/qaccessiblewidgets.cpp | 1667 | ||||
-rw-r--r-- | src/plugins/accessible/widgets/qaccessiblewidgets.h | 318 | ||||
-rw-r--r-- | src/plugins/accessible/widgets/rangecontrols.cpp | 991 | ||||
-rw-r--r-- | src/plugins/accessible/widgets/rangecontrols.h | 233 | ||||
-rw-r--r-- | src/plugins/accessible/widgets/simplewidgets.cpp | 762 | ||||
-rw-r--r-- | src/plugins/accessible/widgets/simplewidgets.h | 156 | ||||
-rw-r--r-- | src/plugins/accessible/widgets/widgets.pro | 20 |
12 files changed, 7760 insertions, 0 deletions
diff --git a/src/plugins/accessible/widgets/complexwidgets.cpp b/src/plugins/accessible/widgets/complexwidgets.cpp new file mode 100644 index 0000000..68ca02b --- /dev/null +++ b/src/plugins/accessible/widgets/complexwidgets.cpp @@ -0,0 +1,2163 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "complexwidgets.h" + +#include <qapplication.h> +#include <qabstractbutton.h> +#include <qevent.h> +#include <qheaderview.h> +#include <qtabbar.h> +#include <qcombobox.h> +#include <qlistview.h> +#include <qtableview.h> +#include <qlineedit.h> +#include <qstyle.h> +#include <qstyleoption.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qtreeview.h> +#include <private/qtabbar_p.h> +#include <QAbstractScrollArea> +#include <QScrollArea> +#include <QScrollBar> +#include <QDebug> + +#ifndef QT_NO_ACCESSIBILITY + +QT_BEGIN_NAMESPACE + +QString Q_GUI_EXPORT qt_accStripAmp(const QString &text); + +#ifndef QT_NO_ITEMVIEWS +/* +The MSDN article "Exposing Data Tables through Microsoft Active Accessibility" explains +how data tables should be exposed. Url: http://msdn2.microsoft.com/en-us/library/ms971325.aspx +Basically, the model is like this: + +ROLE_SYSTEM_TABLE + |- ROLE_SYSTEM_ROW + | |- ROLE_SYSTEM_ROWHEADER + | |- ROLE_SYSTEM_COLUMNHEADER + | |- ROLE_SYSTEM_COLUMNHEADER + | |- ROLE_SYSTEM_COLUMNHEADER + | '- .. + |- ROLE_SYSTEM_ROW + | |- ROLE_SYSTEM_ROWHEADER + | |- ROLE_SYSTEM_CELL + | |- ROLE_SYSTEM_CELL + | |- ROLE_SYSTEM_CELL + | '- .. + |- ROLE_SYSTEM_ROW + | |- ROLE_SYSTEM_ROWHEADER + | |- ROLE_SYSTEM_CELL + | |- ROLE_SYSTEM_CELL + | |- ROLE_SYSTEM_CELL + | '- .. + '- .. + +The headers of QTreeView is also represented like this. +*/ +QAccessibleItemRow::QAccessibleItemRow(QAbstractItemView *aView, const QModelIndex &index, bool isHeader) + : row(index), view(aView), m_header(isHeader) +{ +} + +QHeaderView *QAccessibleItemRow::horizontalHeader() const +{ + QHeaderView *header = 0; + if (m_header) { + if (false) { +#ifndef QT_NO_TABLEVIEW + } else if (const QTableView *tv = qobject_cast<const QTableView*>(view)) { + header = tv->horizontalHeader(); +#endif +#ifndef QT_NO_TREEVIEW + } else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view)) { + header = tv->header(); +#endif + } + } + return header; +} + +QHeaderView *QAccessibleItemRow::verticalHeader() const +{ + QHeaderView *header = 0; +#ifndef QT_NO_TABLEVIEW + if (const QTableView *tv = qobject_cast<const QTableView*>(view)) + header = tv->verticalHeader(); +#endif + return header; +} + +int QAccessibleItemRow::logicalFromChild(QHeaderView *header, int child) const +{ + int logical = -1; + if (header->sectionsHidden()) { + int kid = 0; + for (int i = 0; i < header->count(); ++i) { + if (!header->isSectionHidden(i)) + ++kid; + if (kid == child) { + logical = i; + break; + } + } + } else { + logical = child - 1; + } + return logical; +} + +QRect QAccessibleItemRow::rect(int child) const +{ + QRect r; + if (view && view->isVisible()) { + if (QHeaderView *header = horizontalHeader()) { + if (!child) { + r = header->rect(); + } else { + if (QHeaderView *vheader = verticalHeader()) { + if (child == 1) { + int w = vheader->width(); + int h = header->height(); + r.setRect(0, 0, w, h); + } + --child; + } + if (child) { + int logical = logicalFromChild(header, child); + int w = header->sectionSize(logical); + r.setRect(header->sectionViewportPosition(logical), 0, w, header->height()); + r.translate(header->mapTo(view, QPoint(0, 0))); + } + } + } else if (row.isValid()) { + if (!child) { + QModelIndex parent = row.parent(); + const int colCount = row.model()->columnCount(parent); + for (int i = 0; i < colCount; ++i) + r |= view->visualRect(row.model()->index(row.row(), i, parent)); + r.translate(view->viewport()->mapTo(view, QPoint(0,0))); + + if (const QHeaderView *vheader = verticalHeader()) { // include the section of the vertical header + QRect re; + int logicalRow = row.row(); + int h = vheader->sectionSize(logicalRow); + re.setRect(0, vheader->sectionViewportPosition(logicalRow), vheader->width(), h); + re.translate(vheader->mapTo(view, QPoint(0, 0))); + r |= re; + } + } else { + if (QHeaderView *vheader = verticalHeader()) { + if (child == 1) { + int logicalRow = row.row(); + int h = vheader->sectionSize(logicalRow); + r.setRect(0, vheader->sectionViewportPosition(logicalRow), vheader->width(), h); + r.translate(vheader->mapTo(view, QPoint(0, 0))); + } + --child; + } + if (child) { + r = view->visualRect(childIndex(child)); + r.translate(view->viewport()->mapTo(view, QPoint(0,0))); + } + } + } + } + if (!r.isNull()) + r.translate(view->mapToGlobal(QPoint(0, 0))); + + return r; +} + +int QAccessibleItemRow::treeLevel() const +{ + int level = 0; + QModelIndex idx = row; + while (idx.isValid()) { + idx = idx.parent(); + ++level; + } + return level; +} + +QString QAccessibleItemRow::text_helper(int child) const +{ + QString value; + if (m_header) { + if (!child) + return QString(); + if (verticalHeader()) { + if (child == 1) + return QString(); + --child; + } + QHeaderView *header = horizontalHeader(); + int logical = logicalFromChild(header, child); + value = view->model()->headerData(logical, Qt::Horizontal, Qt::AccessibleTextRole).toString(); + if (value.isEmpty()) + value = view->model()->headerData(logical, Qt::Horizontal).toString(); + return value; + } else { + if (!child) { // for one-column views (i.e. QListView) + if (children().count() >= 1) + child = 1; + else + return QString(); + } + if (verticalHeader()) { + if (child == 1) { + int logical = row.row(); + value = view->model()->headerData(logical, Qt::Vertical, Qt::AccessibleTextRole).toString(); + if (value.isEmpty()) + value = view->model()->headerData(logical, Qt::Vertical).toString(); + return value; + } else { + --child; + } + } + } + if (value.isEmpty()) { + QModelIndex idx = childIndex(child); + if (idx.isValid()) { + value = idx.model()->data(idx, Qt::AccessibleTextRole).toString(); + if (value.isEmpty()) + value = idx.model()->data(idx, Qt::DisplayRole).toString(); + } + } + return value; +} + +QString QAccessibleItemRow::text(Text t, int child) const +{ + QString value; + if (t == Name) { + value = text_helper(child); + } else if (t == Value) { +#ifndef QT_NO_TREEVIEW + if (qobject_cast<const QTreeView*>(view)) { + if (child == 0) + value = QString::number(treeLevel()); + } else +#endif + { + value = text_helper(child); + } + } else if (t == Description) { +#ifndef QT_NO_TREEVIEW + if (child == 0 && qobject_cast<const QTreeView*>(view)) { + // We store the tree coordinates of the current item in the description. + // This enables some screen readers to report where the focus is + // in a tree view. (works in JAWS). Also, Firefox does the same thing. + // For instance the description "L2, 4 of 25 with 24" means + // "L2": Tree Level 2 + // "4 of 25": We are item 4 out of in total 25 other siblings + // "with 24": We have 24 children. (JAWS does not read this number) + + // level + int level = treeLevel(); + + QAbstractItemModel *m = view->model(); + // totalSiblings and itemIndex + QModelIndex parent = row.parent(); + int rowCount = m->rowCount(parent); + int itemIndex = -1; + int totalSiblings = 0; + for (int i = 0 ; i < rowCount; ++i) { + QModelIndex sibling = row.sibling(i, 0); + if (!view->isIndexHidden(sibling)) + ++totalSiblings; + if (row == sibling) + itemIndex = totalSiblings; + } + int totalChildren = m->rowCount(row); // JAWS does not report child count, so we do + // this simple and efficient. + // (don't check if they are all visible). + value = QString::fromAscii("L%1, %2 of %3 with %4").arg(level).arg(itemIndex).arg(totalSiblings).arg(totalChildren); + } else +#endif // QT_NO_TREEVIEW + { + if (!m_header) { + if (child == 0 && children().count() >= 1) + child = 1; + if (verticalHeader()) { + if (child == 1) { + value = view->model()->headerData(row.row(), Qt::Vertical).toString(); + } + --child; + } + if (child) { + QModelIndex idx = childIndex(child); + value = idx.model()->data(idx, Qt::AccessibleDescriptionRole).toString(); + } + + } + } + } + return value; +} + +void QAccessibleItemRow::setText(Text t, int child, const QString &text) +{ + if (m_header) { + if (child) + view->model()->setHeaderData(child - 1, Qt::Horizontal, text); + // child == 0 means the cell to the left of the horizontal header, which is empty!? + } else { + if (!child) { + if (children().count() == 1) + child = 1; + else + return; + } + + if (verticalHeader()) { + if (child == 1) { + view->model()->setHeaderData(row.row(), Qt::Vertical, text); + return; + } + --child; + } + QModelIndex idx = childIndex(child); + if (!idx.isValid()) + return; + + switch (t) { + case Description: + const_cast<QAbstractItemModel *>(idx.model())->setData(idx, text, + Qt::AccessibleDescriptionRole); + break; + case Value: + const_cast<QAbstractItemModel *>(idx.model())->setData(idx, text, Qt::EditRole); + break; + default: + break; + } + } +} + +QModelIndex QAccessibleItemRow::childIndex(int child) const +{ + QList<QModelIndex> kids = children(); + Q_ASSERT(child >= 1 && child <= kids.count()); + return kids.at(child - 1); +} + +QList<QModelIndex> QAccessibleItemRow::children() const +{ + QList<QModelIndex> kids; + for (int i = 0; i < row.model()->columnCount(row.parent()); ++i) { + QModelIndex idx = row.model()->index(row.row(), i, row.parent()); + if (!view->isIndexHidden(idx)) { + kids << idx; + } + } + return kids; +} + +bool QAccessibleItemRow::isValid() const +{ + return m_header ? true : row.isValid(); +} + +QObject *QAccessibleItemRow::object() const +{ + return 0; +} + +int QAccessibleItemRow::childCount() const +{ + int count = 0; + if (QHeaderView *header = horizontalHeader()) { + count = header->count() - header->hiddenSectionCount(); + } else { + count = children().count(); + } +#ifndef QT_NO_TABLEVIEW + if (qobject_cast<const QTableView*>(view)) { + if (verticalHeader()) + ++count; + } +#endif + return count; +} + +int QAccessibleItemRow::indexOfChild(const QAccessibleInterface *iface) const +{ + if (!iface || iface->role(0) != Row) + return -1; + + //### meaningless code? + QList<QModelIndex> kids = children(); + QModelIndex idx = static_cast<const QAccessibleItemRow *>(iface)->row; + if (!idx.isValid()) + return -1; + return kids.indexOf(idx) + 1; +} + +QAccessible::Relation QAccessibleItemRow::relationTo(int child, const QAccessibleInterface *other, + int otherChild) const +{ + if (!child && !otherChild && other->object() == view) + return Child; + if (!child && !otherChild && other == this) + return Self; + if (!child && otherChild && other == this) + return Ancestor; + if (child && otherChild && other == this) + return Sibling; + return Unrelated; +} + +int QAccessibleItemRow::childAt(int x, int y) const +{ + if (!view || !view->isVisible()) + return -1; + + for (int i = childCount(); i >= 0; --i) { + if (rect(i).contains(x, y)) + return i; + } + return -1; +} + +QAbstractItemView::CursorAction QAccessibleItemRow::toCursorAction( + QAccessible::Relation rel) +{ + switch (rel) { + case QAccessible::Up: + return QAbstractItemView::MoveUp; + case QAccessible::Down: + return QAbstractItemView::MoveDown; + case QAccessible::Left: + return QAbstractItemView::MoveLeft; + case QAccessible::Right: + return QAbstractItemView::MoveRight; + default: + Q_ASSERT(false); + } + // should never be reached. + return QAbstractItemView::MoveRight; +} + +int QAccessibleItemRow::navigate(RelationFlag relation, int index, + QAccessibleInterface **iface) const +{ + *iface = 0; + if (!view) + return -1; + + switch (relation) { + case Ancestor: { + if (!index) + return -1; + QAccessibleItemView *ancestor = new QAccessibleItemView(view->viewport()); + if (index == 1) { + *iface = ancestor; + return 0; + } else if (index > 1) { + int ret = ancestor->navigate(Ancestor, index - 1, iface); + delete ancestor; + return ret; + } + } + case Child: { + if (!index) + return -1; + if (index < 1 && index > childCount()) + return -1; + + return index;} + case Sibling: + if (index) { + QAccessibleInterface *ifaceParent = 0; + navigate(Ancestor, 1, &ifaceParent); + if (ifaceParent) { + int entry = ifaceParent->navigate(Child, index, iface); + delete ifaceParent; + return entry; + } + } + return -1; + case Up: + case Down: + case Left: + case Right: { + // This is in the "not so nice" category. In order to find out which item + // is geometrically around, we have to set the current index, navigate + // and restore the index as well as the old selection + view->setUpdatesEnabled(false); + const QModelIndex oldIdx = view->currentIndex(); + QList<QModelIndex> kids = children(); + const QModelIndex currentIndex = index ? kids.at(index - 1) : QModelIndex(row); + const QItemSelection oldSelection = view->selectionModel()->selection(); + view->setCurrentIndex(currentIndex); + const QModelIndex idx = view->moveCursor(toCursorAction(relation), Qt::NoModifier); + view->setCurrentIndex(oldIdx); + view->selectionModel()->select(oldSelection, QItemSelectionModel::ClearAndSelect); + view->setUpdatesEnabled(true); + if (!idx.isValid()) + return -1; + + if (idx.parent() != row.parent() || idx.row() != row.row()) + *iface = new QAccessibleItemRow(view, idx); + return index ? kids.indexOf(idx) + 1 : 0; } + default: + break; + } + + return -1; +} + +QAccessible::Role QAccessibleItemRow::role(int child) const +{ + if (false) { +#ifndef QT_NO_TREEVIEW + } else if (qobject_cast<const QTreeView*>(view)) { + if (horizontalHeader()) { + if (!child) + return Row; + return ColumnHeader; + } + return TreeItem; +#endif +#ifndef QT_NO_LISTVIEW + } else if (qobject_cast<const QListView*>(view)) { + return ListItem; +#endif +#ifndef QT_NO_TABLEVIEW + } else if (qobject_cast<const QTableView *>(view)) { + if (!child) + return Row; + if (child == 1) { + if (verticalHeader()) + return RowHeader; + } + if (m_header) + return ColumnHeader; +#endif + } + return Cell; +} + +QAccessible::State QAccessibleItemRow::state(int child) const +{ + State st = Normal; + + if (!view) + return st; + + QAccessibleInterface *parent = 0; + QRect globalRect; + if (navigate(Ancestor, 1, &parent) == 0) { + globalRect = parent->rect(0); + delete parent; + } + if (!globalRect.intersects(rect(child))) + st |= Invisible; + + if (!horizontalHeader()) { + if (!(st & Invisible)) { + if (child) { + if (QHeaderView *vheader = verticalHeader() ) { + if (child == 1) { + if (!vheader->isVisible()) + st |= Invisible; + } + --child; + } + if (child) { + QModelIndex idx = childIndex(child); + if (!idx.isValid()) + return st; + + if (view->selectionModel()->isSelected(idx)) + st |= Selected; + if (view->selectionModel()->currentIndex() == idx) + st |= Focused; + if (idx.model()->data(idx, Qt::CheckStateRole).toInt() == Qt::Checked) + st |= Checked; + + Qt::ItemFlags flags = idx.flags(); + if (flags & Qt::ItemIsSelectable) { + st |= Selectable; + if (view->selectionMode() == QAbstractItemView::MultiSelection) + st |= MultiSelectable; + if (view->selectionMode() == QAbstractItemView::ExtendedSelection) + st |= ExtSelectable; + } + } + } else { + Qt::ItemFlags flags = row.flags(); + if (flags & Qt::ItemIsSelectable) { + st |= Selectable; + st |= Focusable; + } + if (view->selectionModel()->isRowSelected(row.row(), row.parent())) + st |= Selected; + if (view->selectionModel()->currentIndex().row() == row.row()) + st |= Focused; + } + } + } + + return st; +} + +int QAccessibleItemRow::userActionCount(int) const +{ + return 0; +} + +QString QAccessibleItemRow::actionText(int, Text, int) const +{ + return QString(); +} + +static QItemSelection rowAt(const QModelIndex &idx) +{ + return QItemSelection(idx.sibling(idx.row(), 0), + idx.sibling(idx.row(), idx.model()->columnCount(idx.parent()))); +} + +bool QAccessibleItemRow::doAction(int action, int child, const QVariantList & /*params*/) +{ + if (!view) + return false; + + if (verticalHeader()) + --child; + + QModelIndex idx = child ? childIndex(child) : QModelIndex(row); + if (!idx.isValid()) + return false; + + QItemSelectionModel::SelectionFlags command = QItemSelectionModel::NoUpdate; + + switch (action) { + case SetFocus: + view->setCurrentIndex(idx); + return true; + case ExtendSelection: + if (!child) + return false; + view->selectionModel()->select(QItemSelection(view->currentIndex(), idx), + QItemSelectionModel::SelectCurrent); + return true; + case Select: + command = QItemSelectionModel::ClearAndSelect; + break; + case ClearSelection: + command = QItemSelectionModel::Clear; + break; + case RemoveSelection: + command = QItemSelectionModel::Deselect; + break; + case AddToSelection: + command = QItemSelectionModel::SelectCurrent; + break; + } + if (command == QItemSelectionModel::NoUpdate) + return false; + + if (child) + view->selectionModel()->select(idx, command); + else + view->selectionModel()->select(rowAt(row), command); + return true; +} + +class ModelIndexIterator +{ +public: + ModelIndexIterator(QAbstractItemView *view, const QModelIndex &start = QModelIndex()) : m_view(view) + { +#ifndef QT_NO_LISTVIEW + list = qobject_cast<QListView*>(m_view); +#endif +#ifndef QT_NO_TREEVIEW + tree = qobject_cast<QTreeView*>(m_view); +#endif +#ifndef QT_NO_TABLEVIEW + table = qobject_cast<QTableView*>(m_view); +#endif + if (start.isValid()) { + m_current = start; + } else if (m_view && m_view->model()) { + m_current = view->model()->index(0, 0); + } + } + + bool next(int count = 1) { + for (int i = 0; i < count; ++i) { + do { + if (m_current.isValid()) { + const QAbstractItemModel *m = m_current.model(); +#ifndef QT_NO_TREEVIEW + if (tree && m_current.model()->hasChildren(m_current) && tree->isExpanded(m_current)) { + m_current = m_current.child(0, 0); + } else +#endif + { + int row = m_current.row(); + QModelIndex par = m_current.parent(); + + // Go up to the parent if we reach the end of the rows + // If m_curent becomses invalid, stop going up. + while (row + 1 >= m->rowCount(par)) { + m_current = par; + if (m_current.isValid()) { + row = m_current.row(); + par = m_current.parent(); + } else { + row = 0; + par = QModelIndex(); + break; + } + } + + if (m_current.isValid()) + m_current = m_current.sibling(row + 1, 0); + } + } + } while (isHidden()); + } + return m_current.isValid(); + } + + bool isHidden() const { + if (false) { +#ifndef QT_NO_LISTVIEW + } else if (list) { + return list->isRowHidden(m_current.row()); +#endif +#ifndef QT_NO_TREEVIEW + } else if (tree) { + return tree->isRowHidden(m_current.row(), m_current.parent()); +#endif +#ifndef QT_NO_TABLEVIEW + } else if (table) { + return table->isRowHidden(m_current.row()); +#endif + } + return false; + } + + QModelIndex current() const { + return m_current; + } + +private: + QModelIndex m_current; + QAbstractItemView *m_view; + +#ifndef QT_NO_TREEVIEW + QTreeView *tree; +#endif +#ifndef QT_NO_LISTVIEW + QListView *list; +#endif +#ifndef QT_NO_TABLEVIEW + QTableView *table; +#endif +}; + +QAccessibleItemView::QAccessibleItemView(QWidget *w) + : QAccessibleAbstractScrollArea(w->objectName() == QLatin1String("qt_scrollarea_viewport") ? w->parentWidget() : w) +{ + atVP = w->objectName() == QLatin1String("qt_scrollarea_viewport"); + +} + + +QHeaderView *QAccessibleItemView::horizontalHeader() const +{ + QHeaderView *header = 0; + if (false) { +#ifndef QT_NO_TABLEVIEW + } else if (const QTableView *tv = qobject_cast<const QTableView*>(itemView())) { + header = tv->horizontalHeader(); +#endif +#ifndef QT_NO_TREEVIEW + } else if (const QTreeView *tv = qobject_cast<const QTreeView*>(itemView())) { + header = tv->header(); +#endif + } + return header; +} + +QHeaderView *QAccessibleItemView::verticalHeader() const +{ + QHeaderView *header = 0; + if (false) { +#ifndef QT_NO_TABLEVIEW + } else if (const QTableView *tv = qobject_cast<const QTableView*>(itemView())) { + header = tv->verticalHeader(); +#endif + } + return header; +} + + +bool QAccessibleItemView::isValidChildRole(QAccessible::Role role) const +{ + if (atViewport()) { + if (false) { +#ifndef QT_NO_TREEVIEW + } else if (qobject_cast<const QTreeView*>(itemView())) { + return (role == TreeItem || role == Row); +#endif +#ifndef QT_NO_LISTVIEW + } else if (qobject_cast<const QListView*>(itemView())) { + return (role == ListItem); +#endif + } + // TableView + return role == Row; + } else { + if (false) { +#ifndef QT_NO_TREEVIEW + } else if (qobject_cast<const QTreeView*>(itemView())) { + return (role == Tree); +#endif +#ifndef QT_NO_LISTVIEW + } else if (qobject_cast<const QListView*>(itemView())) { + return (role == List); +#endif + } + // TableView + return (role == Table); + } +} + +QObject *QAccessibleItemView::object() const +{ + QObject *view = QAccessibleAbstractScrollArea::object(); + Q_ASSERT(qobject_cast<const QAbstractItemView *>(view)); + if (atViewport()) + view = qobject_cast<const QAbstractItemView *>(view)->viewport(); + return view; +} + +QAbstractItemView *QAccessibleItemView::itemView() const +{ + return qobject_cast<QAbstractItemView *>(QAccessibleAbstractScrollArea::object()); +} + +int QAccessibleItemView::indexOfChild(const QAccessibleInterface *iface) const +{ + if (atViewport()) { + if (!iface || !isValidChildRole(iface->role(0))) + return -1; + + int entry = -1; + // ### This will fail if a row is hidden. + const QAccessibleItemRow *ifRow = static_cast<const QAccessibleItemRow *>(iface); + if (ifRow->horizontalHeader()) + return 1; + + QModelIndex idx = ifRow->row; + if (!idx.isValid()) + return -1; + + entry = entryFromIndex(idx); + if (horizontalHeader()) + ++entry; + + return entry; + + } else { + return QAccessibleAbstractScrollArea::indexOfChild(iface); + } +} + +QModelIndex QAccessibleItemView::childIndex(int child) const +{ + if (!atViewport()) + return QModelIndex(); + ModelIndexIterator it(itemView()); + it.next(child - 1); + return it.current(); +} + +int QAccessibleItemView::entryFromIndex(const QModelIndex &index) const +{ + int entry = -1; + if (false) { +#ifndef QT_NO_TREEVIEW + } else if (QTreeView *tree = qobject_cast<QTreeView*>(itemView())) { + entry = tree->visualIndex(index) + 1; +#endif +#ifndef QT_NO_LISTVIEW + } else if (QListView *list = qobject_cast<QListView*>(itemView())) { + entry = list->visualIndex(index) + 1; +#endif +#ifndef QT_NO_TABLEVIEW + } else if (QTableView *table = qobject_cast<QTableView*>(itemView())) { + entry = table->visualIndex(index) + 1; +#endif + } + return entry; +} + +int QAccessibleItemView::childCount() const +{ + if (atViewport()) { + if (itemView()->model() == 0) + return 0; + QAbstractItemModel *m = itemView()->model(); + QModelIndex idx = m->index(0,0); + if (!idx.isValid()) + return 0; + ModelIndexIterator it(itemView()); + int count = 1; + while (it.next()) { + ++count; + } + if (horizontalHeader()) + ++count; + + return count; + } else { + return QAccessibleAbstractScrollArea::childCount(); + } +} + +QString QAccessibleItemView::text(Text t, int child) const +{ + if (atViewport()) { + if (!child) + return QAccessibleAbstractScrollArea::text(t, child); + + QAccessibleItemRow item(itemView(), childIndex(child)); + return item.text(t, 1); + } else { + return QAccessibleAbstractScrollArea::text(t, child); + } +} + +void QAccessibleItemView::setText(Text t, int child, const QString &text) +{ + if (atViewport()) { + if (!child) { + QAccessibleAbstractScrollArea::setText(t, child, text); + return; + } + + QAccessibleItemRow item(itemView(), childIndex(child)); + item.setText(t, 1, text); + } else { + QAccessibleAbstractScrollArea::setText(t, child, text); + } +} + +QRect QAccessibleItemView::rect(int child) const +{ + if (atViewport()) { + QRect r; + if (!child) { + // Make sure that the rect *include* the vertical and horizontal headers, while + // not including the potential vertical and horizontal scrollbars. + QAbstractItemView *w = itemView(); + + int vscrollWidth = 0; + const QScrollBar *sb = w->verticalScrollBar(); + if (sb && sb->isVisible()) + vscrollWidth = sb->width(); + + int hscrollHeight = 0; + sb = w->horizontalScrollBar(); + if (sb && sb->isVisible()) + hscrollHeight = sb->height(); + + QPoint globalPos = w->mapToGlobal(QPoint(0,0)); + r = w->rect().translated(globalPos); + if (w->isRightToLeft()) { + r.adjust(vscrollWidth, 0, 0, -hscrollHeight); + } else { + r.adjust(0, 0, -vscrollWidth, -hscrollHeight); + } + } else { + QAccessibleInterface *iface = 0; + if (navigate(Child, child, &iface) == 0) { + r = iface->rect(0); + delete iface; + } + } + return r; + } else { + QRect r = QAccessibleAbstractScrollArea::rect(child); + if (child == 1) { + // include the potential vertical and horizontal headers + + const QHeaderView *header = verticalHeader(); + int headerWidth = (header && header->isVisible()) ? header->width() : 0; + header = horizontalHeader(); + int headerHeight= (header && header->isVisible()) ? header->height() : 0; + if (itemView()->isRightToLeft()) { + r.adjust(0, -headerHeight, headerWidth, 0); + } else { + r.adjust(-headerWidth, -headerHeight, 0, 0); + } + } + return r; + } +} + +int QAccessibleItemView::childAt(int x, int y) const +{ + if (atViewport()) { + QPoint p(x, y); + for (int i = childCount(); i >= 0; --i) { + if (rect(i).contains(p)) + return i; + } + return -1; + } else { + return QAccessibleAbstractScrollArea::childAt(x, y); + } +} + +QAccessible::Role QAccessibleItemView::role(int child) const +{ + if ((!atViewport() && child) || (atViewport() && child == 0)) { + QAbstractItemView *view = itemView(); +#ifndef QT_NO_TABLEVIEW + if (qobject_cast<QTableView *>(view)) + return Table; +#endif +#ifndef QT_NO_LISTVIEW + if (qobject_cast<QListView *>(view)) + return List; +#endif + return Tree; + } + if (atViewport()) { + if (child) + return Row; + } + + return QAccessibleAbstractScrollArea::role(child); +} + +QAccessible::State QAccessibleItemView::state(int child) const +{ + State st = Normal; + + if (itemView() == 0) + return State(Unavailable); + + bool queryViewPort = (atViewport() && child == 0) || (!atViewport() && child == 1); + if (queryViewPort) { + if (itemView()->selectionMode() != QAbstractItemView::NoSelection) { + st |= Selectable; + st |= Focusable; + } + } else if (atViewport()) { // children of viewport + if (horizontalHeader()) + --child; + if (child) { + QAccessibleItemRow item(itemView(), childIndex(child)); + st |= item.state(0); + } + } else if (!atViewport() && child != 1) { + st = QAccessibleAbstractScrollArea::state(child); + } + return st; +} + +bool QAccessibleItemView::isValid() const +{ + if (atViewport()) + return QAccessibleWidgetEx::isValid(); + else + return QAccessibleAbstractScrollArea::isValid(); +} + +int QAccessibleItemView::navigate(RelationFlag relation, int index, + QAccessibleInterface **iface) const +{ + if (atViewport()) { + if (relation == Ancestor && index == 1) { + *iface = new QAccessibleItemView(itemView()); + return 0; + } else if (relation == Child && index >= 1) { + if (horizontalHeader()) { + if (index == 1) { + *iface = new QAccessibleItemRow(itemView(), QModelIndex(), true); + return 0; + } + --index; + } + + //###JAS hidden rows.. + QModelIndex idx = childIndex(index); + if (idx.isValid()) { + *iface = new QAccessibleItemRow(itemView(), idx); + return 0; + } + } else if (relation == Sibling && index >= 1) { + QAccessibleInterface *parent = new QAccessibleItemView(itemView()); + return parent->navigate(Child, index, iface); + } + *iface = 0; + return -1; + } else { + return QAccessibleAbstractScrollArea::navigate(relation, index, iface); + } +} + +/* returns the model index for a given row and column */ +QModelIndex QAccessibleItemView::index(int row, int column) const +{ + return itemView()->model()->index(row, column); +} + +QAccessibleInterface *QAccessibleItemView::accessibleAt(int row, int column) +{ + QWidget *indexWidget = itemView()->indexWidget(index(row, column)); + return QAccessible::queryAccessibleInterface(indexWidget); +} + +/* We don't have a concept of a "caption" in Qt's standard widgets */ +QAccessibleInterface *QAccessibleItemView::caption() +{ + return 0; +} + +/* childIndex is row * columnCount + columnIndex */ +int QAccessibleItemView::childIndex(int rowIndex, int columnIndex) +{ + return rowIndex * itemView()->model()->columnCount() + columnIndex; +} + +/* Return the header data as column description */ +QString QAccessibleItemView::columnDescription(int column) +{ + return itemView()->model()->headerData(column, Qt::Horizontal).toString(); +} + +/* We don't support column spanning atm */ +int QAccessibleItemView::columnSpan(int /* row */, int /* column */) +{ + return 1; +} + +/* Return the horizontal header view */ +QAccessibleInterface *QAccessibleItemView::columnHeader() +{ +#ifndef QT_NO_TREEVIEW + if (QTreeView *tree = qobject_cast<QTreeView *>(itemView())) + return QAccessible::queryAccessibleInterface(tree->header()); +#endif +#ifndef QT_NO_TABLEVIEW + if (QTableView *table = qobject_cast<QTableView *>(itemView())) + return QAccessible::queryAccessibleInterface(table->horizontalHeader()); +#endif + return 0; +} + +int QAccessibleItemView::columnIndex(int childIndex) +{ + int columnCount = itemView()->model()->columnCount(); + if (!columnCount) + return 0; + + return childIndex % columnCount; +} + +int QAccessibleItemView::columnCount() +{ + return itemView()->model()->columnCount(); +} + +int QAccessibleItemView::rowCount() +{ + return itemView()->model()->rowCount(); +} + +int QAccessibleItemView::selectedColumnCount() +{ + return itemView()->selectionModel()->selectedColumns().count(); +} + +int QAccessibleItemView::selectedRowCount() +{ + return itemView()->selectionModel()->selectedRows().count(); +} + +QString QAccessibleItemView::rowDescription(int row) +{ + return itemView()->model()->headerData(row, Qt::Vertical).toString(); +} + +/* We don't support row spanning */ +int QAccessibleItemView::rowSpan(int /*row*/, int /*column*/) +{ + return 1; +} + +QAccessibleInterface *QAccessibleItemView::rowHeader() +{ +#ifndef QT_NO_TABLEVIEW + if (QTableView *table = qobject_cast<QTableView *>(itemView())) + return QAccessible::queryAccessibleInterface(table->verticalHeader()); +#endif + return 0; +} + +int QAccessibleItemView::rowIndex(int childIndex) +{ + int columnCount = itemView()->model()->columnCount(); + if (!columnCount) + return 0; + + return int(childIndex / columnCount); +} + +int QAccessibleItemView::selectedRows(int maxRows, QList<int> *rows) +{ + Q_ASSERT(rows); + + const QModelIndexList selRows = itemView()->selectionModel()->selectedRows(); + int maxCount = qMin(selRows.count(), maxRows); + + for (int i = 0; i < maxCount; ++i) + rows->append(selRows.at(i).row()); + + return maxCount; +} + +int QAccessibleItemView::selectedColumns(int maxColumns, QList<int> *columns) +{ + Q_ASSERT(columns); + + const QModelIndexList selColumns = itemView()->selectionModel()->selectedColumns(); + int maxCount = qMin(selColumns.count(), maxColumns); + + for (int i = 0; i < maxCount; ++i) + columns->append(selColumns.at(i).row()); + + return maxCount; +} + +/* Qt widgets don't have a concept of a summary */ +QAccessibleInterface *QAccessibleItemView::summary() +{ + return 0; +} + +bool QAccessibleItemView::isColumnSelected(int column) +{ + return itemView()->selectionModel()->isColumnSelected(column, QModelIndex()); +} + +bool QAccessibleItemView::isRowSelected(int row) +{ + return itemView()->selectionModel()->isRowSelected(row, QModelIndex()); +} + +bool QAccessibleItemView::isSelected(int row, int column) +{ + return itemView()->selectionModel()->isSelected(index(row, column)); +} + +void QAccessibleItemView::selectRow(int row) +{ + QItemSelectionModel *s = itemView()->selectionModel(); + s->select(index(row, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows); +} + +void QAccessibleItemView::selectColumn(int column) +{ + QItemSelectionModel *s = itemView()->selectionModel(); + s->select(index(0, column), QItemSelectionModel::Select | QItemSelectionModel::Columns); +} + +void QAccessibleItemView::unselectRow(int row) +{ + QItemSelectionModel *s = itemView()->selectionModel(); + s->select(index(row, 0), QItemSelectionModel::Deselect | QItemSelectionModel::Rows); +} + +void QAccessibleItemView::unselectColumn(int column) +{ + QItemSelectionModel *s = itemView()->selectionModel(); + s->select(index(0, column), QItemSelectionModel::Deselect | QItemSelectionModel::Columns); +} + +void QAccessibleItemView::cellAtIndex(int index, int *row, int *column, int *rSpan, + int *cSpan, bool *isSelect) +{ + *row = rowIndex(index); + *column = columnIndex(index); + *rSpan = rowSpan(*row, *column); + *cSpan = columnSpan(*row, *column); + *isSelect = isSelected(*row, *column); +} + +/*! + \class QAccessibleHeader + \brief The QAccessibleHeader class implements the QAccessibleInterface for header widgets. + \internal + + \ingroup accessibility +*/ + +/*! + Constructs a QAccessibleHeader object for \a w. +*/ +QAccessibleHeader::QAccessibleHeader(QWidget *w) +: QAccessibleWidgetEx(w) +{ + Q_ASSERT(header()); + addControllingSignal(QLatin1String("sectionClicked(int)")); +} + +/*! Returns the QHeaderView. */ +QHeaderView *QAccessibleHeader::header() const +{ + return qobject_cast<QHeaderView*>(object()); +} + +/*! \reimp */ +QRect QAccessibleHeader::rect(int child) const +{ + if (!child) + return QAccessibleWidgetEx::rect(0); + + QHeaderView *h = header(); + QPoint zero = h->mapToGlobal(QPoint(0, 0)); + int sectionSize = h->sectionSize(child - 1); + int sectionPos = h->sectionPosition(child - 1); + return h->orientation() == Qt::Horizontal + ? QRect(zero.x() + sectionPos, zero.y(), sectionSize, h->height()) + : QRect(zero.x(), zero.y() + sectionPos, h->width(), sectionSize); +} + +/*! \reimp */ +int QAccessibleHeader::childCount() const +{ + return header()->count(); +} + +/*! \reimp */ +QString QAccessibleHeader::text(Text t, int child) const +{ + QString str; + + if (child > 0 && child <= childCount()) { + switch (t) { + case Name: + str = header()->model()->headerData(child - 1, header()->orientation()).toString(); + break; + case Description: { + QAccessibleEvent event(QEvent::AccessibilityDescription, child); + if (QApplication::sendEvent(widget(), &event)) + str = event.value(); + break; } + case Help: { + QAccessibleEvent event(QEvent::AccessibilityHelp, child); + if (QApplication::sendEvent(widget(), &event)) + str = event.value(); + break; } + default: + break; + } + } + if (str.isEmpty()) + str = QAccessibleWidgetEx::text(t, child); + return str; +} + +/*! \reimp */ +QAccessible::Role QAccessibleHeader::role(int) const +{ + return (header()->orientation() == Qt::Horizontal) ? ColumnHeader : RowHeader; +} + +/*! \reimp */ +QAccessible::State QAccessibleHeader::state(int child) const +{ + State state = QAccessibleWidgetEx::state(child); + + if (child) { + int section = child - 1; + if (header()->isSectionHidden(section)) + state |= Invisible; + if (header()->resizeMode(section) != QHeaderView::Custom) + state |= Sizeable; + } else { + if (header()->isMovable()) + state |= Movable; + } + if (!header()->isClickable()) + state |= Unavailable; + return state; +} +#endif // QT_NO_ITEMVIEWS + +#ifndef QT_NO_TABBAR +/*! + \class QAccessibleTabBar + \brief The QAccessibleTabBar class implements the QAccessibleInterface for tab bars. + \internal + + \ingroup accessibility +*/ + +/*! + Constructs a QAccessibleTabBar object for \a w. +*/ +QAccessibleTabBar::QAccessibleTabBar(QWidget *w) +: QAccessibleWidgetEx(w) +{ + Q_ASSERT(tabBar()); +} + +/*! Returns the QTabBar. */ +QTabBar *QAccessibleTabBar::tabBar() const +{ + return qobject_cast<QTabBar*>(object()); +} + +QAbstractButton *QAccessibleTabBar::button(int child) const +{ + if (child <= tabBar()->count()) + return 0; + QTabBarPrivate * const tabBarPrivate = tabBar()->d_func(); + if (child - tabBar()->count() == 1) + return tabBarPrivate->leftB; + if (child - tabBar()->count() == 2) + return tabBarPrivate->rightB; + Q_ASSERT(false); + return 0; +} + +/*! \reimp */ +QRect QAccessibleTabBar::rect(int child) const +{ + if (!child || !tabBar()->isVisible()) + return QAccessibleWidgetEx::rect(0); + + QPoint tp = tabBar()->mapToGlobal(QPoint(0,0)); + QRect rec; + if (child <= tabBar()->count()) { + rec = tabBar()->tabRect(child - 1); + } else { + QWidget *widget = button(child); + rec = widget ? widget->geometry() : QRect(); + } + return QRect(tp.x() + rec.x(), tp.y() + rec.y(), rec.width(), rec.height()); +} + +/*! \reimp */ +int QAccessibleTabBar::childCount() const +{ + // tabs + scroll buttons + return tabBar()->count() + 2; +} + +/*! \reimp */ +QString QAccessibleTabBar::text(Text t, int child) const +{ + QString str; + + if (child > tabBar()->count()) { + bool left = child - tabBar()->count() == 1; + switch (t) { + case Name: + return left ? QTabBar::tr("Scroll Left") : QTabBar::tr("Scroll Right"); + default: + break; + } + } else if (child > 0) { + switch (t) { + case Name: + return qt_accStripAmp(tabBar()->tabText(child - 1)); + default: + break; + } + } + + if (str.isEmpty()) + str = QAccessibleWidgetEx::text(t, child);; + return str; +} + +/*! \reimp */ +QAccessible::Role QAccessibleTabBar::role(int child) const +{ + if (!child) + return PageTabList; + if (child > tabBar()->count()) + return PushButton; + return PageTab; +} + +/*! \reimp */ +QAccessible::State QAccessibleTabBar::state(int child) const +{ + State st = QAccessibleWidgetEx::state(0); + + if (!child) + return st; + + QTabBar *tb = tabBar(); + + if (child > tb->count()) { + QWidget *bt = button(child); + if (!bt) + return st; + if (bt->isEnabled() == false) + st |= Unavailable; + if (bt->isVisible() == false) + st |= Invisible; + if (bt->focusPolicy() != Qt::NoFocus && bt->isActiveWindow()) + st |= Focusable; + if (bt->hasFocus()) + st |= Focused; + return st; + } + + if (!tb->isTabEnabled(child - 1)) + st |= Unavailable; + else + st |= Selectable; + + if (!tb->currentIndex() == child - 1) + st |= Selected; + + return st; +} + +/*! \reimp */ +bool QAccessibleTabBar::doAction(int action, int child, const QVariantList &) +{ + if (!child) + return false; + + if (action != QAccessible::DefaultAction && action != QAccessible::Press) + return false; + + if (child > tabBar()->count()) { + QAbstractButton *bt = button(child); + if (!bt->isEnabled()) + return false; + bt->animateClick(); + return true; + } + if (!tabBar()->isTabEnabled(child - 1)) + return false; + tabBar()->setCurrentIndex(child - 1); + return true; +} + +/*! + Selects the item with index \a child if \a on is true; otherwise + unselects it. If \a extend is true and the selection mode is not + \c Single and there is an existing selection, the selection is + extended to include all the items from the existing selection up + to and including the item with index \a child. Returns true if a + selection was made or extended; otherwise returns false. + + \sa selection() clearSelection() +*/ +bool QAccessibleTabBar::setSelected(int child, bool on, bool extend) +{ + if (!child || !on || extend || child > tabBar()->count()) + return false; + + if (!tabBar()->isTabEnabled(child - 1)) + return false; + tabBar()->setCurrentIndex(child - 1); + return true; +} + +/*! + Returns a (possibly empty) list of indexes of the items selected + in the list box. + + \sa setSelected() clearSelection() +*/ +QVector<int> QAccessibleTabBar::selection() const +{ + QVector<int> array; + if (tabBar()->currentIndex() != -1) + array +=tabBar()->currentIndex() + 1; + return array; +} + +#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 +*/ + +/*! + \enum QAccessibleComboBox::ComboBoxElements + + \internal + + \value ComboBoxSelf + \value CurrentText + \value OpenList + \value PopupList +*/ + +/*! + Constructs a QAccessibleComboBox object for \a w. +*/ +QAccessibleComboBox::QAccessibleComboBox(QWidget *w) +: QAccessibleWidgetEx(w, ComboBox) +{ + Q_ASSERT(comboBox()); +} + +/*! + Returns the combobox. +*/ +QComboBox *QAccessibleComboBox::comboBox() const +{ + return qobject_cast<QComboBox*>(object()); +} + +/*! \reimp */ +QRect QAccessibleComboBox::rect(int child) const +{ + QPoint tp; + QStyle::SubControl sc; + QRect r; + switch (child) { + case CurrentText: + if (comboBox()->isEditable()) { + tp = comboBox()->lineEdit()->mapToGlobal(QPoint(0,0)); + r = comboBox()->lineEdit()->rect(); + sc = QStyle::SC_None; + } else { + tp = comboBox()->mapToGlobal(QPoint(0,0)); + sc = QStyle::SC_ComboBoxEditField; + } + break; + case OpenList: + tp = comboBox()->mapToGlobal(QPoint(0,0)); + sc = QStyle::SC_ComboBoxArrow; + break; + default: + return QAccessibleWidgetEx::rect(child); + } + + if (sc != QStyle::SC_None) { + QStyleOptionComboBox option; + option.initFrom(comboBox()); + r = comboBox()->style()->subControlRect(QStyle::CC_ComboBox, &option, sc, comboBox()); + } + return QRect(tp.x() + r.x(), tp.y() + r.y(), r.width(), r.height()); +} + +/*! \reimp */ +int QAccessibleComboBox::navigate(RelationFlag rel, int entry, QAccessibleInterface **target) const +{ + *target = 0; + if (entry > ComboBoxSelf) switch (rel) { + case Child: + if (entry < PopupList) + return entry; + if (entry == PopupList) { + QAbstractItemView *view = comboBox()->view(); + QWidget *parent = view ? view->parentWidget() : 0; + *target = QAccessible::queryAccessibleInterface(parent); + return *target ? 0 : -1; + } + case QAccessible::Left: + return entry == OpenList ? CurrentText : -1; + case QAccessible::Right: + return entry == CurrentText ? OpenList : -1; + case QAccessible::Up: + return -1; + case QAccessible::Down: + return -1; + default: + break; + } + return QAccessibleWidgetEx::navigate(rel, entry, target); +} + +/*! \reimp */ +int QAccessibleComboBox::childCount() const +{ + return comboBox()->view() ? PopupList : OpenList; +} + +/*! \reimp */ +int QAccessibleComboBox::childAt(int x, int y) const +{ + if (!comboBox()->isVisible()) + return -1; + QPoint gp = widget()->mapToGlobal(QPoint(0, 0)); + if (!QRect(gp.x(), gp.y(), widget()->width(), widget()->height()).contains(x, y)) + return -1; + + // a complex control + for (int i = 1; i < PopupList; ++i) { + if (rect(i).contains(x, y)) + return i; + } + return 0; +} + +/*! \reimp */ +int QAccessibleComboBox::indexOfChild(const QAccessibleInterface *child) const +{ + QObject *viewParent = comboBox()->view() ? comboBox()->view()->parentWidget() : 0; + if (child->object() == viewParent) + return PopupList; + return -1; +} + +/*! \reimp */ +QString QAccessibleComboBox::text(Text t, int child) const +{ + QString str; + + switch (t) { + case Name: + if (child == OpenList) + str = QComboBox::tr("Open"); + else + str = QAccessibleWidgetEx::text(t, 0); + break; +#ifndef QT_NO_SHORTCUT + case Accelerator: + if (child == OpenList) + str = (QString)QKeySequence(Qt::Key_Down); + // missing break? +#endif + case Value: + if (comboBox()->isEditable()) + str = comboBox()->lineEdit()->text(); + else + str = comboBox()->currentText(); + break; + default: + break; + } + if (str.isEmpty()) + str = QAccessibleWidgetEx::text(t, 0); + return str; +} + +/*! \reimp */ +QAccessible::Role QAccessibleComboBox::role(int child) const +{ + switch (child) { + case CurrentText: + if (comboBox()->isEditable()) + return EditableText; + return StaticText; + case OpenList: + return PushButton; + case PopupList: + return List; + default: + return ComboBox; + } +} + +/*! \reimp */ +QAccessible::State QAccessibleComboBox::state(int /*child*/) const +{ + return QAccessibleWidgetEx::state(0); +} + +/*! \reimp */ +bool QAccessibleComboBox::doAction(int action, int child, const QVariantList &) +{ + if (child == 2 && (action == DefaultAction || action == Press)) { + if (comboBox()->view()->isVisible()) { + comboBox()->hidePopup(); + } else { + comboBox()->showPopup(); + } + return true; + } + return false; +} + +QString QAccessibleComboBox::actionText(int action, Text t, int child) const +{ + QString text; + if (child == 2 && t == Name && (action == DefaultAction || action == Press)) + text = comboBox()->view()->isVisible() ? QComboBox::tr("Close") : QComboBox::tr("Open"); + return text; +} +#endif // QT_NO_COMBOBOX + +static inline void removeInvisibleWidgetsFromList(QWidgetList *list) +{ + if (!list || list->isEmpty()) + return; + + for (int i = 0; i < list->count(); ++i) { + QWidget *widget = list->at(i); + if (!widget->isVisible()) + list->removeAt(i); + } +} + +#ifndef QT_NO_SCROLLAREA +// ======================= QAccessibleAbstractScrollArea ======================= +QAccessibleAbstractScrollArea::QAccessibleAbstractScrollArea(QWidget *widget) + : QAccessibleWidgetEx(widget, Client) +{ + Q_ASSERT(qobject_cast<QAbstractScrollArea *>(widget)); +} + +QString QAccessibleAbstractScrollArea::text(Text textType, int child) const +{ + if (child == Self) + return QAccessibleWidgetEx::text(textType, 0); + QWidgetList children = accessibleChildren(); + if (child < 1 || child > children.count()) + return QString(); + QAccessibleInterface *childInterface = queryAccessibleInterface(children.at(child - 1)); + if (!childInterface) + return QString(); + QString string = childInterface->text(textType, 0); + delete childInterface; + return string; +} + +void QAccessibleAbstractScrollArea::setText(Text textType, int child, const QString &text) +{ + if (text.isEmpty()) + return; + if (child == 0) { + QAccessibleWidgetEx::setText(textType, 0, text); + return; + } + QWidgetList children = accessibleChildren(); + if (child < 1 || child > children.count()) + return; + QAccessibleInterface *childInterface = queryAccessibleInterface(children.at(child - 1)); + if (!childInterface) + return; + childInterface->setText(textType, 0, text); + delete childInterface; +} + +QAccessible::State QAccessibleAbstractScrollArea::state(int child) const +{ + if (child == Self) + return QAccessibleWidgetEx::state(child); + QWidgetList children = accessibleChildren(); + if (child < 1 || child > children.count()) + return QAccessibleWidgetEx::state(Self); + QAccessibleInterface *childInterface = queryAccessibleInterface(children.at(child - 1)); + if (!childInterface) + return QAccessibleWidgetEx::state(Self); + QAccessible::State returnState = childInterface->state(0); + delete childInterface; + return returnState; +} + +QVariant QAccessibleAbstractScrollArea::invokeMethodEx(QAccessible::Method, int, const QVariantList &) +{ + return QVariant(); +} + +int QAccessibleAbstractScrollArea::childCount() const +{ + return accessibleChildren().count(); +} + +int QAccessibleAbstractScrollArea::indexOfChild(const QAccessibleInterface *child) const +{ + if (!child || !child->object()) + return -1; + int index = accessibleChildren().indexOf(qobject_cast<QWidget *>(child->object())); + if (index >= 0) + return ++index; + return -1; +} + +bool QAccessibleAbstractScrollArea::isValid() const +{ + return (QAccessibleWidgetEx::isValid() && abstractScrollArea() && abstractScrollArea()->viewport()); +} + +int QAccessibleAbstractScrollArea::navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const +{ + if (!target) + return -1; + + *target = 0; + + QWidget *targetWidget = 0; + QWidget *entryWidget = 0; + + if (relation == Child || + relation == Left || relation == Up || relation == Right || relation == Down) { + QWidgetList children = accessibleChildren(); + if (entry < 0 || entry > children.count()) + return -1; + + if (entry == Self) + entryWidget = abstractScrollArea(); + else + entryWidget = children.at(entry - 1); + AbstractScrollAreaElement entryElement = elementType(entryWidget); + + // Not one of the most beautiful switches I've ever seen, but I believe it has + // to be like this since each case need special handling. + // It might be possible to make it more general, but I'll leave that as an exercise + // to the reader. :-) + switch (relation) { + case Child: + if (entry > 0) + targetWidget = children.at(entry - 1); + break; + case Left: + if (entry < 1) + break; + switch (entryElement) { + case Viewport: + if (!isLeftToRight()) + targetWidget = abstractScrollArea()->verticalScrollBar(); + break; + case HorizontalContainer: + if (!isLeftToRight()) + targetWidget = abstractScrollArea()->cornerWidget(); + break; + case VerticalContainer: + if (isLeftToRight()) + targetWidget = abstractScrollArea()->viewport(); + break; + case CornerWidget: + if (isLeftToRight()) + targetWidget = abstractScrollArea()->horizontalScrollBar(); + break; + default: + break; + } + break; + case Right: + if (entry < 1) + break; + switch (entryElement) { + case Viewport: + if (isLeftToRight()) + targetWidget = abstractScrollArea()->verticalScrollBar(); + break; + case HorizontalContainer: + targetWidget = abstractScrollArea()->cornerWidget(); + break; + case VerticalContainer: + if (!isLeftToRight()) + targetWidget = abstractScrollArea()->viewport(); + break; + case CornerWidget: + if (!isLeftToRight()) + targetWidget = abstractScrollArea()->horizontalScrollBar(); + break; + default: + break; + } + break; + case Up: + if (entry < 1) + break; + switch (entryElement) { + case HorizontalContainer: + targetWidget = abstractScrollArea()->viewport(); + break; + case CornerWidget: + targetWidget = abstractScrollArea()->verticalScrollBar(); + break; + default: + break; + } + break; + case Down: + if (entry < 1) + break; + switch (entryElement) { + case Viewport: + targetWidget = abstractScrollArea()->horizontalScrollBar(); + break; + case VerticalContainer: + targetWidget = abstractScrollArea()->cornerWidget(); + break; + default: + break; + } + break; + default: + break; + } + } else { + return QAccessibleWidgetEx::navigate(relation, entry, target); + } + + if (qobject_cast<const QScrollBar *>(targetWidget)) + targetWidget = targetWidget->parentWidget(); + *target = QAccessible::queryAccessibleInterface(targetWidget); + return *target ? 0: -1; +} + +QRect QAccessibleAbstractScrollArea::rect(int child) const +{ + if (!abstractScrollArea()->isVisible()) + return QRect(); + if (child == Self) + return QAccessibleWidgetEx::rect(child); + QWidgetList children = accessibleChildren(); + if (child < 1 || child > children.count()) + return QRect(); + const QWidget *childWidget = children.at(child - 1); + if (!childWidget->isVisible()) + return QRect(); + return QRect(childWidget->mapToGlobal(QPoint(0, 0)), childWidget->size()); +} + +int QAccessibleAbstractScrollArea::childAt(int x, int y) const +{ + if (!abstractScrollArea()->isVisible()) + return -1; +#if 0 + const QRect globalSelfGeometry = rect(Self); + if (!globalSelfGeometry.isValid() || !globalSelfGeometry.contains(QPoint(x, y))) + return -1; + const QWidgetList children = accessibleChildren(); + for (int i = 0; i < children.count(); ++i) { + const QWidget *child = children.at(i); + const QRect globalChildGeometry = QRect(child->mapToGlobal(QPoint(0, 0)), child->size()); + if (globalChildGeometry.contains(QPoint(x, y))) { + return ++i; + } + } + return 0; +#else + for (int i = childCount(); i >= 0; --i) { + if (rect(i).contains(x, y)) + return i; + } + return -1; +#endif +} + +QAbstractScrollArea *QAccessibleAbstractScrollArea::abstractScrollArea() const +{ + return static_cast<QAbstractScrollArea *>(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<QScrollArea *>(widget)); +} +#endif // QT_NO_SCROLLAREA + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/widgets/complexwidgets.h b/src/plugins/accessible/widgets/complexwidgets.h new file mode 100644 index 0000000..d5666a7 --- /dev/null +++ b/src/plugins/accessible/widgets/complexwidgets.h @@ -0,0 +1,293 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef COMPLEXWIDGETS_H +#define COMPLEXWIDGETS_H + +#include <QtCore/qpointer.h> +#include <QtGui/qaccessiblewidget.h> +#include <QtGui/qabstractitemview.h> +#include <QtGui/qaccessible2.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_ACCESSIBILITY + +class QAbstractButton; +class QHeaderView; +class QTabBar; +class QComboBox; +class QTitleBar; +class QAbstractScrollArea; +class QScrollArea; + +#ifndef QT_NO_SCROLLAREA +class QAccessibleAbstractScrollArea : public QAccessibleWidgetEx +{ +public: + explicit QAccessibleAbstractScrollArea(QWidget *widget); + + enum AbstractScrollAreaElement { + Self = 0, + Viewport, + HorizontalContainer, + VerticalContainer, + CornerWidget, + Undefined + }; + + QString text(Text textType, int child) const; + void setText(Text textType, int child, const QString &text); + State state(int child) const; + QVariant invokeMethodEx(QAccessible::Method method, int child, const QVariantList ¶ms); + int childCount() const; + int indexOfChild(const QAccessibleInterface *child) const; + bool isValid() const; + int navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const; + QRect rect(int child) const; + int childAt(int x, int y) const; + +//protected: + QAbstractScrollArea *abstractScrollArea() const; + +private: + QWidgetList accessibleChildren() const; + AbstractScrollAreaElement elementType(QWidget *widget) const; + bool isLeftToRight() const; +}; + +class QAccessibleScrollArea : public QAccessibleAbstractScrollArea +{ +public: + explicit QAccessibleScrollArea(QWidget *widget); +}; + +#endif // QT_NO_SCROLLAREA + +#ifndef QT_NO_ITEMVIEWS +class QAccessibleHeader : public QAccessibleWidgetEx +{ + Q_ACCESSIBLE_OBJECT +public: + explicit QAccessibleHeader(QWidget *w); + + int childCount() const; + + QRect rect(int child) const; + QString text(Text t, int child) const; + Role role(int child) const; + State state(int child) const; + +protected: + QHeaderView *header() const; +}; + +class QAccessibleItemRow: public QAccessibleInterface +{ + friend class QAccessibleItemView; +public: + QAccessibleItemRow(QAbstractItemView *view, const QModelIndex &index = QModelIndex(), bool isHeader = false); + QRect rect(int child) const; + QString text(Text t, int child) const; + void setText(Text t, int child, const QString &text); + bool isValid() const; + QObject *object() const; + Role role(int child) const; + State state(int child) const; + + int childCount() const; + int indexOfChild(const QAccessibleInterface *) const; + QList<QModelIndex> children() const; + + Relation relationTo(int child, const QAccessibleInterface *other, int otherChild) const; + int childAt(int x, int y) const; + int navigate(RelationFlag relation, int index, QAccessibleInterface **iface) const; + + int userActionCount(int child) const; + QString actionText(int action, Text t, int child) const; + bool doAction(int action, int child, const QVariantList ¶ms = QVariantList()); + + QModelIndex childIndex(int child) const; + + QHeaderView *horizontalHeader() const; //used by QAccessibleItemView +private: + static QAbstractItemView::CursorAction toCursorAction(Relation rel); + int logicalFromChild(QHeaderView *header, int child) const; + int treeLevel() const; + QHeaderView *verticalHeader() const; + QString text_helper(int child) const; + + QPersistentModelIndex row; + QPointer<QAbstractItemView> view; + bool m_header; +}; + +class QAccessibleItemView: public QAccessibleAbstractScrollArea, public QAccessibleTableInterface +{ + Q_ACCESSIBLE_OBJECT +public: + explicit QAccessibleItemView(QWidget *w); + + QObject *object() const; + Role role(int child) const; + State state(int child) const; + QRect rect(int child) const; + int childAt(int x, int y) const; + int childCount() const; + QString text(Text t, int child) const; + void setText(Text t, int child, const QString &text); + int indexOfChild(const QAccessibleInterface *iface) const; + + QModelIndex childIndex(int child) const; + int entryFromIndex(const QModelIndex &index) const; + bool isValid() const; + int navigate(RelationFlag relation, int index, QAccessibleInterface **iface) const; + + QAccessibleInterface *accessibleAt(int row, int column); + QAccessibleInterface *caption(); + int childIndex(int rowIndex, int columnIndex); + QString columnDescription(int column); + int columnSpan(int row, int column); + QAccessibleInterface *columnHeader(); + int columnIndex(int childIndex); + int columnCount(); + int rowCount(); + int selectedColumnCount(); + int selectedRowCount(); + QString rowDescription(int row); + int rowSpan(int row, int column); + QAccessibleInterface *rowHeader(); + int rowIndex(int childIndex); + int selectedRows(int maxRows, QList<int> *rows); + int selectedColumns(int maxColumns, QList<int> *columns); + QAccessibleInterface *summary(); + bool isColumnSelected(int column); + bool isRowSelected(int row); + bool isSelected(int row, int column); + void selectRow(int row); + void selectColumn(int column); + void unselectRow(int row); + void unselectColumn(int column); + void cellAtIndex(int index, int *row, int *column, int *rowSpan, + int *columnSpan, bool *isSelected); + + QHeaderView *horizontalHeader() const; + QHeaderView *verticalHeader() const; + bool isValidChildRole(QAccessible::Role role) const; + +protected: + QAbstractItemView *itemView() const; + QModelIndex index(int row, int column) const; + +private: + inline bool atViewport() const { + return atVP; + }; + QAccessible::Role expectedRoleOfChildren() const; + + bool atVP; +}; + +#endif + +#ifndef QT_NO_TABBAR +class QAccessibleTabBar : public QAccessibleWidgetEx +{ + Q_ACCESSIBLE_OBJECT +public: + explicit QAccessibleTabBar(QWidget *w); + + int childCount() const; + + QRect rect(int child) const; + QString text(Text t, int child) const; + Role role(int child) const; + State state(int child) const; + + bool doAction(int action, int child, const QVariantList ¶ms); + bool setSelected(int child, bool on, bool extend); + QVector<int> selection() const; + +protected: + QTabBar *tabBar() const; + +private: + QAbstractButton *button(int child) const; +}; +#endif // QT_NO_TABBAR + +#ifndef QT_NO_COMBOBOX +class QAccessibleComboBox : public QAccessibleWidgetEx +{ + Q_ACCESSIBLE_OBJECT +public: + explicit QAccessibleComboBox(QWidget *w); + + enum ComboBoxElements { + ComboBoxSelf = 0, + CurrentText, + OpenList, + PopupList + }; + + int childCount() const; + int childAt(int x, int y) const; + int indexOfChild(const QAccessibleInterface *child) const; + int navigate(RelationFlag rel, int entry, QAccessibleInterface **target) const; + + QString text(Text t, int child) const; + QRect rect(int child) const; + Role role(int child) const; + State state(int child) const; + + bool doAction(int action, int child, const QVariantList ¶ms); + QString actionText(int action, Text t, int child) const; + +protected: + QComboBox *comboBox() const; +}; +#endif // QT_NO_COMBOBOX + +#endif // QT_NO_ACCESSIBILITY + +QT_END_NAMESPACE + +#endif // COMPLEXWIDGETS_H diff --git a/src/plugins/accessible/widgets/main.cpp b/src/plugins/accessible/widgets/main.cpp new file mode 100644 index 0000000..9c0806e --- /dev/null +++ b/src/plugins/accessible/widgets/main.cpp @@ -0,0 +1,339 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaccessiblewidgets.h" +#include "qaccessiblemenu.h" +#include "simplewidgets.h" +#include "rangecontrols.h" +#include "complexwidgets.h" + +#include <qaccessibleplugin.h> +#include <qplugin.h> +#include <qpushbutton.h> +#include <qtoolbutton.h> +#include <qvariant.h> +#include <qaccessible.h> + +#ifndef QT_NO_ACCESSIBILITY + +QT_BEGIN_NAMESPACE + +class AccessibleFactory : public QAccessiblePlugin +{ +public: + AccessibleFactory(); + + QStringList keys() const; + QAccessibleInterface *create(const QString &classname, QObject *object); +}; + +AccessibleFactory::AccessibleFactory() +{ +} + +QStringList AccessibleFactory::keys() const +{ + QStringList list; +#ifndef QT_NO_LINEEDIT + list << QLatin1String("QLineEdit"); +#endif +#ifndef QT_NO_COMBOBOX + list << QLatin1String("QComboBox"); +#endif +#ifndef QT_NO_SPINBOX + list << QLatin1String("QAbstractSpinBox"); + list << QLatin1String("QSpinBox"); + list << QLatin1String("QDoubleSpinBox"); +#endif +#ifndef QT_NO_SCROLLBAR + list << QLatin1String("QScrollBar"); +#endif +#ifndef QT_NO_SLIDER + list << QLatin1String("QSlider"); +#endif + list << QLatin1String("QAbstractSlider"); +#ifndef QT_NO_TOOLBUTTON + list << QLatin1String("QToolButton"); +#endif + list << QLatin1String("QCheckBox"); + list << QLatin1String("QRadioButton"); + list << QLatin1String("QPushButton"); + list << QLatin1String("QAbstractButton"); + list << QLatin1String("QDialog"); + list << QLatin1String("QMessageBox"); + list << QLatin1String("QMainWindow"); + list << QLatin1String("QLabel"); + list << QLatin1String("QLCDNumber"); + list << QLatin1String("QGroupBox"); + list << QLatin1String("QStatusBar"); + list << QLatin1String("QProgressBar"); + list << QLatin1String("QMenuBar"); + list << QLatin1String("Q3PopupMenu"); + list << QLatin1String("QMenu"); + list << QLatin1String("QHeaderView"); + list << QLatin1String("QTabBar"); + list << QLatin1String("QToolBar"); + list << QLatin1String("QWorkspaceChild"); + list << QLatin1String("QSizeGrip"); + list << QLatin1String("QAbstractItemView"); + list << QLatin1String("QWidget"); +#ifndef QT_NO_SPLITTER + list << QLatin1String("QSplitter"); + list << QLatin1String("QSplitterHandle"); +#endif +#ifndef QT_NO_TEXTEDIT + list << QLatin1String("QTextEdit"); +#endif + list << QLatin1String("QTipLabel"); + list << QLatin1String("QFrame"); + list << QLatin1String("QStackedWidget"); + list << QLatin1String("QToolBox"); + list << QLatin1String("QMdiArea"); + list << QLatin1String("QMdiSubWindow"); + list << QLatin1String("QWorkspace"); + list << QLatin1String("QDialogButtonBox"); +#ifndef QT_NO_DIAL + list << QLatin1String("QDial"); +#endif +#ifndef QT_NO_RUBBERBAND + list << QLatin1String("QRubberBand"); +#endif +#ifndef QT_NO_TEXTBROWSER + list << QLatin1String("QTextBrowser"); +#endif +#ifndef QT_NO_SCROLLAREA + list << QLatin1String("QAbstractScrollArea"); + list << QLatin1String("QScrollArea"); +#endif +#ifndef QT_NO_CALENDARWIDGET + list << QLatin1String("QCalendarWidget"); +#endif + +#ifndef QT_NO_DOCKWIDGET + list << QLatin1String("QDockWidget"); +#endif + return list; +} + +QAccessibleInterface *AccessibleFactory::create(const QString &classname, QObject *object) +{ + QAccessibleInterface *iface = 0; + if (!object || !object->isWidgetType()) + return iface; + QWidget *widget = static_cast<QWidget*>(object); + + if (false) { +#ifndef QT_NO_LINEEDIT + } else if (classname == QLatin1String("QLineEdit")) { + iface = new QAccessibleLineEdit(widget); +#endif +#ifndef QT_NO_COMBOBOX + } else if (classname == QLatin1String("QComboBox")) { + iface = new QAccessibleComboBox(widget); +#endif +#ifndef QT_NO_SPINBOX + } else if (classname == QLatin1String("QAbstractSpinBox")) { + iface = new QAccessibleAbstractSpinBox(widget); + } else if (classname == QLatin1String("QSpinBox")) { + iface = new QAccessibleSpinBox(widget); + } else if (classname == QLatin1String("QDoubleSpinBox")) { + iface = new QAccessibleDoubleSpinBox(widget); +#endif +#ifndef QT_NO_SCROLLBAR + } else if (classname == QLatin1String("QScrollBar")) { + iface = new QAccessibleScrollBar(widget); +#endif + } else if (classname == QLatin1String("QAbstractSlider")) { + iface = new QAccessibleAbstractSlider(widget); +#ifndef QT_NO_SLIDER + } else if (classname == QLatin1String("QSlider")) { + iface = new QAccessibleSlider(widget); +#endif +#ifndef QT_NO_TOOLBUTTON + } else if (classname == QLatin1String("QToolButton")) { + Role role = NoRole; +#ifndef QT_NO_MENU + QToolButton *tb = qobject_cast<QToolButton*>(widget); + if (!tb->menu()) + role = tb->isCheckable() ? CheckBox : PushButton; + else if (!tb->popupMode() != QToolButton::DelayedPopup) + role = ButtonDropDown; + else +#endif + role = ButtonMenu; + iface = new QAccessibleToolButton(widget, role); +#endif // QT_NO_TOOLBUTTON + } else if (classname == QLatin1String("QCheckBox")) { + iface = new QAccessibleButton(widget, CheckBox); + } else if (classname == QLatin1String("QRadioButton")) { + iface = new QAccessibleButton(widget, RadioButton); + } else if (classname == QLatin1String("QPushButton")) { + Role role = NoRole; + QPushButton *pb = qobject_cast<QPushButton*>(widget); +#ifndef QT_NO_MENU + if (pb->menu()) + role = ButtonMenu; + else +#endif + if (pb->isCheckable()) + role = CheckBox; + else + role = PushButton; + iface = new QAccessibleButton(widget, role); + } else if (classname == QLatin1String("QAbstractButton")) { + iface = new QAccessibleButton(widget, PushButton); + } else if (classname == QLatin1String("QDialog")) { + iface = new QAccessibleWidgetEx(widget, Dialog); + } else if (classname == QLatin1String("QMessageBox")) { + iface = new QAccessibleWidgetEx(widget, AlertMessage); +#ifndef QT_NO_MAINWINDOW + } else if (classname == QLatin1String("QMainWindow")) { + iface = new QAccessibleMainWindow(widget); +#endif + } else if (classname == QLatin1String("QLabel") || classname == QLatin1String("QLCDNumber")) { + iface = new QAccessibleDisplay(widget); + } else if (classname == QLatin1String("QGroupBox")) { + iface = new QAccessibleDisplay(widget, Grouping); + } else if (classname == QLatin1String("QStatusBar")) { + iface = new QAccessibleWidgetEx(widget, StatusBar); + } else if (classname == QLatin1String("QProgressBar")) { + iface = new QAccessibleDisplay(widget); + } else if (classname == QLatin1String("QToolBar")) { + iface = new QAccessibleWidgetEx(widget, ToolBar, widget->windowTitle()); +#ifndef QT_NO_MENUBAR + } else if (classname == QLatin1String("QMenuBar")) { + iface = new QAccessibleMenuBar(widget); +#endif +#ifndef QT_NO_MENU + } else if (classname == QLatin1String("QMenu")) { + iface = new QAccessibleMenu(widget); + } else if (classname == QLatin1String("Q3PopupMenu")) { + iface = new QAccessibleMenu(widget); +#endif +#ifndef QT_NO_ITEMVIEWS + } else if (classname == QLatin1String("QHeaderView")) { + iface = new QAccessibleHeader(widget); + } else if (classname == QLatin1String("QAbstractItemView")) { + iface = new QAccessibleItemView(widget); + } else if (classname == QLatin1String("QWidget") + && widget->objectName() == QLatin1String("qt_scrollarea_viewport") + && qobject_cast<QAbstractItemView*>(widget->parentWidget())) { + iface = new QAccessibleItemView(widget); +#endif +#ifndef QT_NO_TABBAR + } else if (classname == QLatin1String("QTabBar")) { + iface = new QAccessibleTabBar(widget); +#endif + } else if (classname == QLatin1String("QWorkspaceChild")) { + iface = new QAccessibleWidgetEx(widget, Window); + } else if (classname == QLatin1String("QSizeGrip")) { + iface = new QAccessibleWidgetEx(widget, Grip); +#ifndef QT_NO_SPLITTER + } else if (classname == QLatin1String("QSplitter")) { + iface = new QAccessibleWidgetEx(widget, Splitter); + } else if (classname == QLatin1String("QSplitterHandle")) { + iface = new QAccessibleWidgetEx(widget, Grip); +#endif +#ifndef QT_NO_TEXTEDIT + } else if (classname == QLatin1String("QTextEdit")) { + iface = new QAccessibleTextEdit(widget); +#endif + } else if (classname == QLatin1String("QTipLabel")) { + iface = new QAccessibleDisplay(widget, ToolTip); + } else if (classname == QLatin1String("QFrame")) { + iface = new QAccessibleWidget(widget, Border); +#ifndef QT_NO_STACKEDWIDGET + } else if (classname == QLatin1String("QStackedWidget")) { + iface = new QAccessibleStackedWidget(widget); +#endif +#ifndef QT_NO_TOOLBOX + } else if (classname == QLatin1String("QToolBox")) { + iface = new QAccessibleToolBox(widget); +#endif +#ifndef QT_NO_MDIAREA + } else if (classname == QLatin1String("QMdiArea")) { + iface = new QAccessibleMdiArea(widget); + } else if (classname == QLatin1String("QMdiSubWindow")) { + iface = new QAccessibleMdiSubWindow(widget); +#endif +#ifndef QT_NO_WORKSPACE + } else if (classname == QLatin1String("QWorkspace")) { + iface = new QAccessibleWorkspace(widget); +#endif + } else if (classname == QLatin1String("QDialogButtonBox")) { + iface = new QAccessibleDialogButtonBox(widget); +#ifndef QT_NO_DIAL + } else if (classname == QLatin1String("QDial")) { + iface = new QAccessibleDial(widget); +#endif +#ifndef QT_NO_RUBBERBAND + } else if (classname == QLatin1String("QRubberBand")) { + iface = new QAccessibleWidgetEx(widget, QAccessible::Border); +#endif +#ifndef QT_NO_TEXTBROWSER + } else if (classname == QLatin1String("QTextBrowser")) { + iface = new QAccessibleTextBrowser(widget); +#endif +#ifndef QT_NO_SCROLLAREA + } else if (classname == QLatin1String("QAbstractScrollArea")) { + iface = new QAccessibleAbstractScrollArea(widget); + } else if (classname == QLatin1String("QScrollArea")) { + iface = new QAccessibleScrollArea(widget); +#endif +#ifndef QT_NO_CALENDARWIDGET + } else if (classname == QLatin1String("QCalendarWidget")) { + iface = new QAccessibleCalendarWidget(widget); +#endif +#ifndef QT_NO_DOCKWIDGET + } else if (classname == QLatin1String("QDockWidget")) { + iface = new QAccessibleDockWidget(widget); +#endif + } + + return iface; +} + +Q_EXPORT_STATIC_PLUGIN(AccessibleFactory) +Q_EXPORT_PLUGIN2(qtaccessiblewidgets, AccessibleFactory) + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/widgets/qaccessiblemenu.cpp b/src/plugins/accessible/widgets/qaccessiblemenu.cpp new file mode 100644 index 0000000..f9be483 --- /dev/null +++ b/src/plugins/accessible/widgets/qaccessiblemenu.cpp @@ -0,0 +1,678 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 + diff --git a/src/plugins/accessible/widgets/qaccessiblemenu.h b/src/plugins/accessible/widgets/qaccessiblemenu.h new file mode 100644 index 0000000..748e6a3 --- /dev/null +++ b/src/plugins/accessible/widgets/qaccessiblemenu.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QACCESSIBLEMENU_H +#define QACCESSIBLEMENU_H + +#include <QtGui/qaccessiblewidget.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_ACCESSIBILITY + +#ifndef QT_NO_MENU +class QMenu; +class QMenuBar; +class QAction; + +class QAccessibleMenu : public QAccessibleWidgetEx +{ +public: + explicit QAccessibleMenu(QWidget *w); + + int childCount() const; + int childAt(int x, int y) const; + + QRect rect(int child) const; + QString text(Text t, int child) const; + Role role(int child) const; + State state(int child) const; + int navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const; + int indexOfChild( const QAccessibleInterface *child ) const; + + QString actionText(int action, QAccessible::Text text, int child) const; + bool doAction(int action, int child, const QVariantList ¶ms); + +protected: + QMenu *menu() const; +}; + +#ifndef QT_NO_MENUBAR +class QAccessibleMenuBar : public QAccessibleWidgetEx +{ +public: + explicit QAccessibleMenuBar(QWidget *w); + + int childCount() const; + int childAt(int x, int y) const; + + QRect rect(int child) const; + QString text(Text t, int child) const; + Role role(int child) const; + State state(int child) const; + int navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const; + int indexOfChild( const QAccessibleInterface *child ) const; + + QString actionText(int action, QAccessible::Text text, int child) const; + bool doAction(int action, int child, const QVariantList ¶ms); + +protected: + QMenuBar *menuBar() const; +}; +#endif // QT_NO_MENUBAR + + + +class QAccessibleMenuItem : public QAccessibleInterface +{ +public: + explicit QAccessibleMenuItem(QWidget *owner, QAction *w); + + virtual ~QAccessibleMenuItem(); + virtual QString actionText ( int action, Text t, int child ) const; + virtual int childAt ( int x, int y ) const; + virtual int childCount () const; + virtual bool doAction ( int action, int child, const QVariantList & params = QVariantList() ); + virtual int indexOfChild ( const QAccessibleInterface * child ) const; + virtual bool isValid () const; + virtual int navigate ( RelationFlag relation, int entry, QAccessibleInterface ** target ) const; + virtual QObject * object () const; + virtual QRect rect ( int child ) const; + virtual Relation relationTo ( int child, const QAccessibleInterface * other, int otherChild ) const; + virtual Role role ( int child ) const; + virtual void setText ( Text t, int child, const QString & text ); + virtual State state ( int child ) const; + virtual QString text ( Text t, int child ) const; + virtual int userActionCount ( int child ) const; + + QWidget *owner() const; + + +protected: + QAction *action() const; +private: + QAction *m_action; + QWidget *m_owner; // can hold either QMenu or the QMenuBar that contains the action +}; + +#endif // QT_NO_MENU + +QT_END_NAMESPACE +#endif // QT_NO_ACCESSIBILITY +#endif // QACCESSIBLEMENU_H diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp new file mode 100644 index 0000000..b2b3f9e --- /dev/null +++ b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp @@ -0,0 +1,1667 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaccessiblewidgets.h" +#include "qabstracttextdocumentlayout.h" +#include "qapplication.h" +#include "qclipboard.h" +#include "qtextedit.h" +#include "private/qtextedit_p.h" +#include "qtextdocument.h" +#include "qtextobject.h" +#include "qscrollbar.h" +#include "qdebug.h" +#include <QApplication> +#include <QStackedWidget> +#include <QToolBox> +#include <QMdiArea> +#include <QMdiSubWindow> +#include <QWorkspace> +#include <QDialogButtonBox> +#include <limits.h> +#include <QRubberBand> +#include <QTextBrowser> +#include <QCalendarWidget> +#include <QAbstractItemView> +#include <QDockWidget> +#include <QMainWindow> +#include <QAbstractButton> +#include <private/qdockwidget_p.h> +#include <QtGui/QFocusFrame> + +#ifndef QT_NO_ACCESSIBILITY + +QT_BEGIN_NAMESPACE + +using namespace QAccessible2; + +QList<QWidget*> childWidgets(const QWidget *widget, bool includeTopLevel) +{ + if (widget == 0) + return QList<QWidget*>(); + QList<QObject*> list = widget->children(); + QList<QWidget*> widgets; + for (int i = 0; i < list.size(); ++i) { + QWidget *w = qobject_cast<QWidget *>(list.at(i)); + if (!w) + continue; + QString objectName = w->objectName(); + if ((includeTopLevel || !w->isWindow()) + && !qobject_cast<QFocusFrame*>(w) + && !qobject_cast<QMenu*>(w) + && objectName != QLatin1String("qt_rubberband") + && objectName != QLatin1String("qt_qmainwindow_extended_splitter")) { + widgets.append(w); + } + } + return widgets; +} + +static inline int distance(QWidget *source, QWidget *target, + QAccessible::RelationFlag relation) +{ + if (!source || !target) + return -1; + + int returnValue = -1; + switch (relation) { + case QAccessible::Up: + if (target->y() <= source->y()) + returnValue = source->y() - target->y(); + break; + case QAccessible::Down: + if (target->y() >= source->y() + source->height()) + returnValue = target->y() - (source->y() + source->height()); + break; + case QAccessible::Right: + if (target->x() >= source->x() + source->width()) + returnValue = target->x() - (source->x() + source->width()); + break; + case QAccessible::Left: + if (target->x() <= source->x()) + returnValue = source->x() - target->x(); + break; + default: + break; + } + return returnValue; +} + +static inline QWidget *mdiAreaNavigate(QWidget *area, + QAccessible::RelationFlag relation, int entry) +{ +#if defined(QT_NO_MDIAREA) && defined(QT_NO_WORKSPACE) + Q_UNUSED(area); +#endif +#ifndef QT_NO_MDIAREA + const QMdiArea *mdiArea = qobject_cast<QMdiArea *>(area); +#endif +#ifndef QT_NO_WORKSPACE + const QWorkspace *workspace = qobject_cast<QWorkspace *>(area); +#endif + if (true +#ifndef QT_NO_MDIAREA + && !mdiArea +#endif +#ifndef QT_NO_WORKSPACE + && !workspace +#endif + ) + return 0; + + QWidgetList windows; +#ifndef QT_NO_MDIAREA + if (mdiArea) { + foreach (QMdiSubWindow *window, mdiArea->subWindowList()) + windows.append(window); + } else +#endif + { +#ifndef QT_NO_WORKSPACE + foreach (QWidget *window, workspace->windowList()) + windows.append(window->parentWidget()); +#endif + } + + if (windows.isEmpty() || entry < 1 || entry > windows.count()) + return 0; + + QWidget *source = windows.at(entry - 1); + QMap<int, QWidget *> candidates; + foreach (QWidget *window, windows) { + if (source == window) + continue; + int candidateDistance = distance(source, window, relation); + if (candidateDistance >= 0) + candidates.insert(candidateDistance, window); + } + + int minimumDistance = INT_MAX; + QWidget *target = 0; + foreach (QWidget *candidate, candidates.values()) { + switch (relation) { + case QAccessible::Up: + case QAccessible::Down: + if (qAbs(candidate->x() - source->x()) < minimumDistance) { + target = candidate; + minimumDistance = qAbs(candidate->x() - source->x()); + } + break; + case QAccessible::Left: + case QAccessible::Right: + if (qAbs(candidate->y() - source->y()) < minimumDistance) { + target = candidate; + minimumDistance = qAbs(candidate->y() - source->y()); + } + break; + default: + break; + } + if (minimumDistance == 0) + break; + } + +#ifndef QT_NO_WORKSPACE + if (workspace) { + foreach (QWidget *widget, workspace->windowList()) { + if (widget->parentWidget() == target) + target = widget; + } + } +#endif + return target; +} + +#ifndef QT_NO_TEXTEDIT + +/*! + \class QAccessibleTextEdit + \brief The QAccessibleTextEdit class implements the QAccessibleInterface for richtext editors. + \internal +*/ + +static QTextBlock qTextBlockAt(const QTextDocument *doc, int pos) +{ + Q_ASSERT(pos >= 0); + + QTextBlock block = doc->begin(); + int i = 0; + while (block.isValid() && i < pos) { + block = block.next(); + ++i; + } + return block; +} + +static int qTextBlockPosition(QTextBlock block) +{ + int child = 0; + while (block.isValid()) { + block = block.previous(); + ++child; + } + + return child; +} + +/*! + \fn QAccessibleTextEdit::QAccessibleTextEdit(QWidget* widget) + + Constructs a QAccessibleTextEdit object for a \a widget. +*/ +QAccessibleTextEdit::QAccessibleTextEdit(QWidget *o) +: QAccessibleWidgetEx(o, EditableText) +{ + Q_ASSERT(widget()->inherits("QTextEdit")); + childOffset = QAccessibleWidgetEx::childCount(); +} + +/*! Returns the text edit. */ +QTextEdit *QAccessibleTextEdit::textEdit() const +{ + return static_cast<QTextEdit *>(widget()); +} + +QRect QAccessibleTextEdit::rect(int child) const +{ + if (child <= childOffset) + return QAccessibleWidgetEx::rect(child); + + QTextEdit *edit = textEdit(); + QTextBlock block = qTextBlockAt(edit->document(), child - childOffset - 1); + if (!block.isValid()) + return QRect(); + + QRect rect = edit->document()->documentLayout()->blockBoundingRect(block).toRect(); + rect.translate(-edit->horizontalScrollBar()->value(), -edit->verticalScrollBar()->value()); + + rect = edit->viewport()->rect().intersect(rect); + if (rect.isEmpty()) + return QRect(); + + return rect.translated(edit->viewport()->mapToGlobal(QPoint(0, 0))); +} + +int QAccessibleTextEdit::childAt(int x, int y) const +{ + QTextEdit *edit = textEdit(); + if (!edit->isVisible()) + return -1; + + QPoint point = edit->viewport()->mapFromGlobal(QPoint(x, y)); + QTextBlock block = edit->cursorForPosition(point).block(); + if (block.isValid()) + return qTextBlockPosition(block) + childOffset; + + return QAccessibleWidgetEx::childAt(x, y); +} + +/*! \reimp */ +QString QAccessibleTextEdit::text(Text t, int child) const +{ + if (t == Value) { + if (child > childOffset) + return qTextBlockAt(textEdit()->document(), child - childOffset - 1).text(); + if (!child) + return textEdit()->toPlainText(); + } + + return QAccessibleWidgetEx::text(t, child); +} + +/*! \reimp */ +void QAccessibleTextEdit::setText(Text t, int child, const QString &text) +{ + if (t != Value || (child > 0 && child <= childOffset)) { + QAccessibleWidgetEx::setText(t, child, text); + return; + } + if (textEdit()->isReadOnly()) + return; + + if (!child) { + textEdit()->setText(text); + return; + } + QTextBlock block = qTextBlockAt(textEdit()->document(), child - childOffset - 1); + if (!block.isValid()) + return; + + QTextCursor cursor(block); + cursor.select(QTextCursor::BlockUnderCursor); + cursor.insertText(text); +} + +/*! \reimp */ +QAccessible::Role QAccessibleTextEdit::role(int child) const +{ + if (child > childOffset) + return EditableText; + return QAccessibleWidgetEx::role(child); +} + +QVariant QAccessibleTextEdit::invokeMethodEx(QAccessible::Method method, int child, + const QVariantList ¶ms) +{ + if (child) + return QVariant(); + + switch (method) { + case ListSupportedMethods: { + QSet<QAccessible::Method> set; + set << ListSupportedMethods << SetCursorPosition << GetCursorPosition; + return qVariantFromValue(set | qvariant_cast<QSet<QAccessible::Method> >( + QAccessibleWidgetEx::invokeMethodEx(method, child, params))); + } + case SetCursorPosition: + setCursorPosition(params.value(0).toInt()); + return true; + case GetCursorPosition: + return textEdit()->textCursor().position(); + default: + return QAccessibleWidgetEx::invokeMethodEx(method, child, params); + } +} + +int QAccessibleTextEdit::childCount() const +{ + return childOffset + textEdit()->document()->blockCount(); +} +#endif // QT_NO_TEXTEDIT + +#ifndef QT_NO_STACKEDWIDGET +// ======================= QAccessibleStackedWidget ====================== +QAccessibleStackedWidget::QAccessibleStackedWidget(QWidget *widget) + : QAccessibleWidgetEx(widget, LayeredPane) +{ + Q_ASSERT(qobject_cast<QStackedWidget *>(widget)); +} + +QVariant QAccessibleStackedWidget::invokeMethodEx(QAccessible::Method, int, const QVariantList &) +{ + return QVariant(); +} + + +int QAccessibleStackedWidget::childAt(int x, int y) const +{ + if (!stackedWidget()->isVisible()) + return -1; + QWidget *currentWidget = stackedWidget()->currentWidget(); + if (!currentWidget) + return -1; + QPoint position = currentWidget->mapFromGlobal(QPoint(x, y)); + if (currentWidget->rect().contains(position)) + return 1; + return -1; +} + +int QAccessibleStackedWidget::childCount() const +{ + return stackedWidget()->count(); +} + +int QAccessibleStackedWidget::indexOfChild(const QAccessibleInterface *child) const +{ + if (!child || (stackedWidget()->currentWidget() != child->object())) + return -1; + return 1; +} + +int QAccessibleStackedWidget::navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const +{ + *target = 0; + + QObject *targetObject = 0; + switch (relation) { + case Child: + if (entry != 1) + return -1; + targetObject = stackedWidget()->currentWidget(); + break; + default: + return QAccessibleWidgetEx::navigate(relation, entry, target); + } + *target = QAccessible::queryAccessibleInterface(targetObject); + return *target ? 0 : -1; +} + +QStackedWidget *QAccessibleStackedWidget::stackedWidget() const +{ + return static_cast<QStackedWidget *>(object()); +} +#endif // QT_NO_STACKEDWIDGET + +#ifndef QT_NO_TOOLBOX +// ======================= QAccessibleToolBox ====================== +QAccessibleToolBox::QAccessibleToolBox(QWidget *widget) + : QAccessibleWidgetEx(widget, LayeredPane) +{ + Q_ASSERT(qobject_cast<QToolBox *>(widget)); +} + +QString QAccessibleToolBox::text(Text textType, int child) const +{ + if (textType != Value || child <= 0 || child > toolBox()->count()) + return QAccessibleWidgetEx::text(textType, child); + return toolBox()->itemText(child - 1); +} + +void QAccessibleToolBox::setText(Text textType, int child, const QString &text) +{ + if (textType != Value || child <= 0 || child > toolBox()->count()) { + QAccessibleWidgetEx::setText(textType, child, text); + return; + } + toolBox()->setItemText(child - 1, text); +} + +QAccessible::State QAccessibleToolBox::state(int child) const +{ + QWidget *childWidget = toolBox()->widget(child - 1); + if (!childWidget) + return QAccessibleWidgetEx::state(child); + QAccessible::State childState = QAccessible::Normal; + if (toolBox()->currentWidget() == childWidget) + childState |= QAccessible::Expanded; + else + childState |= QAccessible::Collapsed; + return childState; +} + +QVariant QAccessibleToolBox::invokeMethodEx(QAccessible::Method, int, const QVariantList &) +{ + return QVariant(); +} + +int QAccessibleToolBox::childCount() const +{ + return toolBox()->count(); +} + +int QAccessibleToolBox::indexOfChild(const QAccessibleInterface *child) const +{ + if (!child) + return -1; + QWidget *childWidget = qobject_cast<QWidget *>(child->object()); + if (!childWidget) + return -1; + int index = toolBox()->indexOf(childWidget); + if (index != -1) + ++index; + return index; +} + +int QAccessibleToolBox::navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const +{ + *target = 0; + if (entry <= 0 || entry > toolBox()->count()) + return QAccessibleWidgetEx::navigate(relation, entry, target); + int index = -1; + if (relation == QAccessible::Up) + index = entry - 2; + else if (relation == QAccessible::Down) + index = entry; + *target = QAccessible::queryAccessibleInterface(toolBox()->widget(index)); + return *target ? 0: -1; +} + +QToolBox * QAccessibleToolBox::toolBox() const +{ + return static_cast<QToolBox *>(object()); +} +#endif // QT_NO_TOOLBOX + +// ======================= QAccessibleMdiArea ====================== +#ifndef QT_NO_MDIAREA +QAccessibleMdiArea::QAccessibleMdiArea(QWidget *widget) + : QAccessibleWidgetEx(widget, LayeredPane) +{ + Q_ASSERT(qobject_cast<QMdiArea *>(widget)); +} + +QAccessible::State QAccessibleMdiArea::state(int child) const +{ + if (child < 0) + return QAccessibleWidgetEx::state(child); + if (child == 0) + return QAccessible::Normal; + QList<QMdiSubWindow *> subWindows = mdiArea()->subWindowList(); + if (subWindows.isEmpty() || child > subWindows.count()) + return QAccessibleWidgetEx::state(child); + if (subWindows.at(child - 1) == mdiArea()->activeSubWindow()) + return QAccessible::Focused; + return QAccessible::Normal; +} + +QVariant QAccessibleMdiArea::invokeMethodEx(QAccessible::Method, int, const QVariantList &) +{ + return QVariant(); +} + +int QAccessibleMdiArea::childCount() const +{ + return mdiArea()->subWindowList().count(); +} + +int QAccessibleMdiArea::indexOfChild(const QAccessibleInterface *child) const +{ + if (!child || !child->object() || mdiArea()->subWindowList().isEmpty()) + return -1; + if (QMdiSubWindow *window = qobject_cast<QMdiSubWindow *>(child->object())) { + int index = mdiArea()->subWindowList().indexOf(window); + if (index != -1) + return ++index; + } + return -1; +} + +int QAccessibleMdiArea::navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const +{ + *target = 0; + QWidget *targetObject = 0; + QList<QMdiSubWindow *> subWindows = mdiArea()->subWindowList(); + switch (relation) { + case Child: + if (entry < 1 || subWindows.isEmpty() || entry > subWindows.count()) + return -1; + targetObject = subWindows.at(entry - 1); + break; + case Up: + case Down: + case Left: + case Right: + targetObject = mdiAreaNavigate(mdiArea(), relation, entry); + break; + default: + return QAccessibleWidgetEx::navigate(relation, entry, target); + } + *target = QAccessible::queryAccessibleInterface(targetObject); + return *target ? 0: -1; +} + +QMdiArea *QAccessibleMdiArea::mdiArea() const +{ + return static_cast<QMdiArea *>(object()); +} + +// ======================= QAccessibleMdiSubWindow ====================== +QAccessibleMdiSubWindow::QAccessibleMdiSubWindow(QWidget *widget) + : QAccessibleWidgetEx(widget, QAccessible::Window) +{ + Q_ASSERT(qobject_cast<QMdiSubWindow *>(widget)); +} + +QString QAccessibleMdiSubWindow::text(Text textType, int child) const +{ + if (textType == QAccessible::Name && (child == 0 || child == 1)) { + QString title = mdiSubWindow()->windowTitle(); + title.replace(QLatin1String("[*]"), QLatin1String("")); + return title; + } + return QAccessibleWidgetEx::text(textType, child); +} + +void QAccessibleMdiSubWindow::setText(Text textType, int child, const QString &text) +{ + if (textType == QAccessible::Name && (child == 0 || child == 1)) + mdiSubWindow()->setWindowTitle(text); + else + QAccessibleWidgetEx::setText(textType, child, text); +} + +QAccessible::State QAccessibleMdiSubWindow::state(int child) const +{ + if (child != 0 || !mdiSubWindow()->parent()) + return QAccessibleWidgetEx::state(child); + QAccessible::State state = QAccessible::Normal | QAccessible::Focusable; + if (!mdiSubWindow()->isMaximized()) + state |= (QAccessible::Movable | QAccessible::Sizeable); + if (mdiSubWindow()->isAncestorOf(QApplication::focusWidget()) + || QApplication::focusWidget() == mdiSubWindow()) + state |= QAccessible::Focused; + if (!mdiSubWindow()->isVisible()) + state |= QAccessible::Invisible; + if (!mdiSubWindow()->parentWidget()->contentsRect().contains(mdiSubWindow()->geometry())) + state |= QAccessible::Offscreen; + if (!mdiSubWindow()->isEnabled()) + state |= QAccessible::Unavailable; + return state; +} + +QVariant QAccessibleMdiSubWindow::invokeMethodEx(QAccessible::Method, int, const QVariantList &) +{ + return QVariant(); +} + +int QAccessibleMdiSubWindow::childCount() const +{ + if (mdiSubWindow()->widget()) + return 1; + return 0; +} + +int QAccessibleMdiSubWindow::indexOfChild(const QAccessibleInterface *child) const +{ + if (child && child->object() && child->object() == mdiSubWindow()->widget()) + return 1; + return -1; +} + +int QAccessibleMdiSubWindow::navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const +{ + *target = 0; + + if (!mdiSubWindow()->parent()) + return QAccessibleWidgetEx::navigate(relation, entry, target); + + QWidget *targetObject = 0; + QMdiSubWindow *source = mdiSubWindow(); + switch (relation) { + case Child: + if (entry != 1 || !source->widget()) + return -1; + targetObject = source->widget(); + break; + case Up: + case Down: + case Left: + case Right: { + if (entry != 0) + break; + QWidget *parent = source->parentWidget(); + while (parent && !parent->inherits("QMdiArea")) + parent = parent->parentWidget(); + QMdiArea *mdiArea = qobject_cast<QMdiArea *>(parent); + if (!mdiArea) + break; + int index = mdiArea->subWindowList().indexOf(source); + if (index == -1) + break; + if (QWidget *dest = mdiAreaNavigate(mdiArea, relation, index + 1)) { + *target = QAccessible::queryAccessibleInterface(dest); + return *target ? 0 : -1; + } + break; + } + default: + return QAccessibleWidgetEx::navigate(relation, entry, target); + } + *target = QAccessible::queryAccessibleInterface(targetObject); + return *target ? 0: -1; +} + +QRect QAccessibleMdiSubWindow::rect(int child) const +{ + if (mdiSubWindow()->isHidden()) + return QRect(); + if (!mdiSubWindow()->parent()) + return QAccessibleWidgetEx::rect(child); + const QPoint pos = mdiSubWindow()->mapToGlobal(QPoint(0, 0)); + if (child == 0) + return QRect(pos, mdiSubWindow()->size()); + if (child == 1 && mdiSubWindow()->widget()) { + if (mdiSubWindow()->widget()->isHidden()) + return QRect(); + const QRect contentsRect = mdiSubWindow()->contentsRect(); + return QRect(pos.x() + contentsRect.x(), pos.y() + contentsRect.y(), + contentsRect.width(), contentsRect.height()); + } + return QRect(); +} + +int QAccessibleMdiSubWindow::childAt(int x, int y) const +{ + if (!mdiSubWindow()->isVisible()) + return -1; + if (!mdiSubWindow()->parent()) + return QAccessibleWidgetEx::childAt(x, y); + const QRect globalGeometry = rect(0); + if (!globalGeometry.isValid()) + return -1; + const QRect globalChildGeometry = rect(1); + if (globalChildGeometry.isValid() && globalChildGeometry.contains(QPoint(x, y))) + return 1; + if (globalGeometry.contains(QPoint(x, y))) + return 0; + return -1; +} + +QMdiSubWindow *QAccessibleMdiSubWindow::mdiSubWindow() const +{ + return static_cast<QMdiSubWindow *>(object()); +} +#endif // QT_NO_MDIAREA + +// ======================= QAccessibleWorkspace ====================== +#ifndef QT_NO_WORKSPACE +QAccessibleWorkspace::QAccessibleWorkspace(QWidget *widget) + : QAccessibleWidgetEx(widget, LayeredPane) +{ + Q_ASSERT(qobject_cast<QWorkspace *>(widget)); +} + +QAccessible::State QAccessibleWorkspace::state(int child) const +{ + if (child < 0) + return QAccessibleWidgetEx::state(child); + if (child == 0) + return QAccessible::Normal; + QWidgetList subWindows = workspace()->windowList(); + if (subWindows.isEmpty() || child > subWindows.count()) + return QAccessibleWidgetEx::state(child); + if (subWindows.at(child - 1) == workspace()->activeWindow()) + return QAccessible::Focused; + return QAccessible::Normal; +} + +QVariant QAccessibleWorkspace::invokeMethodEx(QAccessible::Method, int, const QVariantList &) +{ + return QVariant(); +} + +int QAccessibleWorkspace::childCount() const +{ + return workspace()->windowList().count(); +} + +int QAccessibleWorkspace::indexOfChild(const QAccessibleInterface *child) const +{ + if (!child || !child->object() || workspace()->windowList().isEmpty()) + return -1; + if (QWidget *window = qobject_cast<QWidget *>(child->object())) { + int index = workspace()->windowList().indexOf(window); + if (index != -1) + return ++index; + } + return -1; +} + +int QAccessibleWorkspace::navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const +{ + *target = 0; + QWidget *targetObject = 0; + QWidgetList subWindows = workspace()->windowList(); + switch (relation) { + case Child: + if (entry < 1 || subWindows.isEmpty() || entry > subWindows.count()) + return -1; + targetObject = subWindows.at(entry - 1); + break; + case Up: + case Down: + case Left: + case Right: + targetObject = mdiAreaNavigate(workspace(), relation, entry); + break; + default: + return QAccessibleWidgetEx::navigate(relation, entry, target); + } + *target = QAccessible::queryAccessibleInterface(targetObject); + return *target ? 0: -1; +} + +QWorkspace *QAccessibleWorkspace::workspace() const +{ + return static_cast<QWorkspace *>(object()); +} +#endif + +#ifndef QT_NO_DIALOGBUTTONBOX +// ======================= QAccessibleDialogButtonBox ====================== +QAccessibleDialogButtonBox::QAccessibleDialogButtonBox(QWidget *widget) + : QAccessibleWidgetEx(widget, Grouping) +{ + Q_ASSERT(qobject_cast<QDialogButtonBox*>(widget)); +} + +QVariant QAccessibleDialogButtonBox::invokeMethodEx(QAccessible::Method, int, const QVariantList &) +{ + return QVariant(); +} +#endif // QT_NO_DIALOGBUTTONBOX + +#ifndef QT_NO_TEXTBROWSER +QAccessibleTextBrowser::QAccessibleTextBrowser(QWidget *widget) + : QAccessibleTextEdit(widget) +{ + Q_ASSERT(qobject_cast<QTextBrowser *>(widget)); +} + +QAccessible::Role QAccessibleTextBrowser::role(int child) const +{ + if (child != 0) + return QAccessibleTextEdit::role(child); + return QAccessible::StaticText; +} +#endif // QT_NO_TEXTBROWSER + +#ifndef QT_NO_CALENDARWIDGET +// ===================== QAccessibleCalendarWidget ======================== +QAccessibleCalendarWidget::QAccessibleCalendarWidget(QWidget *widget) + : QAccessibleWidgetEx(widget, Table) +{ + Q_ASSERT(qobject_cast<QCalendarWidget *>(widget)); +} + +QVariant QAccessibleCalendarWidget::invokeMethodEx(QAccessible::Method, int, const QVariantList &) +{ + return QVariant(); +} + +int QAccessibleCalendarWidget::childCount() const +{ + return calendarWidget()->isNavigationBarVisible() ? 2 : 1; +} + +int QAccessibleCalendarWidget::indexOfChild(const QAccessibleInterface *child) const +{ + if (!child || !child->object() || childCount() <= 0) + return -1; + if (qobject_cast<QAbstractItemView *>(child->object())) + return childCount(); + return 1; +} + +int QAccessibleCalendarWidget::navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const +{ + *target = 0; + if (entry <= 0 || entry > childCount()) + return QAccessibleWidgetEx::navigate(relation, entry, target); + QWidget *targetWidget = 0; + switch (relation) { + case Child: + if (childCount() == 1) { + targetWidget = calendarView(); + } else { + if (entry == 1) + targetWidget = navigationBar(); + else + targetWidget = calendarView(); + } + break; + case Up: + if (entry == 2) + targetWidget = navigationBar(); + break; + case Down: + if (entry == 1 && childCount() == 2) + targetWidget = calendarView(); + break; + default: + return QAccessibleWidgetEx::navigate(relation, entry, target); + } + *target = queryAccessibleInterface(targetWidget); + return *target ? 0: -1; +} + +QRect QAccessibleCalendarWidget::rect(int child) const +{ + if (!calendarWidget()->isVisible() || child > childCount()) + return QRect(); + if (child == 0) + return QAccessibleWidgetEx::rect(child); + QWidget *childWidget = 0; + if (childCount() == 2) + childWidget = child == 1 ? navigationBar() : calendarView(); + else + childWidget = calendarView(); + return QRect(childWidget->mapToGlobal(QPoint(0, 0)), childWidget->size()); +} + +int QAccessibleCalendarWidget::childAt(int x, int y) const +{ + const QPoint globalTargetPos = QPoint(x, y); + if (!rect(0).contains(globalTargetPos)) + return -1; + if (rect(1).contains(globalTargetPos)) + return 1; + if (rect(2).contains(globalTargetPos)) + return 2; + return 0; +} + +QCalendarWidget *QAccessibleCalendarWidget::calendarWidget() const +{ + return static_cast<QCalendarWidget *>(object()); +} + +QAbstractItemView *QAccessibleCalendarWidget::calendarView() const +{ + foreach (QObject *child, calendarWidget()->children()) { + if (child->objectName() == QLatin1String("qt_calendar_calendarview")) + return static_cast<QAbstractItemView *>(child); + } + return 0; +} + +QWidget *QAccessibleCalendarWidget::navigationBar() const +{ + foreach (QObject *child, calendarWidget()->children()) { + if (child->objectName() == QLatin1String("qt_calendar_navigationbar")) + return static_cast<QWidget *>(child); + } + return 0; +} +#endif // QT_NO_CALENDARWIDGET + +#ifndef QT_NO_DOCKWIDGET +QAccessibleDockWidget::QAccessibleDockWidget(QWidget *widget) + : QAccessibleWidgetEx(widget, Window) +{ + +} + +int QAccessibleDockWidget::navigate(RelationFlag relation, int entry, QAccessibleInterface **iface) const +{ + if (relation == Child) { + if (entry == 1) { + *iface = new QAccessibleTitleBar(dockWidget()); + return 0; + } else if (entry == 2) { + if (dockWidget()->widget()) + *iface = QAccessible::queryAccessibleInterface(dockWidget()->widget()); + return 0; + } + *iface = 0; + return -1; + } + return QAccessibleWidgetEx::navigate(relation, entry, iface); +} + +int QAccessibleDockWidget::childAt(int x, int y) const +{ + for (int i = childCount(); i >= 0; --i) { + if (rect(i).contains(x,y)) + return i; + } + return -1; +} + +int QAccessibleDockWidget::childCount() const +{ + return dockWidget()->widget() ? 2 : 1; +} + +int QAccessibleDockWidget::indexOfChild(const QAccessibleInterface *child) const +{ + if (child) { + if (qobject_cast<QDockWidget *>(child->object()) == dockWidget() && child->role(0) == TitleBar) { + return 1; + } else { + return 2; //### + } + } + return -1; +} + +QAccessible::Role QAccessibleDockWidget::role(int child) const +{ + switch (child) { + case 0: + return Window; + case 1: + return TitleBar; + case 2: + //### + break; + default: + break; + } + return NoRole; +} + +QAccessible::State QAccessibleDockWidget::state(int child) const +{ + //### mark tabified widgets as invisible + return QAccessibleWidgetEx::state(child); +} + +QRect QAccessibleDockWidget::rect (int child ) const +{ + QRect rect; + bool mapToGlobal = true; + if (child == 0) { + if (dockWidget()->isFloating()) { + rect = dockWidget()->frameGeometry(); + mapToGlobal = false; + } else { + rect = dockWidget()->rect(); + } + }else if (child == 1) { + QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(dockWidget()->layout()); + rect = layout->titleArea(); + }else if (child == 2) { + if (dockWidget()->widget()) + rect = dockWidget()->widget()->geometry(); + } + if (rect.isNull()) + return rect; + + if (mapToGlobal) + rect.moveTopLeft(dockWidget()->mapToGlobal(rect.topLeft())); + + return rect; +} + +QVariant QAccessibleDockWidget::invokeMethodEx(QAccessible::Method, int, const QVariantList &) +{ + return QVariant(); +} + +QDockWidget *QAccessibleDockWidget::dockWidget() const +{ + return static_cast<QDockWidget *>(object()); +} + +//// +// QAccessibleTitleBar +//// +QAccessibleTitleBar::QAccessibleTitleBar(QDockWidget *widget) + : m_dockWidget(widget) +{ + +} + +int QAccessibleTitleBar::navigate(RelationFlag relation, int entry, QAccessibleInterface **iface) const +{ + if (entry == 0 || relation == Self) { + *iface = new QAccessibleTitleBar(dockWidget()); + return 0; + } + switch (relation) { + case Child: + case FocusChild: + if (entry >= 1) { + QDockWidgetLayout *layout = dockWidgetLayout(); + int index = 1; + int role; + for (role = QDockWidgetLayout::CloseButton; role <= QDockWidgetLayout::FloatButton; ++role) { + QWidget *w = layout->widgetForRole((QDockWidgetLayout::Role)role); + if (!w->isVisible()) + continue; + if (index == entry) + break; + ++index; + } + *iface = 0; + return role > QDockWidgetLayout::FloatButton ? -1 : index; + } + break; + case Ancestor: + { + QAccessibleDockWidget *target = new QAccessibleDockWidget(dockWidget()); + int index; + if (entry == 1) { + *iface = target; + return 0; + } + index = target->navigate(Ancestor, entry - 1, iface); + delete target; + return index; + + break;} + case Sibling: + return navigate(Child, entry, iface); + break; + default: + break; + } + *iface = 0; + return -1; +} + +QAccessible::Relation QAccessibleTitleBar::relationTo(int /*child*/, const QAccessibleInterface * /*other*/, int /*otherChild*/) const +{ + return Unrelated; //### +} + +int QAccessibleTitleBar::indexOfChild(const QAccessibleInterface * /*child*/) const +{ + return -1; +} + +int QAccessibleTitleBar::childCount() const +{ + QDockWidgetLayout *layout = dockWidgetLayout(); + int count = 0; + for (int role = QDockWidgetLayout::CloseButton; role <= QDockWidgetLayout::FloatButton; ++role) { + QWidget *w = layout->widgetForRole((QDockWidgetLayout::Role)role); + if (w && w->isVisible()) + ++count; + } + return count; +} + +QString QAccessibleTitleBar::text(Text t, int child) const +{ + if (!child) { + if (t == Value) { + return dockWidget()->windowTitle(); + } + } + return QString(); +} + +QAccessible::State QAccessibleTitleBar::state(int child) const +{ + QAccessible::State state = Normal; + if (child) { + QDockWidgetLayout *layout = dockWidgetLayout(); + QAbstractButton *b = static_cast<QAbstractButton *>(layout->widgetForRole((QDockWidgetLayout::Role)child)); + if (b) { + if (b->isDown()) + state |= Pressed; + } + } else { + QDockWidget *w = dockWidget(); + if (w->testAttribute(Qt::WA_WState_Visible) == false) + state |= Invisible; + if (w->focusPolicy() != Qt::NoFocus && w->isActiveWindow()) + state |= Focusable; + if (w->hasFocus()) + state |= Focused; + if (!w->isEnabled()) + state |= Unavailable; + } + + return state; +} + +QRect QAccessibleTitleBar::rect (int child ) const +{ + bool mapToGlobal = true; + QRect rect; + if (child == 0) { + if (dockWidget()->isFloating()) { + rect = dockWidget()->frameGeometry(); + QPoint globalPos = dockWidget()->mapToGlobal( dockWidget()->widget()->rect().topLeft() ); + globalPos.ry()--; + rect.setBottom(globalPos.y()); + mapToGlobal = false; + } else { + QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(dockWidget()->layout()); + rect = layout->titleArea(); + } + }else if (child >= 1 && child <= childCount()) { + QDockWidgetLayout *layout = dockWidgetLayout(); + int index = 1; + for (int role = QDockWidgetLayout::CloseButton; role <= QDockWidgetLayout::FloatButton; ++role) { + QWidget *w = layout->widgetForRole((QDockWidgetLayout::Role)role); + if (!w || !w->isVisible()) + continue; + if (index == child) { + rect = w->geometry(); + break; + } + ++index; + } + } + if (rect.isNull()) + return rect; + + if (mapToGlobal) + rect.moveTopLeft(dockWidget()->mapToGlobal(rect.topLeft())); + return rect; +} + +int QAccessibleTitleBar::childAt(int x, int y) const +{ + for (int i = childCount(); i >= 0; --i) { + if (rect(i).contains(x,y)) + return i; + } + return -1; +} + +QObject *QAccessibleTitleBar::object() const +{ + return m_dockWidget; +} + +QDockWidgetLayout *QAccessibleTitleBar::dockWidgetLayout() const +{ + return qobject_cast<QDockWidgetLayout*>(dockWidget()->layout()); +} + +QDockWidget *QAccessibleTitleBar::dockWidget() const +{ + return m_dockWidget; +} + +QString QAccessibleTitleBar::actionText(int action, Text t, int child) const +{ + QString str; + if (child >= 1 && child <= childCount()) { + if (t == Name) { + switch (action) { + case Press: + case DefaultAction: + if (child == QDockWidgetLayout::CloseButton) { + str = QDockWidget::tr("Close"); + } else if (child == QDockWidgetLayout::FloatButton) { + str = dockWidget()->isFloating() ? QDockWidget::tr("Dock") + : QDockWidget::tr("Float"); + } + break; + default: + break; + } + } + } + return str; +} + +bool QAccessibleTitleBar::doAction(int action, int child, const QVariantList& /*params*/) +{ + if (!child || !dockWidget()->isEnabled()) + return false; + + switch (action) { + case DefaultAction: + case Press: { + QDockWidgetLayout *layout = dockWidgetLayout(); + QAbstractButton *btn = static_cast<QAbstractButton *>(layout->widgetForRole((QDockWidgetLayout::Role)child)); + if (btn) + btn->animateClick(); + return true; + break;} + default: + break; + } + + return false; +} + +int QAccessibleTitleBar::userActionCount (int /*child*/) const +{ + return 0; +} + +QAccessible::Role QAccessibleTitleBar::role(int child) const +{ + switch (child) { + case 0: + return TitleBar; + break; + default: + if (child >= 1 && child <= childCount()) + return PushButton; + break; + } + + return NoRole; +} + +void QAccessibleTitleBar::setText(Text /*t*/, int /*child*/, const QString &/*text*/) +{ + +} + +bool QAccessibleTitleBar::isValid() const +{ + return dockWidget(); +} + +#endif // QT_NO_DOCKWIDGET + +#ifndef QT_NO_TEXTEDIT +void QAccessibleTextEdit::addSelection(int startOffset, int endOffset) +{ + setSelection(0, startOffset, endOffset); +} + +QString QAccessibleTextEdit::attributes(int offset, int *startOffset, int *endOffset) +{ + // TODO - wait for a definition of attributes + Q_UNUSED(offset); + Q_UNUSED(startOffset); + Q_UNUSED(endOffset); + return QString(); +} + +int QAccessibleTextEdit::cursorPosition() +{ + return textEdit()->textCursor().position(); +} + +QRect QAccessibleTextEdit::characterRect(int offset, CoordinateType coordType) +{ + QTextEdit *edit = textEdit(); + QTextCursor cursor(edit->document()); + cursor.setPosition(offset); + + if (cursor.position() != offset) + return QRect(); + + QRect r = edit->cursorRect(cursor); + if (cursor.movePosition(QTextCursor::NextCharacter)) { + r.setWidth(edit->cursorRect(cursor).y() - r.y()); + } else { + // we don't know the width of the character - maybe because we're at document end + // in that case, IAccessible2 tells us to return the width of a default character + int averageCharWidth = QFontMetrics(cursor.charFormat().font()).averageCharWidth(); + if (edit->layoutDirection() == Qt::RightToLeft) + averageCharWidth *= -1; + r.setWidth(averageCharWidth); + } + + switch (coordType) { + case RelativeToScreen: + r.moveTo(edit->viewport()->mapToGlobal(r.topLeft())); + break; + case RelativeToParent: + break; + } + + return r; +} + +int QAccessibleTextEdit::selectionCount() +{ + return textEdit()->textCursor().hasSelection() ? 1 : 0; +} + +int QAccessibleTextEdit::offsetAtPoint(const QPoint &point, CoordinateType coordType) +{ + QTextEdit *edit = textEdit(); + + QPoint p = point; + if (coordType == RelativeToScreen) + p = edit->viewport()->mapFromGlobal(p); + // convert to document coordinates + p += QPoint(edit->horizontalScrollBar()->value(), edit->verticalScrollBar()->value()); + + return edit->document()->documentLayout()->hitTest(p, Qt::ExactHit); +} + +void QAccessibleTextEdit::selection(int selectionIndex, int *startOffset, int *endOffset) +{ + *startOffset = *endOffset = 0; + QTextCursor cursor = textEdit()->textCursor(); + + if (selectionIndex != 0 || !cursor.hasSelection()) + return; + + *startOffset = cursor.selectionStart(); + *endOffset = cursor.selectionEnd(); +} + +QString QAccessibleTextEdit::text(int startOffset, int endOffset) +{ + QTextCursor cursor(textEdit()->document()); + + cursor.setPosition(startOffset, QTextCursor::MoveAnchor); + cursor.setPosition(endOffset, QTextCursor::KeepAnchor); + + return cursor.selectedText(); +} + +QString QAccessibleTextEdit::textBeforeOffset (int offset, BoundaryType boundaryType, + int *startOffset, int *endOffset) +{ + // TODO - what exactly is before? + Q_UNUSED(offset); + Q_UNUSED(boundaryType); + Q_UNUSED(startOffset); + Q_UNUSED(endOffset); + return QString(); +} + +QString QAccessibleTextEdit::textAfterOffset(int offset, BoundaryType boundaryType, + int *startOffset, int *endOffset) +{ + // TODO - what exactly is after? + Q_UNUSED(offset); + Q_UNUSED(boundaryType); + Q_UNUSED(startOffset); + Q_UNUSED(endOffset); + return QString(); +} + +QString QAccessibleTextEdit::textAtOffset(int offset, BoundaryType boundaryType, + int *startOffset, int *endOffset) +{ + Q_ASSERT(startOffset); + Q_ASSERT(endOffset); + + *startOffset = *endOffset = -1; + QTextEdit *edit = textEdit(); + + QTextCursor cursor(edit->document()); + if (offset >= characterCount()) + return QString(); + + switch (boundaryType) { + case CharBoundary: + cursor.setPosition(offset); + *startOffset = cursor.position(); + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); + *endOffset = cursor.position(); + break; + case WordBoundary: + cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor); + *startOffset = cursor.position(); + cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); + *endOffset = cursor.position(); + break; + case SentenceBoundary: + // TODO - what's a sentence? + return QString(); + case LineBoundary: + cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor); + *startOffset = cursor.position(); + cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor); + *endOffset = cursor.position(); + break; + case ParagraphBoundary: + cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor); + *startOffset = cursor.position(); + cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); + *endOffset = cursor.position(); + break; + case NoBoundary: { + *startOffset = 0; + const QString txt = edit->toPlainText(); + *endOffset = txt.count(); + return txt; } + default: + qDebug("AccessibleTextAdaptor::textAtOffset: Unknown boundary type %d", boundaryType); + return QString(); + } + + return cursor.selectedText(); +} + +void QAccessibleTextEdit::removeSelection(int selectionIndex) +{ + if (selectionIndex != 0) + return; + + QTextCursor cursor = textEdit()->textCursor(); + cursor.clearSelection(); + textEdit()->setTextCursor(cursor); +} + +void QAccessibleTextEdit::setCursorPosition(int position) +{ + QTextCursor cursor = textEdit()->textCursor(); + cursor.setPosition(position); + textEdit()->setTextCursor(cursor); +} + +void QAccessibleTextEdit::setSelection(int selectionIndex, int startOffset, int endOffset) +{ + if (selectionIndex != 0) + return; + + QTextCursor cursor = textEdit()->textCursor(); + cursor.setPosition(startOffset, QTextCursor::MoveAnchor); + cursor.setPosition(endOffset, QTextCursor::KeepAnchor); + textEdit()->setTextCursor(cursor); +} + +int QAccessibleTextEdit::characterCount() +{ + return textEdit()->toPlainText().count(); +} + +void QAccessibleTextEdit::scrollToSubstring(int startIndex, int endIndex) +{ + QTextEdit *edit = textEdit(); + + QTextCursor cursor(edit->document()); + cursor.setPosition(startIndex); + QRect r = edit->cursorRect(cursor); + + cursor.setPosition(endIndex); + r.setBottomRight(edit->cursorRect(cursor).bottomRight()); + + r.moveTo(r.x() + edit->horizontalScrollBar()->value(), + r.y() + edit->verticalScrollBar()->value()); + + // E V I L, but ensureVisible is not public + if (!QMetaObject::invokeMethod(edit, "_q_ensureVisible", Q_ARG(QRectF, r))) + qWarning("AccessibleTextEdit::scrollToSubstring failed!"); +} + +static QTextCursor cursorForRange(QTextEdit *textEdit, int startOffset, int endOffset) +{ + QTextCursor cursor(textEdit->document()); + cursor.setPosition(startOffset, QTextCursor::MoveAnchor); + cursor.setPosition(endOffset, QTextCursor::KeepAnchor); + + return cursor; +} + +void QAccessibleTextEdit::copyText(int startOffset, int endOffset) +{ + QTextCursor cursor = cursorForRange(textEdit(), startOffset, endOffset); + + if (!cursor.hasSelection()) + return; + +// QApplication::clipboard()->setMimeData(new QTextEditMimeData(cursor.selection())); +} + +void QAccessibleTextEdit::deleteText(int startOffset, int endOffset) +{ + QTextCursor cursor = cursorForRange(textEdit(), startOffset, endOffset); + + cursor.removeSelectedText(); +} + +void QAccessibleTextEdit::insertText(int offset, const QString &text) +{ + QTextCursor cursor(textEdit()->document()); + cursor.setPosition(offset); + + cursor.insertText(text); +} + +void QAccessibleTextEdit::cutText(int startOffset, int endOffset) +{ + QTextCursor cursor = cursorForRange(textEdit(), startOffset, endOffset); + + if (!cursor.hasSelection()) + return; + +// QApplication::clipboard()->setMimeData(new QTextEditMimeData(cursor.selection())); + cursor.removeSelectedText(); +} + +void QAccessibleTextEdit::pasteText(int offset) +{ + QTextEdit *edit = textEdit(); + + QTextCursor oldCursor = edit->textCursor(); + QTextCursor newCursor = oldCursor; + newCursor.setPosition(offset); + + edit->setTextCursor(newCursor); +#ifndef QT_NO_CLIPBOARD + edit->paste(); +#endif + edit->setTextCursor(oldCursor); +} + +void QAccessibleTextEdit::replaceText(int startOffset, int endOffset, const QString &text) +{ + QTextCursor cursor = cursorForRange(textEdit(), startOffset, endOffset); + + cursor.removeSelectedText(); + cursor.insertText(text); +} + +void QAccessibleTextEdit::setAttributes(int startOffset, int endOffset, const QString &attributes) +{ + // TODO + Q_UNUSED(startOffset); + Q_UNUSED(endOffset); + Q_UNUSED(attributes); +} + +#endif // QT_NO_TEXTEDIT + +#ifndef QT_NO_MAINWINDOW +QAccessibleMainWindow::QAccessibleMainWindow(QWidget *widget) + : QAccessibleWidgetEx(widget, Application) { } + +QVariant QAccessibleMainWindow::invokeMethodEx(QAccessible::Method /*method*/, int /*child*/, const QVariantList & /*params*/) +{ + return QVariant(); +} + +int QAccessibleMainWindow::childCount() const +{ + QList<QWidget*> kids = childWidgets(mainWindow(), true); + return kids.count(); +} + +int QAccessibleMainWindow::indexOfChild(const QAccessibleInterface *iface) const +{ + QList<QWidget*> kids = childWidgets(mainWindow(), true); + int childIndex = kids.indexOf(static_cast<QWidget*>(iface->object())); + return childIndex == -1 ? -1 : ++childIndex; +} + +int QAccessibleMainWindow::navigate(RelationFlag relation, int entry, QAccessibleInterface **iface) const +{ + if (relation == Child && entry >= 1) { + QList<QWidget*> kids = childWidgets(mainWindow(), true); + if (entry <= kids.count()) { + *iface = QAccessible::queryAccessibleInterface(kids.at(entry - 1)); + return *iface ? 0 : -1; + } + } + return QAccessibleWidgetEx::navigate(relation, entry, iface); +} + +int QAccessibleMainWindow::childAt(int x, int y) const +{ + QWidget *w = widget(); + if (!w->isVisible()) + return -1; + QPoint gp = w->mapToGlobal(QPoint(0, 0)); + if (!QRect(gp.x(), gp.y(), w->width(), w->height()).contains(x, y)) + return -1; + + QWidgetList kids = childWidgets(mainWindow(), true); + QPoint rp = mainWindow()->mapFromGlobal(QPoint(x, y)); + for (int i = 0; i < kids.size(); ++i) { + QWidget *child = kids.at(i); + if (!child->isWindow() && !child->isHidden() && child->geometry().contains(rp)) { + return i + 1; + } + } + return 0; +} + +QMainWindow *QAccessibleMainWindow::mainWindow() const +{ + return qobject_cast<QMainWindow *>(object()); +} + +#endif //QT_NO_MAINWINDOW + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.h b/src/plugins/accessible/widgets/qaccessiblewidgets.h new file mode 100644 index 0000000..648ed78 --- /dev/null +++ b/src/plugins/accessible/widgets/qaccessiblewidgets.h @@ -0,0 +1,318 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QACCESSIBLEWIDGETS_H +#define QACCESSIBLEWIDGETS_H + +#include <QtGui/qaccessible2.h> +#include <QtGui/qaccessiblewidget.h> + +#ifndef QT_NO_ACCESSIBILITY + +#include <QtCore/QPointer> + +QT_BEGIN_NAMESPACE + +class QTextEdit; +class QStackedWidget; +class QToolBox; +class QMdiArea; +class QMdiSubWindow; +class QWorkspace; +class QRubberBand; +class QTextBrowser; +class QCalendarWidget; +class QAbstractItemView; +class QDockWidget; +class QDockWidgetLayout; +class QMainWindow; + +#ifndef QT_NO_TEXTEDIT +class QAccessibleTextEdit : public QAccessibleWidgetEx, public QAccessibleTextInterface, + public QAccessibleEditableTextInterface +{ + Q_ACCESSIBLE_OBJECT +public: + explicit QAccessibleTextEdit(QWidget *o); + + QString text(Text t, int child) const; + void setText(Text t, int control, const QString &text); + Role role(int child) const; + + QVariant invokeMethodEx(QAccessible::Method method, int child, const QVariantList ¶ms); + + QRect rect(int child) const; + int childAt(int x, int y) const; + + int childCount() const; + + // QAccessibleTextInterface + void addSelection(int startOffset, int endOffset); + QString attributes(int offset, int *startOffset, int *endOffset); + int cursorPosition(); + QRect characterRect(int offset, QAccessible2::CoordinateType coordType); + int selectionCount(); + int offsetAtPoint(const QPoint &point, QAccessible2::CoordinateType coordType); + void selection(int selectionIndex, int *startOffset, int *endOffset); + QString text(int startOffset, int endOffset); + QString textBeforeOffset (int offset, QAccessible2::BoundaryType boundaryType, + int *startOffset, int *endOffset); + QString textAfterOffset(int offset, QAccessible2::BoundaryType boundaryType, + int *startOffset, int *endOffset); + QString textAtOffset(int offset, QAccessible2::BoundaryType boundaryType, + int *startOffset, int *endOffset); + void removeSelection(int selectionIndex); + void setCursorPosition(int position); + void setSelection(int selectionIndex, int startOffset, int endOffset); + int characterCount(); + void scrollToSubstring(int startIndex, int endIndex); + + // QAccessibleEditableTextInterface + void copyText(int startOffset, int endOffset); + void deleteText(int startOffset, int endOffset); + void insertText(int offset, const QString &text); + void cutText(int startOffset, int endOffset); + void pasteText(int offset); + void replaceText(int startOffset, int endOffset, const QString &text); + void setAttributes(int startOffset, int endOffset, const QString &attributes); + +protected: + QTextEdit *textEdit() const; + +private: + int childOffset; +}; +#endif // QT_NO_TEXTEDIT + +class QAccessibleStackedWidget : public QAccessibleWidgetEx +{ + Q_ACCESSIBLE_OBJECT +public: + explicit QAccessibleStackedWidget(QWidget *widget); + + QVariant invokeMethodEx(QAccessible::Method method, int child, const QVariantList ¶ms); + int childAt(int x, int y) const; + int childCount() const; + int indexOfChild(const QAccessibleInterface *child) const; + int navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const; + +protected: + QStackedWidget *stackedWidget() const; +}; + +class QAccessibleToolBox : public QAccessibleWidgetEx +{ + Q_ACCESSIBLE_OBJECT +public: + explicit QAccessibleToolBox(QWidget *widget); + + QString text(Text textType, int child) const; + void setText(Text textType, int child, const QString &text); + State state(int child) const; + QVariant invokeMethodEx(QAccessible::Method method, int child, const QVariantList ¶ms); + int childCount() const; + int indexOfChild(const QAccessibleInterface *child) const; + int navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const; + +protected: + QToolBox *toolBox() const; +}; + +#ifndef QT_NO_MDIAREA +class QAccessibleMdiArea : public QAccessibleWidgetEx +{ +public: + explicit QAccessibleMdiArea(QWidget *widget); + + State state(int child) const; + QVariant invokeMethodEx(QAccessible::Method method, int child, const QVariantList ¶ms); + int childCount() const; + int indexOfChild(const QAccessibleInterface *child) const; + int navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const; + +protected: + QMdiArea *mdiArea() const; +}; + +class QAccessibleMdiSubWindow : public QAccessibleWidgetEx +{ +public: + explicit QAccessibleMdiSubWindow(QWidget *widget); + + QString text(Text textType, int child) const; + void setText(Text textType, int child, const QString &text); + State state(int child) const; + QVariant invokeMethodEx(QAccessible::Method method, int child, const QVariantList ¶ms); + int childCount() const; + int indexOfChild(const QAccessibleInterface *child) const; + int navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const; + QRect rect(int child) const; + int childAt(int x, int y) const; + +protected: + QMdiSubWindow *mdiSubWindow() const; +}; +#endif // QT_NO_MDIAREA + +#ifndef QT_NO_WORKSPACE +class QAccessibleWorkspace : public QAccessibleWidgetEx +{ +public: + explicit QAccessibleWorkspace(QWidget *widget); + + State state(int child) const; + QVariant invokeMethodEx(QAccessible::Method method, int child, const QVariantList ¶ms); + int childCount() const; + int indexOfChild(const QAccessibleInterface *child) const; + int navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const; + +protected: + QWorkspace *workspace() const; +}; +#endif + +class QAccessibleDialogButtonBox : public QAccessibleWidgetEx +{ +public: + explicit QAccessibleDialogButtonBox(QWidget *widget); + + QVariant invokeMethodEx(QAccessible::Method method, int child, const QVariantList ¶ms); +}; + +#ifndef QT_NO_TEXTBROWSER +class QAccessibleTextBrowser : public QAccessibleTextEdit +{ +public: + explicit QAccessibleTextBrowser(QWidget *widget); + + Role role(int child) const; +}; +#endif // QT_NO_TEXTBROWSER + +#ifndef QT_NO_CALENDARWIDGET +class QAccessibleCalendarWidget : public QAccessibleWidgetEx +{ +public: + explicit QAccessibleCalendarWidget(QWidget *widget); + + QVariant invokeMethodEx(QAccessible::Method method, int child, const QVariantList ¶ms); + int childCount() const; + int indexOfChild(const QAccessibleInterface *child) const; + int navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const; + QRect rect(int child) const; + int childAt(int x, int y) const; + +protected: + QCalendarWidget *calendarWidget() const; + +private: + QAbstractItemView *calendarView() const; + QWidget *navigationBar() const; +}; +#endif // QT_NO_CALENDARWIDGET + +#ifndef QT_NO_DOCKWIDGET +class QAccessibleDockWidget: public QAccessibleWidgetEx +{ +public: + explicit QAccessibleDockWidget(QWidget *widget); + int navigate(RelationFlag relation, int entry, QAccessibleInterface **iface) const; + int indexOfChild(const QAccessibleInterface *child) const; + int childCount() const; + QRect rect (int child ) const; + Role role(int child) const; + State state(int child) const; + int childAt(int x, int y) const; + + QVariant invokeMethodEx(QAccessible::Method method, int child, const QVariantList ¶ms); + QDockWidget *dockWidget() const; +}; + +class QAccessibleTitleBar : public QAccessibleInterface +{ +public: + explicit QAccessibleTitleBar(QDockWidget *widget); + QString actionText(int action, Text t, int child) const; + bool doAction(int action, int child, const QVariantList& params = QVariantList()); + int userActionCount ( int child) const; + int navigate(RelationFlag relation, int entry, QAccessibleInterface **iface) const; + int indexOfChild(const QAccessibleInterface *child) const; + int childCount() const; + Relation relationTo(int child, const QAccessibleInterface *other, int otherChild) const; + void setText(Text t, int child, const QString &text); + QString text(Text t, int child) const; + Role role(int child) const; + QRect rect (int child) const; + State state(int child) const; + int childAt(int x, int y) const; + QObject *object() const; + bool isValid() const; + + + QPointer<QDockWidget> m_dockWidget; + + QDockWidget *dockWidget() const; + QDockWidgetLayout *dockWidgetLayout() const; +}; + +#endif // QT_NO_DOCKWIDGET + +#ifndef QT_NO_MAINWINDOW +class QAccessibleMainWindow : public QAccessibleWidgetEx +{ +public: + explicit QAccessibleMainWindow(QWidget *widget); + + QVariant invokeMethodEx(QAccessible::Method method, int child, const QVariantList ¶ms); + int childCount() const; + int navigate(RelationFlag relation, int entry, QAccessibleInterface **iface) const; + int indexOfChild(const QAccessibleInterface *iface) const; + int childAt(int x, int y) const; + QMainWindow *mainWindow() const; + +}; +#endif //QT_NO_MAINWINDOW + +#endif // QT_NO_ACCESSIBILITY + +QT_END_NAMESPACE + +#endif // QACESSIBLEWIDGETS_H diff --git a/src/plugins/accessible/widgets/rangecontrols.cpp b/src/plugins/accessible/widgets/rangecontrols.cpp new file mode 100644 index 0000000..9297d6e --- /dev/null +++ b/src/plugins/accessible/widgets/rangecontrols.cpp @@ -0,0 +1,991 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "rangecontrols.h" + +#include <qslider.h> +#include <qdial.h> +#include <qspinbox.h> +#include <qscrollbar.h> +#include <qstyle.h> +#include <qstyleoption.h> +#include <qdebug.h> +#include <qglobal.h> +#include <QDoubleSpinBox> +#include <QDial> +#include <qmath.h> +#include <private/qmath_p.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_ACCESSIBILITY +extern QString Q_GUI_EXPORT qt_accStripAmp(const QString &text); +#ifndef QT_NO_SCROLLBAR +extern QStyleOptionSlider Q_GUI_EXPORT qt_qscrollbarStyleOption(QScrollBar *scrollBar); +#endif +#ifndef QT_NO_SLIDER +extern QStyleOptionSlider Q_GUI_EXPORT qt_qsliderStyleOption(QSlider *slider); +#endif + +#ifndef QT_NO_SPINBOX +QAccessibleAbstractSpinBox::QAccessibleAbstractSpinBox(QWidget *w) +: QAccessibleWidgetEx(w, SpinBox) +{ + Q_ASSERT(abstractSpinBox()); +} + +/*! + Returns the underlying QAbstractSpinBox. +*/ +QAbstractSpinBox *QAccessibleAbstractSpinBox::abstractSpinBox() const +{ + return qobject_cast<QAbstractSpinBox*>(object()); +} + +/*! \reimp */ +int QAccessibleAbstractSpinBox::childCount() const +{ + if (!abstractSpinBox()->isVisible()) + return 0; + return ValueDown; +} + +/*! \reimp */ +QRect QAccessibleAbstractSpinBox::rect(int child) const +{ + QRect rect; + if (!abstractSpinBox()->isVisible()) + return rect; + QStyleOptionSpinBox so; + so.rect = widget()->rect(); + switch(child) { + case Editor: + rect = widget()->style()->subControlRect(QStyle::CC_SpinBox, &so, + QStyle::SC_SpinBoxEditField, widget()); + break; + case ValueUp: + rect = widget()->style()->subControlRect(QStyle::CC_SpinBox, &so, + QStyle::SC_SpinBoxUp, widget()); + break; + case ValueDown: + rect = widget()->style()->subControlRect(QStyle::CC_SpinBox, &so, + QStyle::SC_SpinBoxDown, widget()); + break; + default: + rect = so.rect; + break; + } + QPoint tl = widget()->mapToGlobal(QPoint(0, 0)); + return QRect(tl.x() + rect.x(), tl.y() + rect.y(), rect.width(), rect.height()); +} + +/*! \reimp */ +int QAccessibleAbstractSpinBox::navigate(RelationFlag rel, int entry, QAccessibleInterface **target) const +{ + *target = 0; + + if (entry) switch (rel) { + case Child: + return entry <= childCount() ? entry : -1; + case QAccessible::Left: + return (entry == ValueUp || entry == ValueDown) ? Editor : -1; + case QAccessible::Right: + return entry == Editor ? ValueUp : -1; + case QAccessible::Up: + return entry == ValueDown ? ValueUp : -1; + case QAccessible::Down: + return entry == ValueUp ? ValueDown : -1; + default: + break; + } + return QAccessibleWidgetEx::navigate(rel, entry, target); +} + +/*! \reimp */ +QString QAccessibleAbstractSpinBox::text(Text t, int child) const +{ + if (!abstractSpinBox()->isVisible()) + return QString(); + switch (t) { + case Name: + switch (child) { + case ValueUp: + return QSpinBox::tr("More"); + case ValueDown: + return QSpinBox::tr("Less"); + } + break; + case Value: + if (child == Editor || child == SpinBoxSelf) + return abstractSpinBox()->text(); + break; + default: + break; + } + return QAccessibleWidgetEx::text(t, 0); +} + +/*! \reimp */ +QAccessible::Role QAccessibleAbstractSpinBox::role(int child) const +{ + switch(child) { + case Editor: + return EditableText; + case ValueUp: + case ValueDown: + return PushButton; + default: + break; + } + return QAccessibleWidgetEx::role(child); +} + +/*! \reimp */ +bool QAccessibleAbstractSpinBox::doAction(int action, int child, const QVariantList ¶ms) +{ + if (!widget()->isEnabled()) + return false; + + if (action == Press) { + switch(child) { + case ValueUp: + abstractSpinBox()->stepUp(); + return true; + case ValueDown: + abstractSpinBox()->stepDown(); + return true; + default: + break; + } + } + return QAccessibleWidgetEx::doAction(action, 0, params); +} + +QVariant QAccessibleAbstractSpinBox::currentValue() +{ + QVariant result = abstractSpinBox()->property("value"); + QVariant::Type type = result.type(); + + // IA2 only allows numeric types + if (type == QVariant::Int || type == QVariant::UInt || type == QVariant::LongLong + || type == QVariant::ULongLong || type == QVariant::Double) + return result; + + return QVariant(); +} + +void QAccessibleAbstractSpinBox::setCurrentValue(const QVariant &value) +{ + abstractSpinBox()->setProperty("setValue", value); +} + +QVariant QAccessibleAbstractSpinBox::maximumValue() +{ + return abstractSpinBox()->property("maximum"); +} + +QVariant QAccessibleAbstractSpinBox::minimumValue() +{ + return abstractSpinBox()->property("minimum"); +} + +QVariant QAccessibleAbstractSpinBox::invokeMethodEx(Method method, int child, const QVariantList ¶ms) +{ + switch (method) { + case ListSupportedMethods: { + QSet<QAccessible::Method> set; + set << ListSupportedMethods; + return qVariantFromValue(set | qvariant_cast<QSet<QAccessible::Method> >( + QAccessibleWidgetEx::invokeMethodEx(method, child, params))); + } + default: + return QAccessibleWidgetEx::invokeMethodEx(method, child, params); + } +} + + +/*! + \class QAccessibleSpinBox + \brief The QAccessibleSpinBox class implements the QAccessibleInterface for spinbox widgets. + \internal + + \ingroup accessibility +*/ + +/*! + \enum QAccessibleAbstractSpinBox::SpinBoxElements + + This enum identifies the components of the spin box. + + \value SpinBoxSelf The spin box as a whole + \value Editor The line edit sub-widget. + \value ValueUp The up sub-widget (i.e. the up arrow or + button) + \value ValueDown The down sub-widget (i.e. the down arrow or - button) +*/ + +/*! + Constructs a QAccessibleSpinWidget object for \a w. +*/ +QAccessibleSpinBox::QAccessibleSpinBox(QWidget *w) +: QAccessibleAbstractSpinBox(w) +{ + Q_ASSERT(spinBox()); + addControllingSignal(QLatin1String("valueChanged(int)")); + addControllingSignal(QLatin1String("valueChanged(QString)")); +} + +/*! + Returns the underlying QSpinBox. +*/ +QSpinBox *QAccessibleSpinBox::spinBox() const +{ + return qobject_cast<QSpinBox*>(object()); +} + +/*! \reimp */ +QAccessible::State QAccessibleSpinBox::state(int child) const +{ + State state = QAccessibleAbstractSpinBox::state(child); + switch(child) { + case ValueUp: + if (spinBox()->value() >= spinBox()->maximum()) + state |= Unavailable; + return state; + case ValueDown: + if (spinBox()->value() <= spinBox()->minimum()) + state |= Unavailable; + return state; + default: + break; + } + return state; +} + +/*! \reimp */ +bool QAccessibleSpinBox::doAction(int action, int child, const QVariantList ¶ms) +{ + if (!widget()->isEnabled()) + return false; + + if (action == Press) { + switch(child) { + case ValueUp: + if (spinBox()->value() >= spinBox()->maximum()) + return false; + spinBox()->stepUp(); + return true; + case ValueDown: + if (spinBox()->value() <= spinBox()->minimum()) + return false; + spinBox()->stepDown(); + return true; + default: + break; + } + } + return QAccessibleAbstractSpinBox::doAction(action, 0, params); +} + +// ================================== QAccessibleDoubleSpinBox ================================== +QAccessibleDoubleSpinBox::QAccessibleDoubleSpinBox(QWidget *widget) + : QAccessibleWidgetEx(widget, SpinBox) +{ + Q_ASSERT(qobject_cast<QDoubleSpinBox *>(widget)); + addControllingSignal(QLatin1String("valueChanged(double)")); + addControllingSignal(QLatin1String("valueChanged(QString)")); +} + +/*! + Returns the underlying QDoubleSpinBox. +*/ +QDoubleSpinBox *QAccessibleDoubleSpinBox::doubleSpinBox() const +{ + return static_cast<QDoubleSpinBox*>(object()); +} + +/*! \reimp */ +int QAccessibleDoubleSpinBox::childCount() const +{ + if (!doubleSpinBox()->isVisible()) + return 0; + return ValueDown; +} + +/*! \reimp */ +QRect QAccessibleDoubleSpinBox::rect(int child) const +{ + QRect rect; + if (!doubleSpinBox()->isVisible()) + return rect; + QStyleOptionSpinBox spinBoxOption; + spinBoxOption.initFrom(doubleSpinBox()); + switch (child) { + case Editor: + rect = doubleSpinBox()->style()->subControlRect(QStyle::CC_SpinBox, &spinBoxOption, + QStyle::SC_SpinBoxEditField, doubleSpinBox()); + break; + case ValueUp: + rect = doubleSpinBox()->style()->subControlRect(QStyle::CC_SpinBox, &spinBoxOption, + QStyle::SC_SpinBoxUp, doubleSpinBox()); + break; + case ValueDown: + rect = doubleSpinBox()->style()->subControlRect(QStyle::CC_SpinBox, &spinBoxOption, + QStyle::SC_SpinBoxDown, doubleSpinBox()); + break; + default: + rect = spinBoxOption.rect; + break; + } + const QPoint globalPos = doubleSpinBox()->mapToGlobal(QPoint(0, 0)); + return QRect(globalPos.x() + rect.x(), globalPos.y() + rect.y(), rect.width(), rect.height()); +} + +/*! \reimp */ +int QAccessibleDoubleSpinBox::navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const +{ + if (entry <= 0) + return QAccessibleWidgetEx::navigate(relation, entry, target); + + *target = 0; + switch (relation) { + case Child: + return entry <= childCount() ? entry : -1; + case QAccessible::Left: + return (entry == ValueUp || entry == ValueDown) ? Editor : -1; + case QAccessible::Right: + return entry == Editor ? ValueUp : -1; + case QAccessible::Up: + return entry == ValueDown ? ValueUp : -1; + case QAccessible::Down: + return entry == ValueUp ? ValueDown : -1; + default: + break; + } + return QAccessibleWidgetEx::navigate(relation, entry, target); +} + +QVariant QAccessibleDoubleSpinBox::invokeMethodEx(QAccessible::Method, int, const QVariantList &) +{ + return QVariant(); +} + +/*! \reimp */ +QString QAccessibleDoubleSpinBox::text(Text textType, int child) const +{ + if (!doubleSpinBox()->isVisible()) + return QString(); + switch (textType) { + case Name: + if (child == ValueUp) + return QDoubleSpinBox::tr("More"); + else if (child == ValueDown) + return QDoubleSpinBox::tr("Less"); + break; + case Value: + if (child == Editor || child == SpinBoxSelf) + return doubleSpinBox()->textFromValue(doubleSpinBox()->value()); + break; + default: + break; + } + return QAccessibleWidgetEx::text(textType, 0); +} + +/*! \reimp */ +QAccessible::Role QAccessibleDoubleSpinBox::role(int child) const +{ + switch (child) { + case Editor: + return EditableText; + case ValueUp: + case ValueDown: + return PushButton; + default: + break; + } + return QAccessibleWidgetEx::role(child); +} + +/*! \reimp */ +QAccessible::State QAccessibleDoubleSpinBox::state(int child) const +{ + State state = QAccessibleWidgetEx::state(child); + switch (child) { + case ValueUp: + if (doubleSpinBox()->value() >= doubleSpinBox()->maximum()) + state |= Unavailable; + break; + case ValueDown: + if (doubleSpinBox()->value() <= doubleSpinBox()->minimum()) + state |= Unavailable; + break; + default: + break; + } + return state; +} +#endif // QT_NO_SPINBOX + +#ifndef QT_NO_SCROLLBAR +/*! + \class QAccessibleScrollBar + \brief The QAccessibleScrollBar class implements the QAccessibleInterface for scroll bars. + \internal + + \ingroup accessibility +*/ + +/*! + \enum QAccessibleScrollBar::ScrollBarElements + + This enum identifies the components of the scroll bar. + + \value ScrollBarSelf The scroll bar as a whole. + \value LineUp The up arrow button. + \value PageUp The area between the position and the up arrow button. + \value Position The position marking rectangle. + \value PageDown The area between the position and the down arrow button. + \value LineDown The down arrow button. +*/ + +/*! + Constructs a QAccessibleScrollBar object for \a w. + \a name is propagated to the QAccessibleWidgetEx constructor. +*/ +QAccessibleScrollBar::QAccessibleScrollBar(QWidget *w) +: QAccessibleAbstractSlider(w, ScrollBar) +{ + Q_ASSERT(scrollBar()); + addControllingSignal(QLatin1String("valueChanged(int)")); +} + +/*! Returns the scroll bar. */ +QScrollBar *QAccessibleScrollBar::scrollBar() const +{ + return qobject_cast<QScrollBar*>(object()); +} + +/*! \reimp */ +QRect QAccessibleScrollBar::rect(int child) const +{ + if (!scrollBar()->isVisible()) + return QRect(); + + QStyle::SubControl subControl; + switch (child) { + case LineUp: + subControl = QStyle ::SC_ScrollBarSubLine; + break; + case PageUp: + subControl = QStyle::SC_ScrollBarSubPage; + break; + case Position: + subControl = QStyle::SC_ScrollBarSlider; + break; + case PageDown: + subControl = QStyle::SC_ScrollBarAddPage; + break; + case LineDown: + subControl = QStyle::SC_ScrollBarAddLine; + break; + default: + return QAccessibleAbstractSlider::rect(child); + } + + const QStyleOptionSlider option = qt_qscrollbarStyleOption(scrollBar()); + const QRect rect = scrollBar()->style()->subControlRect(QStyle::CC_ScrollBar, &option, + subControl, scrollBar()); + const QPoint tp = scrollBar()->mapToGlobal(QPoint(0,0)); + return QRect(tp.x() + rect.x(), tp.y() + rect.y(), rect.width(), rect.height()); +} + +/*! \reimp */ +int QAccessibleScrollBar::childCount() const +{ + if (!scrollBar()->isVisible()) + return 0; + return LineDown; +} + +/*! \reimp */ +QString QAccessibleScrollBar::text(Text t, int child) const +{ + if (!scrollBar()->isVisible()) + return QString(); + switch (t) { + case Value: + if (!child || child == Position) + return QString::number(scrollBar()->value()); + return QString(); + case Name: + switch (child) { + case LineUp: + return QScrollBar::tr("Line up"); + case PageUp: + return QScrollBar::tr("Page up"); + case Position: + return QScrollBar::tr("Position"); + case PageDown: + return QScrollBar::tr("Page down"); + case LineDown: + return QScrollBar::tr("Line down"); + } + break; + default: + break; + } + return QAccessibleAbstractSlider::text(t, child); +} + +/*! \reimp */ +QAccessible::Role QAccessibleScrollBar::role(int child) const +{ + switch (child) { + case LineUp: + case PageUp: + case PageDown: + case LineDown: + return PushButton; + case Position: + return Indicator; + default: + return ScrollBar; + } +} + +/*! \reimp */ +QAccessible::State QAccessibleScrollBar::state(int child) const +{ + const State parentState = QAccessibleAbstractSlider::state(0); + + if (child == 0) + return parentState; + + // Inherit the Invisible state from parent. + State state = parentState & QAccessible::Invisible; + + // Disable left/right if we are at the minimum/maximum. + const QScrollBar * const scrollBar = QAccessibleScrollBar::scrollBar(); + switch (child) { + case LineUp: + case PageUp: + if (scrollBar->value() <= scrollBar->minimum()) + state |= Unavailable; + break; + case LineDown: + case PageDown: + if (scrollBar->value() >= scrollBar->maximum()) + state |= Unavailable; + break; + case Position: + default: + break; + } + + return state; +} +#endif // QT_NO_SCROLLBAR + +#ifndef QT_NO_SLIDER +/*! + \class QAccessibleSlider + \brief The QAccessibleSlider class implements the QAccessibleInterface for sliders. + \internal + + \ingroup accessibility +*/ + +/*! + \enum QAccessibleSlider::SliderElements + + This enum identifies the components of the slider. + + \value SliderSelf The slider as a whole. + \value PageLeft The area to the left of the position. + \value Position The position indicator. + \value PageRight The area to the right of the position. +*/ + +/*! + Constructs a QAccessibleScrollBar object for \a w. + \a name is propagated to the QAccessibleWidgetEx constructor. +*/ +QAccessibleSlider::QAccessibleSlider(QWidget *w) +: QAccessibleAbstractSlider(w) +{ + Q_ASSERT(slider()); + addControllingSignal(QLatin1String("valueChanged(int)")); +} + +/*! Returns the slider. */ +QSlider *QAccessibleSlider::slider() const +{ + return qobject_cast<QSlider*>(object()); +} + +/*! \reimp */ +QRect QAccessibleSlider::rect(int child) const +{ + QRect rect; + if (!slider()->isVisible()) + return rect; + const QStyleOptionSlider option = qt_qsliderStyleOption(slider()); + QRect srect = slider()->style()->subControlRect(QStyle::CC_Slider, &option, + QStyle::SC_SliderHandle, slider()); + + switch (child) { + case PageLeft: + if (slider()->orientation() == Qt::Vertical) + rect = QRect(0, 0, slider()->width(), srect.y()); + else + rect = QRect(0, 0, srect.x(), slider()->height()); + break; + case Position: + rect = srect; + break; + case PageRight: + if (slider()->orientation() == Qt::Vertical) + rect = QRect(0, srect.y() + srect.height(), slider()->width(), slider()->height()- srect.y() - srect.height()); + else + rect = QRect(srect.x() + srect.width(), 0, slider()->width() - srect.x() - srect.width(), slider()->height()); + break; + default: + return QAccessibleAbstractSlider::rect(child); + } + + QPoint tp = slider()->mapToGlobal(QPoint(0,0)); + return QRect(tp.x() + rect.x(), tp.y() + rect.y(), rect.width(), rect.height()); +} + +/*! \reimp */ +int QAccessibleSlider::childCount() const +{ + if (!slider()->isVisible()) + return 0; + return PageRight; +} + +/*! \reimp */ +QString QAccessibleSlider::text(Text t, int child) const +{ + if (!slider()->isVisible()) + return QString(); + switch (t) { + case Value: + if (!child || child == 2) + return QString::number(slider()->value()); + return QString(); + case Name: + switch (child) { + case PageLeft: + return slider()->orientation() == Qt::Horizontal ? + QSlider::tr("Page left") : QSlider::tr("Page up"); + case Position: + return QSlider::tr("Position"); + case PageRight: + return slider()->orientation() == Qt::Horizontal ? + QSlider::tr("Page right") : QSlider::tr("Page down"); + } + break; + default: + break; + } + return QAccessibleAbstractSlider::text(t, child); +} + +/*! \reimp */ +QAccessible::Role QAccessibleSlider::role(int child) const +{ + switch (child) { + case PageLeft: + case PageRight: + return PushButton; + case Position: + return Indicator; + default: + return Slider; + } +} + +/*! \reimp */ +QAccessible::State QAccessibleSlider::state(int child) const +{ + const State parentState = QAccessibleAbstractSlider::state(0); + + if (child == 0) + return parentState; + + // Inherit the Invisible state from parent. + State state = parentState & QAccessible::Invisible; + + // Disable left/right if we are at the minimum/maximum. + const QSlider * const slider = QAccessibleSlider::slider(); + switch (child) { + case PageLeft: + if (slider->value() <= slider->minimum()) + state |= Unavailable; + break; + case PageRight: + if (slider->value() >= slider->maximum()) + state |= Unavailable; + break; + case Position: + default: + break; + } + + return state; +} + +/*! + \fn int QAccessibleSlider::defaultAction(int child) const + + Returns the default action for the given \a child. The base class + implementation returns 0. +*/ +int QAccessibleSlider::defaultAction(int /*child*/) const +{ +/* + switch (child) { + case SliderSelf: + return SetFocus; + case PageLeft: + return Press; + case PageRight: + return Press; + } +*/ + return 0; +} + +/*! \internal */ +QString QAccessibleSlider::actionText(int /*action*/, Text /*t*/, int /*child*/) const +{ + return QString(QLatin1String("")); +} + +QAccessibleAbstractSlider::QAccessibleAbstractSlider(QWidget *w, Role r) + : QAccessibleWidgetEx(w, r) +{ + Q_ASSERT(qobject_cast<QAbstractSlider *>(w)); +} + +QVariant QAccessibleAbstractSlider::invokeMethodEx(Method method, int child, const QVariantList ¶ms) +{ + switch (method) { + case ListSupportedMethods: { + QSet<QAccessible::Method> set; + set << ListSupportedMethods; + return qVariantFromValue(set | qvariant_cast<QSet<QAccessible::Method> >( + QAccessibleWidgetEx::invokeMethodEx(method, child, params))); + } + default: + return QAccessibleWidgetEx::invokeMethodEx(method, child, params); + } +} + +QVariant QAccessibleAbstractSlider::currentValue() +{ + return abstractSlider()->value(); +} + +void QAccessibleAbstractSlider::setCurrentValue(const QVariant &value) +{ + abstractSlider()->setValue(value.toInt()); +} + +QVariant QAccessibleAbstractSlider::maximumValue() +{ + return abstractSlider()->maximum(); +} + +QVariant QAccessibleAbstractSlider::minimumValue() +{ + return abstractSlider()->minimum(); +} + +QAbstractSlider *QAccessibleAbstractSlider::abstractSlider() const +{ + return static_cast<QAbstractSlider *>(object()); +} + +#endif // QT_NO_SLIDER + +#ifndef QT_NO_DIAL +// ======================================= QAccessibleDial ====================================== +QAccessibleDial::QAccessibleDial(QWidget *widget) + : QAccessibleWidgetEx(widget, Dial) +{ + Q_ASSERT(qobject_cast<QDial *>(widget)); + addControllingSignal(QLatin1String("valueChanged(int)")); +} + +QRect QAccessibleDial::rect(int child) const +{ + QRect rect; + if (!dial()->isVisible()) + return rect; + switch (child) { + case Self: + return QAccessibleWidgetEx::rect(child); + case SpeedoMeter: { + // Mixture from qcommonstyle.cpp (focus rect). + int width = dial()->width(); + int height = dial()->height(); + qreal radius = qMin(width, height) / 2.0; + qreal delta = radius / 6.0; + qreal dx = delta + (width - 2 * radius) / 2.0; + qreal dy = delta + (height - 2 * radius) / 2.0; + rect = QRect(int(dx), int(dy), int(radius * 2 - 2 * delta), int(radius * 2 - 2 * delta)); + if (dial()->notchesVisible()) { + rect.translate(int(-radius / 6), int(-radius / 6)); + rect.setWidth(rect.width() + int(radius / 3)); + rect.setHeight(rect.height() + int(radius / 3)); + } + break; + } + case SliderHandle: { + // Mixture from qcommonstyle.cpp and qdial.cpp. + int sliderValue = !dial()->invertedAppearance() ? dial()->value() + : (dial()->maximum() - dial()->value()); + qreal angle = 0; + if (dial()->maximum() == dial()->minimum()) { + angle = Q_PI / 2; + } else if (dial()->wrapping()) { + angle = Q_PI * 3 / 2 - (sliderValue - dial()->minimum()) * 2 * Q_PI + / (dial()->maximum() - dial()->minimum()); + } else { + angle = (Q_PI * 8 - (sliderValue - dial()->minimum()) * 10 * Q_PI + / (dial()->maximum() - dial()->minimum())) / 6; + } + + int width = dial()->rect().width(); + int height = dial()->rect().height(); + int radius = qMin(width, height) / 2; + int xc = width / 2; + int yc = height / 2; + int bigLineSize = radius / 6; + if (bigLineSize < 4) + bigLineSize = 4; + if (bigLineSize > radius / 2) + bigLineSize = radius / 2; + int len = radius - bigLineSize - 5; + if (len < 5) + len = 5; + int back = len / 2; + + QPolygonF arrow(3); + arrow[0] = QPointF(0.5 + xc + len * qCos(angle), + 0.5 + yc - len * qSin(angle)); + arrow[1] = QPointF(0.5 + xc + back * qCos(angle + Q_PI * 5 / 6), + 0.5 + yc - back * qSin(angle + Q_PI * 5 / 6)); + arrow[2] = QPointF(0.5 + xc + back * qCos(angle - Q_PI * 5 / 6), + 0.5 + yc - back * qSin(angle - Q_PI * 5 / 6)); + rect = arrow.boundingRect().toRect(); + break; + } + default: + return QRect(); + } + + QPoint globalPos = dial()->mapToGlobal(QPoint(0,0)); + return QRect(globalPos.x() + rect.x(), globalPos.y() + rect.y(), rect.width(), rect.height()); +} + +int QAccessibleDial::childCount() const +{ + if (!dial()->isVisible()) + return 0; + return SliderHandle; +} + +QString QAccessibleDial::text(Text textType, int child) const +{ + if (!dial()->isVisible()) + return QString(); + if (textType == Value && child >= Self && child <= SliderHandle) + return QString::number(dial()->value()); + if (textType == Name) { + switch (child) { + case Self: + if (!widget()->accessibleName().isEmpty()) + return widget()->accessibleName(); + return QDial::tr("QDial"); + case SpeedoMeter: + return QDial::tr("SpeedoMeter"); + case SliderHandle: + return QDial::tr("SliderHandle"); + } + } + return QAccessibleWidgetEx::text(textType, child); +} + +QAccessible::Role QAccessibleDial::role(int child) const +{ + if (child == SpeedoMeter) + return Slider; + else if (child == SliderHandle) + return Indicator; + return QAccessibleWidgetEx::role(child); +} + +QAccessible::State QAccessibleDial::state(int child) const +{ + const State parentState = QAccessibleWidgetEx::state(0); + if (child == SliderHandle) + return parentState | HotTracked; + return parentState; +} + +QVariant QAccessibleDial::invokeMethodEx(Method, int, const QVariantList &) +{ + return QVariant(); +} + +QDial *QAccessibleDial::dial() const +{ + return static_cast<QDial*>(object()); +} +#endif // QT_NO_DIAL + +#endif // QT_NO_ACCESSIBILITY + +QT_END_NAMESPACE diff --git a/src/plugins/accessible/widgets/rangecontrols.h b/src/plugins/accessible/widgets/rangecontrols.h new file mode 100644 index 0000000..aea91e1 --- /dev/null +++ b/src/plugins/accessible/widgets/rangecontrols.h @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef RANGECONTROLS_H +#define RANGECONTROLS_H + +#include <QtGui/qaccessiblewidget.h> +#include <QtGui/qaccessible2.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_ACCESSIBILITY + +class QAbstractSpinBox; +class QAbstractSlider; +class QScrollBar; +class QSlider; +class QSpinBox; +class QDoubleSpinBox; +class QDial; + +#ifndef QT_NO_SPINBOX +class QAccessibleAbstractSpinBox: public QAccessibleWidgetEx, public QAccessibleValueInterface +{ +public: + explicit QAccessibleAbstractSpinBox(QWidget *w); + + enum SpinBoxElements { + SpinBoxSelf = 0, + Editor, + ValueUp, + ValueDown + }; + + int childCount() const; + QRect rect(int child) const; + + int navigate(RelationFlag rel, int entry, QAccessibleInterface **target) const; + + QString text(Text t, int child) const; + Role role(int child) const; + + bool doAction(int action, int child, const QVariantList ¶ms); + + QVariant invokeMethodEx(Method method, int child, const QVariantList ¶ms); + + // QAccessibleValueInterface + QVariant currentValue(); + void setCurrentValue(const QVariant &value); + QVariant maximumValue(); + QVariant minimumValue(); + +protected: + QAbstractSpinBox *abstractSpinBox() const; +}; + +class QAccessibleSpinBox : public QAccessibleAbstractSpinBox +{ +public: + explicit QAccessibleSpinBox(QWidget *w); + + State state(int child) const; + + bool doAction(int action, int child, const QVariantList ¶ms); + +protected: + QSpinBox *spinBox() const; +}; + +class QAccessibleDoubleSpinBox : public QAccessibleWidgetEx +{ +public: + explicit QAccessibleDoubleSpinBox(QWidget *widget); + + enum DoubleSpinBoxElements { + SpinBoxSelf = 0, + Editor, + ValueUp, + ValueDown + }; + + int childCount() const; + QRect rect(int child) const; + int navigate(RelationFlag rel, int entry, QAccessibleInterface **target) const; + QVariant invokeMethodEx(QAccessible::Method method, int child, const QVariantList ¶ms); + QString text(Text t, int child) const; + Role role(int child) const; + State state(int child) const; + +protected: + QDoubleSpinBox *doubleSpinBox() const; +}; +#endif // QT_NO_SPINBOX + +class QAccessibleAbstractSlider: public QAccessibleWidgetEx, public QAccessibleValueInterface +{ +public: + explicit QAccessibleAbstractSlider(QWidget *w, Role r = Slider); + + QVariant invokeMethodEx(Method method, int child, const QVariantList ¶ms); + + // QAccessibleValueInterface + QVariant currentValue(); + void setCurrentValue(const QVariant &value); + QVariant maximumValue(); + QVariant minimumValue(); + +protected: + QAbstractSlider *abstractSlider() const; +}; + +#ifndef QT_NO_SCROLLBAR +class QAccessibleScrollBar : public QAccessibleAbstractSlider +{ +public: + explicit QAccessibleScrollBar(QWidget *w); + + enum ScrollBarElements { + ScrollBarSelf = 0, + LineUp, + PageUp, + Position, + PageDown, + LineDown + }; + + int childCount() const; + + QRect rect(int child) const; + QString text(Text t, int child) const; + Role role(int child) const; + State state(int child) const; + +protected: + QScrollBar *scrollBar() const; +}; +#endif // QT_NO_SCROLLBAR + +#ifndef QT_NO_SLIDER +class QAccessibleSlider : public QAccessibleAbstractSlider +{ +public: + explicit QAccessibleSlider(QWidget *w); + + enum SliderElements { + SliderSelf = 0, + PageLeft, + Position, + PageRight + }; + + int childCount() const; + + QRect rect(int child) const; + QString text(Text t, int child) const; + Role role(int child) const; + State state(int child) const; + + int defaultAction(int child) const; + QString actionText(int action, Text t, int child) const; + +protected: + QSlider *slider() const; +}; +#endif // QT_NO_SLIDER + +#ifndef QT_NO_DIAL +class QAccessibleDial : public QAccessibleWidgetEx +{ +public: + explicit QAccessibleDial(QWidget *w); + + enum DialElements { + Self = 0, + SpeedoMeter, + SliderHandle + }; + + int childCount() const; + QRect rect(int child) const; + QString text(Text textType, int child) const; + Role role(int child) const; + State state(int child) const; + QVariant invokeMethodEx(Method method, int child, const QVariantList ¶ms); + +protected: + QDial *dial() const; +}; +#endif // QT_NO_DIAL + +#endif // QT_NO_ACCESSIBILITY + +QT_END_NAMESPACE + +#endif // RANGECONTROLS_H diff --git a/src/plugins/accessible/widgets/simplewidgets.cpp b/src/plugins/accessible/widgets/simplewidgets.cpp new file mode 100644 index 0000000..e629505 --- /dev/null +++ b/src/plugins/accessible/widgets/simplewidgets.cpp @@ -0,0 +1,762 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "simplewidgets.h" + +#include <qabstractbutton.h> +#include <qcheckbox.h> +#include <qpushbutton.h> +#include <qprogressbar.h> +#include <qradiobutton.h> +#include <qtoolbutton.h> +#include <qlabel.h> +#include <qgroupbox.h> +#include <qlcdnumber.h> +#include <qlineedit.h> +#include <qstyle.h> +#include <qstyleoption.h> + +#ifdef Q_OS_MAC +#include <qfocusframe.h> +#endif + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_ACCESSIBILITY + +using namespace QAccessible2; +extern QList<QWidget*> childWidgets(const QWidget *widget, bool includeTopLevel = false); + +QString Q_GUI_EXPORT qt_accStripAmp(const QString &text); +QString Q_GUI_EXPORT qt_accHotKey(const QString &text); + +/*! + \class QAccessibleButton + \brief The QAccessibleButton class implements the QAccessibleInterface for button type widgets. + \internal + + \ingroup accessibility +*/ + +/*! + Creates a QAccessibleButton object for \a w. + \a role is propagated to the QAccessibleWidgetEx constructor. +*/ +QAccessibleButton::QAccessibleButton(QWidget *w, Role role) +: QAccessibleWidgetEx(w, role) +{ + Q_ASSERT(button()); + if (button()->isCheckable()) + addControllingSignal(QLatin1String("toggled(bool)")); + else + addControllingSignal(QLatin1String("clicked()")); +} + +/*! Returns the button. */ +QAbstractButton *QAccessibleButton::button() const +{ + return qobject_cast<QAbstractButton*>(object()); +} + +/*! \reimp */ +QString QAccessibleButton::actionText(int action, Text text, int child) const +{ + if (child) + return QString(); + + if (text == Name) switch (action) { + case Press: + case DefaultAction: // press, checking or open + switch (role(0)) { + case ButtonMenu: + return QPushButton::tr("Open"); + case CheckBox: + { + if (state(child) & Checked) + return QCheckBox::tr("Uncheck"); + QCheckBox *cb = qobject_cast<QCheckBox*>(object()); + if (!cb || !cb->isTristate() || cb->checkState() == Qt::PartiallyChecked) + return QCheckBox::tr("Check"); + return QCheckBox::tr("Toggle"); + } + break; + case RadioButton: + return QRadioButton::tr("Check"); + default: + break; + } + break; + } + return QAccessibleWidgetEx::actionText(action, text, child); +} + +/*! \reimp */ +bool QAccessibleButton::doAction(int action, int child, const QVariantList ¶ms) +{ + if (child || !widget()->isEnabled() || !widget()->isVisible()) + return false; + + switch (action) { + case DefaultAction: + case Press: + { +#ifndef QT_NO_MENU + QPushButton *pb = qobject_cast<QPushButton*>(object()); + if (pb && pb->menu()) + pb->showMenu(); + else +#endif + button()->animateClick(); + } + return true; + } + return QAccessibleWidgetEx::doAction(action, child, params); +} + +/*! \reimp */ +QString QAccessibleButton::text(Text t, int child) const +{ + QString str; + if (!widget()->isVisible()) + return str; + + switch (t) { + case Accelerator: + { +#ifndef QT_NO_SHORTCUT + QPushButton *pb = qobject_cast<QPushButton*>(object()); + if (pb && pb->isDefault()) + str = (QString)QKeySequence(Qt::Key_Enter); +#endif + if (str.isEmpty()) + str = qt_accHotKey(button()->text()); + } + break; + case Name: + str = widget()->accessibleName(); + if (str.isEmpty()) + str = button()->text(); + break; + default: + break; + } + if (str.isEmpty()) + str = QAccessibleWidgetEx::text(t, child);; + return qt_accStripAmp(str); +} + +/*! \reimp */ +QAccessible::State QAccessibleButton::state(int child) const +{ + State state = QAccessibleWidgetEx::state(child); + + QAbstractButton *b = button(); + QCheckBox *cb = qobject_cast<QCheckBox *>(b); + if (b->isChecked()) + state |= Checked; + else if (cb && cb->checkState() == Qt::PartiallyChecked) + state |= Mixed; + if (b->isDown()) + state |= Pressed; + QPushButton *pb = qobject_cast<QPushButton*>(b); + if (pb) { + if (pb->isDefault()) + state |= DefaultButton; +#ifndef QT_NO_MENU + if (pb->menu()) + state |= HasPopup; +#endif + } + + return state; +} + +#ifndef QT_NO_TOOLBUTTON +/*! + \class QAccessibleToolButton + \brief The QAccessibleToolButton class implements the QAccessibleInterface for tool buttons. + \internal + + \ingroup accessibility +*/ + +/*! + \enum QAccessibleToolButton::ToolButtonElements + + This enum identifies the components of the tool button. + + \value ToolButtonSelf The tool button as a whole. + \value ButtonExecute The button. + \value ButtonDropMenu The drop down menu. +*/ + +/*! + Creates a QAccessibleToolButton object for \a w. + \a role is propagated to the QAccessibleWidgetEx constructor. +*/ +QAccessibleToolButton::QAccessibleToolButton(QWidget *w, Role role) +: QAccessibleButton(w, role) +{ + Q_ASSERT(toolButton()); +} + +/*! Returns the button. */ +QToolButton *QAccessibleToolButton::toolButton() const +{ + return qobject_cast<QToolButton*>(object()); +} + +/*! + Returns true if this tool button is a split button. +*/ +bool QAccessibleToolButton::isSplitButton() const +{ +#ifndef QT_NO_MENU + return toolButton()->menu() && toolButton()->popupMode() == QToolButton::MenuButtonPopup; +#else + return false; +#endif +} + +/*! \reimp */ +QAccessible::Role QAccessibleToolButton::role(int child) const +{ + if (isSplitButton()) switch(child) { + case ButtonExecute: + return PushButton; + case ButtonDropMenu: + return ButtonMenu; + } + return QAccessibleButton::role(child); +} + +/*! \reimp */ +QAccessible::State QAccessibleToolButton::state(int child) const +{ + QAccessible::State st = QAccessibleButton::state(child); + if (toolButton()->autoRaise()) + st |= HotTracked; +#ifndef QT_NO_MENU + if (toolButton()->menu() && child != ButtonExecute) + st |= HasPopup; +#endif + return st; +} + +/*! \reimp */ +int QAccessibleToolButton::childCount() const +{ + if (!toolButton()->isVisible()) + return 0; + return isSplitButton() ? ButtonDropMenu : 0; +} + +/*! + \internal + + Returns the rectangle occupied by this button, depending on \a + child. +*/ +QRect QAccessibleToolButton::rect(int child) const +{ + if (!toolButton()->isVisible()) + return QRect(); + if (!child) + return QAccessibleButton::rect(child); + + QStyleOptionToolButton opt; + opt.init(widget()); + QRect subrect = widget()->style()->subControlRect(QStyle::CC_ToolButton, &opt, + QStyle::SC_ToolButtonMenu, toolButton()); + + if (child == ButtonExecute) + subrect = QRect(0, 0, subrect.x(), widget()->height()); + + QPoint ntl = widget()->mapToGlobal(subrect.topLeft()); + subrect.moveTopLeft(ntl); + return subrect; +} + +/*! + \internal + + Returns the button's text label, depending on the text \a t, and + the \a child. +*/ +QString QAccessibleToolButton::text(Text t, int child) const +{ + QString str; + if (!toolButton()->isVisible()) + return str; + + switch (t) { + case Name: + str = toolButton()->text(); + if (str.isEmpty()) + str = toolButton()->text(); + break; + default: + break; + } + if (str.isEmpty()) + str = QAccessibleButton::text(t, child);; + return qt_accStripAmp(str); +} + +/*! + \internal + + Returns the number of actions which is 0, 1, or 2, in part + depending on \a child. +*/ +int QAccessibleToolButton::actionCount(int child) const +{ + // each subelement has one action + if (child) + return isSplitButton() ? 1 : 0; + int ac = widget()->focusPolicy() != Qt::NoFocus ? 1 : 0; + // button itself has two actions if a menu button +#ifndef QT_NO_MENU + return ac + (toolButton()->menu() ? 2 : 1); +#else + return ac + 1; +#endif +} + +/*! + \internal + + If \a text is \c Name, then depending on the \a child or the \a + action, an action text is returned. This is a translated string + which in English is one of "Press", "Open", or "Set Focus". If \a + text is not \c Name, an empty string is returned. +*/ +QString QAccessibleToolButton::actionText(int action, Text text, int child) const +{ + if (text == Name) switch(child) { + case ButtonExecute: + return QToolButton::tr("Press"); + case ButtonDropMenu: + return QToolButton::tr("Open"); + default: + switch(action) { + case 0: + return QToolButton::tr("Press"); + case 1: +#ifndef QT_NO_MENU + if (toolButton()->menu()) + return QToolButton::tr("Open"); +#endif + //fall through + case 2: + return QLatin1String("Set Focus"); + } + } + return QString(); +} + +/*! + \internal +*/ +bool QAccessibleToolButton::doAction(int action, int child, const QVariantList ¶ms) +{ + if (!widget()->isEnabled() || !widget()->isVisible()) + return false; + if (action == 1 || child == ButtonDropMenu) { + if(!child) + toolButton()->setDown(true); +#ifndef QT_NO_MENU + toolButton()->showMenu(); +#endif + return true; + } + return QAccessibleButton::doAction(action, 0, params); +} + +#endif // QT_NO_TOOLBUTTON + +/*! + \class QAccessibleDisplay + \brief The QAccessibleDisplay class implements the QAccessibleInterface for widgets that display information. + \internal + + \ingroup accessibility +*/ + +/*! + Constructs a QAccessibleDisplay object for \a w. + \a role is propagated to the QAccessibleWidgetEx constructor. +*/ +QAccessibleDisplay::QAccessibleDisplay(QWidget *w, Role role) +: QAccessibleWidgetEx(w, role) +{ +} + +/*! \reimp */ +QAccessible::Role QAccessibleDisplay::role(int child) const +{ + QLabel *l = qobject_cast<QLabel*>(object()); + if (l) { + if (l->pixmap()) + return Graphic; +#ifndef QT_NO_PICTURE + if (l->picture()) + return Graphic; +#endif +#ifndef QT_NO_MOVIE + if (l->movie()) + return Animation; +#endif +#ifndef QT_NO_PROGRESSBAR + } else if (qobject_cast<QProgressBar*>(object())) { + return ProgressBar; +#endif + } + return QAccessibleWidgetEx::role(child); +} + +/*! \reimp */ +QString QAccessibleDisplay::text(Text t, int child) const +{ + QString str; + if (!widget()->isVisible()) + return str; + switch (t) { + case Name: + str = widget()->accessibleName(); + if (str.isEmpty()) { + if (qobject_cast<QLabel*>(object())) { + str = qobject_cast<QLabel*>(object())->text(); +#ifndef QT_NO_GROUPBOX + } else if (qobject_cast<QGroupBox*>(object())) { + str = qobject_cast<QGroupBox*>(object())->title(); +#endif +#ifndef QT_NO_LCDNUMBER + } else if (qobject_cast<QLCDNumber*>(object())) { + QLCDNumber *l = qobject_cast<QLCDNumber*>(object()); + if (l->numDigits()) + str = QString::number(l->value()); + else + str = QString::number(l->intValue()); +#endif + } + } + break; + case Value: +#ifndef QT_NO_PROGRESSBAR + if (qobject_cast<QProgressBar*>(object())) + str = QString::number(qobject_cast<QProgressBar*>(object())->value()); +#endif + break; + default: + break; + } + if (str.isEmpty()) + str = QAccessibleWidgetEx::text(t, child);; + return qt_accStripAmp(str); +} + +/*! \reimp */ +QAccessible::Relation QAccessibleDisplay::relationTo(int child, const QAccessibleInterface *other, + int otherChild) const +{ + Relation relation = QAccessibleWidgetEx::relationTo(child, other, otherChild); + if (child || otherChild) + return relation; + + QObject *o = other->object(); + QLabel *label = qobject_cast<QLabel*>(object()); + if (label) { +#ifndef QT_NO_SHORTCUT + if (o == label->buddy()) + relation |= Label; +#endif +#ifndef QT_NO_GROUPBOX + } else { + QGroupBox *groupbox = qobject_cast<QGroupBox*>(object()); + if (groupbox && !groupbox->title().isEmpty()) + if (groupbox->children().contains(o)) + relation |= Label; +#endif + } + return relation; +} + +/*! \reimp */ +int QAccessibleDisplay::navigate(RelationFlag rel, int entry, QAccessibleInterface **target) const +{ + *target = 0; + if (rel == Labelled) { + QObject *targetObject = 0; + QLabel *label = qobject_cast<QLabel*>(object()); + if (label) { +#ifndef QT_NO_SHORTCUT + if (entry == 1) + targetObject = label->buddy(); +#endif +#ifndef QT_NO_GROUPBOX + } else { + QGroupBox *groupbox = qobject_cast<QGroupBox*>(object()); + if (groupbox && !groupbox->title().isEmpty()) + rel = Child; +#endif + } + *target = QAccessible::queryAccessibleInterface(targetObject); + if (*target) + return 0; + } + return QAccessibleWidgetEx::navigate(rel, entry, target); +} + +#ifndef QT_NO_LINEEDIT +/*! + \class QAccessibleLineEdit + \brief The QAccessibleLineEdit class implements the QAccessibleInterface for widgets with editable text + \internal + + \ingroup accessibility +*/ + +/*! + Constructs a QAccessibleLineEdit object for \a w. + \a name is propagated to the QAccessibleWidgetEx constructor. +*/ +QAccessibleLineEdit::QAccessibleLineEdit(QWidget *w, const QString &name) +: QAccessibleWidgetEx(w, EditableText, name), QAccessibleSimpleEditableTextInterface(this) +{ + addControllingSignal(QLatin1String("textChanged(const QString&)")); + addControllingSignal(QLatin1String("returnPressed()")); +} + +/*! Returns the line edit. */ +QLineEdit *QAccessibleLineEdit::lineEdit() const +{ + return qobject_cast<QLineEdit*>(object()); +} + +/*! \reimp */ +QString QAccessibleLineEdit::text(Text t, int child) const +{ + QString str; + if (!lineEdit()->isVisible()) + return str; + switch (t) { + case Value: + if (lineEdit()->echoMode() == QLineEdit::Normal) + str = lineEdit()->text(); + break; + default: + break; + } + if (str.isEmpty()) + str = QAccessibleWidgetEx::text(t, child);; + return qt_accStripAmp(str); +} + +/*! \reimp */ +void QAccessibleLineEdit::setText(Text t, int control, const QString &text) +{ + if (!lineEdit()->isVisible()) + return; + if (t != Value || control) { + QAccessibleWidgetEx::setText(t, control, text); + return; + } + lineEdit()->setText(text); +} + +/*! \reimp */ +QAccessible::State QAccessibleLineEdit::state(int child) const +{ + State state = QAccessibleWidgetEx::state(child); + + QLineEdit *l = lineEdit(); + if (l->isReadOnly()) + state |= ReadOnly; + if (l->echoMode() != QLineEdit::Normal) + state |= Protected; + state |= Selectable; + if (l->hasSelectedText()) + state |= Selected; + + if (l->contextMenuPolicy() != Qt::NoContextMenu + && l->contextMenuPolicy() != Qt::PreventContextMenu) + state |= HasPopup; + + return state; +} + +QVariant QAccessibleLineEdit::invokeMethodEx(QAccessible::Method method, int child, + const QVariantList ¶ms) +{ + if (child) + return QVariant(); + + switch (method) { + case ListSupportedMethods: { + QSet<QAccessible::Method> set; + set << ListSupportedMethods << SetCursorPosition << GetCursorPosition; + return qVariantFromValue(set | qvariant_cast<QSet<QAccessible::Method> >( + QAccessibleWidgetEx::invokeMethodEx(method, child, params))); + } + case SetCursorPosition: + setCursorPosition(params.value(0).toInt()); + return true; + case GetCursorPosition: + return cursorPosition(); + default: + return QAccessibleWidgetEx::invokeMethodEx(method, child, params); + } +} + +void QAccessibleLineEdit::addSelection(int startOffset, int endOffset) +{ + setSelection(0, startOffset, endOffset); +} + +QString QAccessibleLineEdit::attributes(int offset, int *startOffset, int *endOffset) +{ + // QLineEdit doesn't have text attributes + *startOffset = *endOffset = offset; + return QString(); +} + +int QAccessibleLineEdit::cursorPosition() +{ + return lineEdit()->cursorPosition(); +} + +QRect QAccessibleLineEdit::characterRect(int /*offset*/, CoordinateType /*coordType*/) +{ + // QLineEdit doesn't hand out character rects + return QRect(); +} + +int QAccessibleLineEdit::selectionCount() +{ + return lineEdit()->hasSelectedText() ? 1 : 0; +} + +int QAccessibleLineEdit::offsetAtPoint(const QPoint &point, CoordinateType coordType) +{ + QPoint p = point; + if (coordType == RelativeToScreen) + p = lineEdit()->mapFromGlobal(p); + + return lineEdit()->cursorPositionAt(p); +} + +void QAccessibleLineEdit::selection(int selectionIndex, int *startOffset, int *endOffset) +{ + *startOffset = *endOffset = 0; + if (selectionIndex != 0) + return; + + *startOffset = lineEdit()->selectionStart(); + *endOffset = *startOffset + lineEdit()->selectedText().count(); +} + +QString QAccessibleLineEdit::text(int startOffset, int endOffset) +{ + if (startOffset > endOffset) + return QString(); + return lineEdit()->text().mid(startOffset, endOffset - startOffset); +} + +QString QAccessibleLineEdit::textBeforeOffset (int /*offset*/, BoundaryType /*boundaryType*/, + int * /*startOffset*/, int * /*endOffset*/) +{ + // TODO + return QString(); +} + +QString QAccessibleLineEdit::textAfterOffset(int /*offset*/, BoundaryType /*boundaryType*/, + int * /*startOffset*/, int * /*endOffset*/) +{ + // TODO + return QString(); +} + +QString QAccessibleLineEdit::textAtOffset(int /*offset*/, BoundaryType /*boundaryType*/, + int * /*startOffset*/, int * /*endOffset*/) +{ + // TODO + return QString(); +} + +void QAccessibleLineEdit::removeSelection(int selectionIndex) +{ + if (selectionIndex != 0) + return; + + lineEdit()->deselect(); +} + +void QAccessibleLineEdit::setCursorPosition(int position) +{ + lineEdit()->setCursorPosition(position); +} + +void QAccessibleLineEdit::setSelection(int selectionIndex, int startOffset, int endOffset) +{ + if (selectionIndex != 0) + return; + + lineEdit()->setSelection(startOffset, endOffset - startOffset); +} + +int QAccessibleLineEdit::characterCount() +{ + return lineEdit()->text().count(); +} + +void QAccessibleLineEdit::scrollToSubstring(int startIndex, int endIndex) +{ + lineEdit()->setCursorPosition(endIndex); + lineEdit()->setCursorPosition(startIndex); +} + +#endif // QT_NO_LINEEDIT + +#endif // QT_NO_ACCESSIBILITY + +QT_END_NAMESPACE + diff --git a/src/plugins/accessible/widgets/simplewidgets.h b/src/plugins/accessible/widgets/simplewidgets.h new file mode 100644 index 0000000..d4552e3 --- /dev/null +++ b/src/plugins/accessible/widgets/simplewidgets.h @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIMPLEWIDGETS_H +#define SIMPLEWIDGETS_H + +#include <QtGui/qaccessible2.h> +#include <QtGui/qaccessiblewidget.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_ACCESSIBILITY + +class QAbstractButton; +class QLineEdit; +class QToolButton; + +class QAccessibleButton : public QAccessibleWidgetEx +{ +public: + QAccessibleButton(QWidget *w, Role r); + + QString text(Text t, int child) const; + State state(int child) const; + + QString actionText(int action, Text text, int child) const; + bool doAction(int action, int child, const QVariantList ¶ms); + +protected: + QAbstractButton *button() const; +}; + +#ifndef QT_NO_TOOLBUTTON +class QAccessibleToolButton : public QAccessibleButton +{ +public: + QAccessibleToolButton(QWidget *w, Role role); + + enum ToolButtonElements { + ToolButtonSelf = 0, + ButtonExecute, + ButtonDropMenu + }; + + Role role(int child) const; + State state(int child) const; + + int childCount() const; + QRect rect(int child) const; + + QString text(Text t, int child) const; + + int actionCount(int child) const; + QString actionText(int action, Text text, int child) const; + bool doAction(int action, int child, const QVariantList ¶ms); + +protected: + QToolButton *toolButton() const; + + bool isSplitButton() const; +}; +#endif // QT_NO_TOOLBUTTON + +class QAccessibleDisplay : public QAccessibleWidgetEx +{ +public: + explicit QAccessibleDisplay(QWidget *w, Role role = StaticText); + + QString text(Text t, int child) const; + Role role(int child) const; + + Relation relationTo(int child, const QAccessibleInterface *other, int otherChild) const; + int navigate(RelationFlag, int entry, QAccessibleInterface **target) const; +}; + +#ifndef QT_NO_LINEEDIT +class QAccessibleLineEdit : public QAccessibleWidgetEx, public QAccessibleTextInterface, + public QAccessibleSimpleEditableTextInterface +{ +public: + explicit QAccessibleLineEdit(QWidget *o, const QString &name = QString()); + + QString text(Text t, int child) const; + void setText(Text t, int control, const QString &text); + State state(int child) const; + QVariant invokeMethodEx(QAccessible::Method method, int child, const QVariantList ¶ms); + + // QAccessibleTextInterface + void addSelection(int startOffset, int endOffset); + QString attributes(int offset, int *startOffset, int *endOffset); + int cursorPosition(); + QRect characterRect(int offset, QAccessible2::CoordinateType coordType); + int selectionCount(); + int offsetAtPoint(const QPoint &point, QAccessible2::CoordinateType coordType); + void selection(int selectionIndex, int *startOffset, int *endOffset); + QString text(int startOffset, int endOffset); + QString textBeforeOffset (int offset, QAccessible2::BoundaryType boundaryType, + int *startOffset, int *endOffset); + QString textAfterOffset(int offset, QAccessible2::BoundaryType boundaryType, + int *startOffset, int *endOffset); + QString textAtOffset(int offset, QAccessible2::BoundaryType boundaryType, + int *startOffset, int *endOffset); + void removeSelection(int selectionIndex); + void setCursorPosition(int position); + void setSelection(int selectionIndex, int startOffset, int endOffset); + int characterCount(); + void scrollToSubstring(int startIndex, int endIndex); + +protected: + QLineEdit *lineEdit() const; +}; +#endif // QT_NO_LINEEDIT + +#endif // QT_NO_ACCESSIBILITY + +QT_END_NAMESPACE + +#endif // SIMPLEWIDGETS_H diff --git a/src/plugins/accessible/widgets/widgets.pro b/src/plugins/accessible/widgets/widgets.pro new file mode 100644 index 0000000..79110cb --- /dev/null +++ b/src/plugins/accessible/widgets/widgets.pro @@ -0,0 +1,20 @@ +TARGET = qtaccessiblewidgets +include(../../qpluginbase.pri) +include (../qaccessiblebase.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/accessible + +QTDIR_build:REQUIRES += "contains(QT_CONFIG, accessibility)" + +SOURCES += main.cpp \ + simplewidgets.cpp \ + rangecontrols.cpp \ + complexwidgets.cpp \ + qaccessiblewidgets.cpp \ + qaccessiblemenu.cpp + +HEADERS += qaccessiblewidgets.h \ + simplewidgets.h \ + rangecontrols.h \ + complexwidgets.h \ + qaccessiblemenu.h |