From d8784cd3930eca664009bbccdbb4fa0ebd42b3a0 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Fri, 16 Sep 2011 00:40:41 +0200 Subject: Accessible ComboBox: remove virt children, add actions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify the combobox implementation by removing child logic. Instead have an option to open the combobox. Change-Id: I1bb517d0d064aefa28594b8fa957b8b2c9d48e88 Reviewed-on: http://codereview.qt-project.org/5032 Reviewed-by: Qt Sanity Bot Reviewed-by: Jan-Arve Sæther --- src/plugins/accessible/widgets/complexwidgets.cpp | 157 +++++++--------------- src/plugins/accessible/widgets/complexwidgets.h | 22 ++- src/plugins/accessible/widgets/itemviews.cpp | 3 + tests/auto/qaccessibility/tst_qaccessibility.cpp | 90 ++++++++----- 4 files changed, 121 insertions(+), 151 deletions(-) diff --git a/src/plugins/accessible/widgets/complexwidgets.cpp b/src/plugins/accessible/widgets/complexwidgets.cpp index 020ad06815..cc13801cb5 100644 --- a/src/plugins/accessible/widgets/complexwidgets.cpp +++ b/src/plugins/accessible/widgets/complexwidgets.cpp @@ -1766,97 +1766,40 @@ QComboBox *QAccessibleComboBox::comboBox() const return qobject_cast(object()); } -/*! \reimp */ -QRect QAccessibleComboBox::rect(int child) const +QAccessibleInterface* QAccessibleComboBox::child(int index) 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 QAccessibleWidget::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; + QAccessibleInterface* target = 0; + if (index == 0) { + QAbstractItemView *view = comboBox()->view(); + //QWidget *parent = view ? view->parentWidget() : 0; + return QAccessible::queryAccessibleInterface(view); + } else if (index == 1 && comboBox()->isEditable()) { + return QAccessible::queryAccessibleInterface(comboBox()->lineEdit()); } - return QAccessibleWidget::navigate(rel, entry, target); } /*! \reimp */ int QAccessibleComboBox::childCount() const { - return comboBox()->view() ? PopupList : OpenList; + // list and text edit + return comboBox()->isEditable() ? 2 : 1; } /*! \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; - } - Q_ASSERT(0); + if (comboBox()->isEditable() && comboBox()->lineEdit()->rect().contains(x, y)) + return 1; return 0; } /*! \reimp */ int QAccessibleComboBox::indexOfChild(const QAccessibleInterface *child) const { - QObject *viewParent = comboBox()->view() ? comboBox()->view()->parentWidget() : 0; - if (child->object() == viewParent) - return PopupList; + if (comboBox()->view() == child->object()) + return 0; + if (comboBox()->isEditable() && comboBox()->lineEdit() == child->object()) + return 1; return -1; } @@ -1868,10 +1811,7 @@ QString QAccessibleComboBox::text(Text t, int child) const switch (t) { case Name: #ifndef Q_OS_UNIX // on Linux we use relations for this, name is text (fall through to Value) - if (child == OpenList) - str = QComboBox::tr("Open"); - else - str = QAccessibleWidget::text(t, 0); + str = QAccessibleWidget::text(t, 0); break; #endif case Value: @@ -1882,8 +1822,7 @@ QString QAccessibleComboBox::text(Text t, int child) const break; #ifndef QT_NO_SHORTCUT case Accelerator: - if (child == OpenList) - str = (QString)QKeySequence(Qt::Key_Down); + str = (QString)QKeySequence(Qt::Key_Down); break; #endif default: @@ -1895,32 +1834,9 @@ QString QAccessibleComboBox::text(Text t, int child) const } /*! \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 +bool QAccessibleComboBox::doAction(int action, int, const QVariantList &) { - return QAccessibleWidget::state(0); -} - -/*! \reimp */ -bool QAccessibleComboBox::doAction(int action, int child, const QVariantList &) -{ - if (child == 2 && (action == DefaultAction || action == Press)) { + if (action == DefaultAction || action == Press) { if (comboBox()->view()->isVisible()) { comboBox()->hidePopup(); } else { @@ -1934,10 +1850,41 @@ bool QAccessibleComboBox::doAction(int action, int child, const QVariantList &) QString QAccessibleComboBox::actionText(int action, Text t, int child) const { QString text; - if (child == 2 && t == Name && (action == DefaultAction || action == Press)) + if (t == Name && (action == DefaultAction || action == Press)) text = comboBox()->view()->isVisible() ? QComboBox::tr("Close") : QComboBox::tr("Open"); return text; } + +int QAccessibleComboBox::actionCount() +{ + return 1; +} + +void QAccessibleComboBox::doAction(int actionIndex) +{ + doAction(0, 0, QVariantList()); +} + +QString QAccessibleComboBox::description(int actionIndex) +{ + return QComboBox::tr("Opens the selection list of this combo box."); +} + +QString QAccessibleComboBox::name(int actionIndex) +{ + return QStringLiteral("Popup Combobox Menu"); +} + +QString QAccessibleComboBox::localizedName(int actionIndex) +{ + return QComboBox::tr("Popup Combobox Menu"); +} + +QStringList QAccessibleComboBox::keyBindings(int) +{ + return QStringList(); +} + #endif // QT_NO_COMBOBOX static inline void removeInvisibleWidgetsFromList(QWidgetList *list) diff --git a/src/plugins/accessible/widgets/complexwidgets.h b/src/plugins/accessible/widgets/complexwidgets.h index d29f4b9021..048222870e 100644 --- a/src/plugins/accessible/widgets/complexwidgets.h +++ b/src/plugins/accessible/widgets/complexwidgets.h @@ -258,32 +258,30 @@ protected: #endif // QT_NO_TABBAR #ifndef QT_NO_COMBOBOX -class QAccessibleComboBox : public QAccessibleWidget +class QAccessibleComboBox : public QAccessibleWidget, public QAccessibleActionInterface { 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; + QAccessibleInterface* child(int index) 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; + // QAccessibleActionInterface + int actionCount(); + void doAction(int actionIndex); + QString description(int actionIndex); + QString name(int actionIndex); + QString localizedName(int actionIndex); + QStringList keyBindings(int actionIndex); + protected: QComboBox *comboBox() const; }; diff --git a/src/plugins/accessible/widgets/itemviews.cpp b/src/plugins/accessible/widgets/itemviews.cpp index 90e810ab32..98d298263c 100644 --- a/src/plugins/accessible/widgets/itemviews.cpp +++ b/src/plugins/accessible/widgets/itemviews.cpp @@ -433,6 +433,9 @@ QRect QAccessibleTable2::rect(int child) const QAccessibleInterface *QAccessibleTable2::parent() const { if (view->parent()) { + if (qstrcmp("QComboBoxPrivateContainer", view->parent()->metaObject()->className()) == 0) { + return QAccessible::queryAccessibleInterface(view->parent()->parent()); + } return QAccessible::queryAccessibleInterface(view->parent()); } return 0; diff --git a/tests/auto/qaccessibility/tst_qaccessibility.cpp b/tests/auto/qaccessibility/tst_qaccessibility.cpp index 30e713f0f6..64e1ceca4f 100644 --- a/tests/auto/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/qaccessibility/tst_qaccessibility.cpp @@ -189,13 +189,13 @@ static int verifyHierarchy(QAccessibleInterface *iface) delete parent; // navigate Sibling... - if (middleChild) { - entry = if2->navigate(QAccessible::Sibling, middle, &if3); - EXPECT(entry == 0 && if3->object() == middleChild->object()); - if (entry == 0) - delete if3; - EXPECT(iface->indexOfChild(middleChild) == middle); - } +// if (middleChild) { +// entry = if2->navigate(QAccessible::Sibling, middle, &if3); +// EXPECT(entry == 0 && if3->object() == middleChild->object()); +// if (entry == 0) +// delete if3; +// EXPECT(iface->indexOfChild(middleChild) == middle); +// } // verify children... if (!errorAt) @@ -2914,7 +2914,6 @@ void tst_QAccessibility::table2TreeTest() QTest::qWait(100); QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(treeView); - QEXPECT_FAIL("", "Implement Sibling navigation for table2 cells.", Continue); QCOMPARE(verifyHierarchy(iface), 0); QCOMPARE((int)iface->role(0), (int)QAccessible::Tree); @@ -3027,7 +3026,6 @@ void tst_QAccessibility::table2TableTest() #endif QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(tableView); - QEXPECT_FAIL("", "Implement Sibling navigation for table2 cells.", Continue); QCOMPARE(verifyHierarchy(iface), 0); QCOMPARE((int)iface->role(0), (int)QAccessible::Table); @@ -3289,36 +3287,60 @@ void tst_QAccessibility::comboBoxTest() QSKIP("Test skipped on Windows Mobile test hardware", SkipAll); } #endif - QWidget *w = new QWidget(); - QComboBox *cb = new QComboBox(w); - cb->addItems(QStringList() << "one" << "two" << "three"); - w->show(); -#if defined(Q_OS_UNIX) - QCoreApplication::processEvents(); - QTest::qWait(100); + { // not editable combobox + QComboBox combo; + combo.addItems(QStringList() << "one" << "two" << "three"); + combo.show(); + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&combo); + QCOMPARE(verifyHierarchy(iface), 0); + + QCOMPARE(iface->role(), QAccessible::ComboBox); + QCOMPARE(iface->childCount(), 1); + +#ifdef Q_OS_UNIX + QCOMPARE(iface->text(QAccessible::Name), QStringLiteral("one")); #endif - QAccessibleInterface *acc = QAccessible::queryAccessibleInterface(w); - delete acc; + QCOMPARE(iface->text(QAccessible::Value), QStringLiteral("one")); + combo.setCurrentIndex(2); +#ifdef Q_OS_UNIX + QCOMPARE(iface->text(QAccessible::Name), QStringLiteral("three")); +#endif + QCOMPARE(iface->text(QAccessible::Value), QStringLiteral("three")); + + QAccessibleInterface *listIface = iface->child(0); + QCOMPARE(listIface->role(), QAccessible::List); + QCOMPARE(listIface->childCount(), 3); - acc = QAccessible::queryAccessibleInterface(cb); + QVERIFY(!combo.view()->isVisible()); + QVERIFY(iface->actionInterface()); + QCOMPARE(iface->actionInterface()->actionCount(), 1); + iface->actionInterface()->doAction(0); + QVERIFY(combo.view()->isVisible()); - for (int i = 1; i < acc->childCount(); ++i) { - QTRY_VERIFY(acc->rect(0).contains(acc->rect(i))); + delete iface; } - QCOMPARE(acc->doAction(QAccessible::Press, 2), true); - QTest::qWait(400); - QAccessibleInterface *accList = 0; - int entry = acc->navigate(QAccessible::Child, 3, &accList); - QCOMPARE(entry, 0); - QAccessibleInterface *acc2 = 0; - entry = accList->navigate(QAccessible::Ancestor, 1, &acc2); - QCOMPARE(entry, 0); - QCOMPARE(verifyHierarchy(acc), 0); - delete acc2; - delete accList; - delete acc; - delete w; + { // editable combobox + QComboBox editableCombo; + editableCombo.show(); + editableCombo.setEditable(true); + editableCombo.addItems(QStringList() << "foo" << "bar" << "baz"); + + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&editableCombo); + QCOMPARE(verifyHierarchy(iface), 0); + + QCOMPARE(iface->role(), QAccessible::ComboBox); + QCOMPARE(iface->childCount(), 2); + + QAccessibleInterface *listIface = iface->child(0); + QCOMPARE(listIface->role(), QAccessible::List); + QAccessibleInterface *editIface = iface->child(1); + QCOMPARE(editIface->role(), QAccessible::EditableText); + + delete listIface; + delete editIface; + delete iface; + } QTestAccessibility::clearEvents(); } -- cgit v1.2.3