]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Fix accessibility ancestor tree
authorFelix Ernst <felixernst@zohomail.eu>
Mon, 17 Jul 2023 14:13:51 +0000 (17:13 +0300)
committerFelix Ernst <felixernst@kde.org>
Thu, 5 Oct 2023 12:09:25 +0000 (12:09 +0000)
Before this commit, KItemListViewAccessible would always return
nullptr as its parent. This meant that accessibility software would
have to guess to which window/hierarchy the KItemListView belongs
to. Guessing shouldn't be necessary here.

This commit makes sure that the KItemListView always returns a
sensible parent in the accessible hierarchy. It does so by
explicitly setting the accessible parent for every KItemListView
after construction in the DolphinView contructor. Since
KItemListView now always knows about its accessible parent, the
accessibleInterfaceFactory can always ask the KItemListView for
that information when constructing the QAccessibleInterfaces.

Fixes https://invent.kde.org/system/dolphin/-/issues/47.

src/kitemviews/kitemlistview.cpp
src/kitemviews/kitemlistview.h
src/kitemviews/kitemlistviewaccessible.cpp
src/kitemviews/kitemlistviewaccessible.h
src/tests/kitemlistcontrollerexpandtest.cpp
src/tests/kitemlistcontrollertest.cpp
src/views/dolphinview.cpp

index 38d21ff5e73b23df49c732027680a9b5cc4e83af..457c02ec5f5253f70f504ee50b76384aa7b8ec52 100644 (file)
@@ -50,9 +50,14 @@ QAccessibleInterface *accessibleInterfaceFactory(const QString &key, QObject *ob
     Q_UNUSED(key)
 
     if (KItemListContainer *container = qobject_cast<KItemListContainer *>(object)) {
+        if (auto controller = container->controller(); controller) {
+            if (KItemListView *view = controller->view(); view && view->accessibleParent()) {
+                return view->accessibleParent();
+            }
+        }
         return new KItemListContainerAccessible(container);
     } else if (KItemListView *view = qobject_cast<KItemListView *>(object)) {
-        return new KItemListViewAccessible(view);
+        return new KItemListViewAccessible(view, view->accessibleParent());
     }
 
     return nullptr;
@@ -337,6 +342,19 @@ KItemListGroupHeaderCreatorBase *KItemListView::groupHeaderCreator() const
     return m_groupHeaderCreator;
 }
 
+#ifndef QT_NO_ACCESSIBILITY
+void KItemListView::setAccessibleParentsObject(KItemListContainer *accessibleParentsObject)
+{
+    Q_ASSERT(!m_accessibleParent);
+    m_accessibleParent = new KItemListContainerAccessible(accessibleParentsObject);
+}
+KItemListContainerAccessible *KItemListView::accessibleParent()
+{
+    Q_CHECK_PTR(m_accessibleParent); // We always want the accessibility tree/hierarchy to be complete.
+    return m_accessibleParent;
+}
+#endif
+
 QSizeF KItemListView::itemSize() const
 {
     return m_itemSize;
index ff51af92243d4deb75a0d35714891fe41028a758..7bcaec704dee9f8316852e7457a66a6f4bcec827 100644 (file)
@@ -21,6 +21,8 @@
 #include <QGraphicsWidget>
 #include <QSet>
 
+class KItemListContainer;
+class KItemListContainerAccessible;
 class KItemListController;
 class KItemListGroupHeaderCreatorBase;
 class KItemListHeader;
@@ -142,6 +144,18 @@ public:
     void setGroupHeaderCreator(KItemListGroupHeaderCreatorBase *groupHeaderCreator);
     KItemListGroupHeaderCreatorBase *groupHeaderCreator() const;
 
+#ifndef QT_NO_ACCESSIBILITY
+    /**
+     * Uses \a parent to create an accessible object for \a parent. That accessible object will
+     * then be used as the accessible parent of the accessible object for this KItemListView.
+     * Make sure \a parent is the container which contains this specific KItemListView.
+     * This method must be called once before the accessible interface is queried for this class.
+     */
+    void setAccessibleParentsObject(KItemListContainer *accessibleParentsObject);
+    /** The parent of the QAccessibilityInterface of this class. */
+    KItemListContainerAccessible *accessibleParent();
+#endif
+
     /**
      * @return The basic size of all items. The size of an item may be larger than
      *         the basic size (see KItemListView::itemRect()).
@@ -711,6 +725,10 @@ private:
     QList<QByteArray> m_visibleRoles;
     mutable KItemListWidgetCreatorBase *m_widgetCreator;
     mutable KItemListGroupHeaderCreatorBase *m_groupHeaderCreator;
+#ifndef QT_NO_ACCESSIBILITY
+    /** The object that will be the parent of this classes QAccessibleInterface. */
+    KItemListContainerAccessible *m_accessibleParent = nullptr;
+#endif
     KItemListStyleOption m_styleOption;
 
     QHash<int, KItemListWidget *> m_visibleItems;
index a75df8b760f99f6d9151f89ea75b721bc98f4a27..38c883efec52da321e9d4fd52563304e84cc2d65 100644 (file)
@@ -21,10 +21,12 @@ KItemListView *KItemListViewAccessible::view() const
     return qobject_cast<KItemListView *>(object());
 }
 
-KItemListViewAccessible::KItemListViewAccessible(KItemListView *view_)
+KItemListViewAccessible::KItemListViewAccessible(KItemListView *view_, KItemListContainerAccessible *parent)
     : QAccessibleObject(view_)
+    , m_parent(parent)
 {
     Q_ASSERT(view());
+    Q_CHECK_PTR(parent);
     m_cells.resize(childCount());
 }
 
@@ -208,8 +210,7 @@ QAccessibleInterface *KItemListViewAccessible::childAt(int x, int y) const
 
 QAccessibleInterface *KItemListViewAccessible::parent() const
 {
-    // FIXME: return KItemListContainerAccessible here
-    return nullptr;
+    return m_parent;
 }
 
 int KItemListViewAccessible::childCount() const
index 628c32fc2515763e444088eebfc9db758258482f..41aacf3670108feb5f2a423f9b254ae83dcd3455 100644 (file)
 
 class KItemListView;
 class KItemListContainer;
+class KItemListContainerAccessible;
 
 class DOLPHIN_EXPORT KItemListViewAccessible : public QAccessibleObject, public QAccessibleTableInterface
 {
 public:
-    explicit KItemListViewAccessible(KItemListView *view);
+    explicit KItemListViewAccessible(KItemListView *view, KItemListContainerAccessible *parent);
     ~KItemListViewAccessible() override;
 
     void *interface_cast(QAccessible::InterfaceType type) override;
@@ -81,6 +82,8 @@ private:
         QAccessible::Id id;
     };
     mutable QVector<AccessibleIdWrapper> m_cells;
+
+    KItemListContainerAccessible *m_parent;
 };
 
 class DOLPHIN_EXPORT KItemListAccessibleCell : public QAccessibleInterface, public QAccessibleTableCellInterface
index 368ec67ce57a96f5ff722e7ac7948ec820fc3c59..05708f4d23629c822118e3be9c018865d83bedd6 100644 (file)
@@ -48,6 +48,9 @@ void KItemListControllerExpandTest::initTestCase()
     m_view = new KFileItemListView();
     m_controller = new KItemListController(m_model, m_view, this);
     m_container = new KItemListContainer(m_controller);
+#ifndef QT_NO_ACCESSIBILITY
+    m_view->setAccessibleParentsObject(m_container);
+#endif
     m_controller = m_container->controller();
     m_controller->setSelectionBehavior(KItemListController::MultiSelection);
     m_selectionManager = m_controller->selectionManager();
index d1a9cfc7c7980cee961f42f3ce3d2e013e8cc4b8..9d345fdd96995465b91fda46ddef69688626eb87 100644 (file)
@@ -109,6 +109,9 @@ void KItemListControllerTest::initTestCase()
     m_view = new KFileItemListView();
     m_controller = new KItemListController(m_model, m_view, this);
     m_container = new KItemListContainer(m_controller);
+#ifndef QT_NO_ACCESSIBILITY
+    m_view->setAccessibleParentsObject(m_container);
+#endif
     m_controller = m_container->controller();
     m_controller->setSelectionBehavior(KItemListController::MultiSelection);
     m_selectionManager = m_controller->selectionManager();
index 21e23d5acae65b838c86c9c198ece771904dc8c8..d8eab142d54f4f37860337893e0089f6bb741bca 100644 (file)
@@ -129,6 +129,9 @@ DolphinView::DolphinView(const QUrl &url, QWidget *parent)
 
     m_container = new KItemListContainer(controller, this);
     m_container->installEventFilter(this);
+#ifndef QT_NO_ACCESSIBILITY
+    m_view->setAccessibleParentsObject(m_container);
+#endif
     setFocusProxy(m_container);
     connect(m_container->horizontalScrollBar(), &QScrollBar::valueChanged, this, [=] {
         hideToolTip();