]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/accessibility/kitemlistviewaccessible.h
Adapt to Orca 47
[dolphin.git] / src / kitemviews / accessibility / kitemlistviewaccessible.h
1 /*
2 * SPDX-FileCopyrightText: 2012 Amandeep Singh <aman.dedman@gmail.com>
3 * SPDX-FileCopyrightText: 2024 Felix Ernst <felixernst@kde.org>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8 #ifndef KITEMLISTVIEWACCESSIBLE_H
9 #define KITEMLISTVIEWACCESSIBLE_H
10
11 #include "dolphin_export.h"
12
13 #include <QAccessible>
14 #include <QAccessibleObject>
15 #include <QAccessibleWidget>
16 #include <QPointer>
17
18 class KItemListView;
19 class KItemListContainer;
20 class KItemListContainerAccessible;
21 class KItemListSelectionManager;
22
23 /**
24 * The main class for making the main view accessible.
25 *
26 * Such a class is necessary because the KItemListView is a mostly custom entity. This class provides a lot of the functionality to make it possible to
27 * interact with the view using accessibility tools. It implements various interfaces mostly to generally allow working with the view as a whole. However,
28 * actually interacting with singular items within the view is implemented in KItemListDelegateAccessible.
29 *
30 * @note For documentation of most of the methods within this class, check out the documentation of the methods which are being overriden here.
31 */
32 class DOLPHIN_EXPORT KItemListViewAccessible : public QAccessibleObject,
33 public QAccessibleSelectionInterface,
34 public QAccessibleTableInterface,
35 public QAccessibleActionInterface
36 {
37 public:
38 explicit KItemListViewAccessible(KItemListView *view, KItemListContainerAccessible *parent);
39 ~KItemListViewAccessible() override;
40
41 // QAccessibleObject
42 void *interface_cast(QAccessible::InterfaceType type) override;
43
44 QAccessible::Role role() const override;
45 QAccessible::State state() const override;
46 QString text(QAccessible::Text t) const override;
47 QRect rect() const override;
48
49 QAccessibleInterface *child(int index) const override;
50 int childCount() const override;
51 int indexOfChild(const QAccessibleInterface *) const override;
52 QAccessibleInterface *childAt(int x, int y) const override;
53 QAccessibleInterface *parent() const override;
54
55 // Table interface
56 QAccessibleInterface *cellAt(int row, int column) const override;
57 QAccessibleInterface *caption() const override;
58 QAccessibleInterface *summary() const override;
59 QString columnDescription(int column) const override;
60 QString rowDescription(int row) const override;
61 int columnCount() const override;
62 int rowCount() const override;
63
64 // Selection
65 int selectedCellCount() const override;
66 int selectedColumnCount() const override;
67 int selectedRowCount() const override;
68 QList<QAccessibleInterface *> selectedCells() const override;
69 QList<int> selectedColumns() const override;
70 QList<int> selectedRows() const override;
71 bool isColumnSelected(int column) const override;
72 bool isRowSelected(int row) const override;
73 bool selectRow(int row) override;
74 bool selectColumn(int column) override;
75 bool unselectRow(int row) override;
76 bool unselectColumn(int column) override;
77 void modelChange(QAccessibleTableModelChangeEvent *) override;
78
79 // Selection interface
80 /** Clear selection */
81 bool clear() override;
82 bool isSelected(QAccessibleInterface *childItem) const override;
83 bool select(QAccessibleInterface *childItem) override;
84 bool selectAll() override;
85 QAccessibleInterface *selectedItem(int selectionIndex) const override;
86 int selectedItemCount() const override;
87 QList<QAccessibleInterface *> selectedItems() const override;
88 bool unselect(QAccessibleInterface *childItem) override;
89
90 // Action interface
91 QStringList actionNames() const override;
92 void doAction(const QString &actionName) override;
93 QStringList keyBindingsForAction(const QString &actionName) const override;
94
95 // Custom non-interface methods
96 KItemListView *view() const;
97
98 /**
99 * Called by KItemListContainer when it passes on focus to the view. Accessible focus is then meant to go towards this accessible interface and a detailed
100 * announcement of the current view state (current item and overall location state) should be triggered.
101 */
102 void setAccessibleFocusAndAnnounceAll();
103
104 /**
105 * Called multiple times while a new location is loading. A timer is restarted, and if this method has not been called for a split second, the newly loaded
106 * location is finally announced.
107 * Either the @p placeholderMessage is announced when there are no items in the view (yet), or the current item is announced together with the view state.
108 *
109 * @param placeholderMessage The message that should be announced when no items are visible (yet). This message is mostly identical to
110 * DolphinView::m_placeholderLabel in both content and purpose. @see DolphinView::updatePlaceHolderLabel().
111 *
112 * If there are items in the view and the placeholderMessage is therefore not visible, the current item and location is announced instead.
113 */
114 void announceNewlyLoadedLocation(const QString &placeholderMessage);
115
116 /**
117 * Starts a timer that will trigger an announcement of the current item. The timer makes sure that quick changes to the current item will only lead to a
118 * singular announcement. This way when a new folder is loaded we only trigger a single announcement even if the items quickly change.
119 *
120 * When m_shouldAnnounceLocation is true, the current location will be announced following the announcement of the current item.
121 *
122 * If the current item is invalid, only the current location is announced, which has the responsibility of then telling why there is no valid item in the
123 * view.
124 */
125 void announceCurrentItem();
126
127 private:
128 /**
129 * @returns a KItemListDelegateAccessible representing the file or folder at the @index. Returns nullptr for invalid indices.
130 * If a KItemListDelegateAccessible for an index does not yet exist, it will be created.
131 * Index is 0-based.
132 */
133 inline QAccessibleInterface *accessibleDelegate(int index) const;
134
135 KItemListSelectionManager *selectionManager() const;
136
137 private Q_SLOTS:
138 /**
139 * Is run in response to announceCurrentItem(). If the current item exists, it is announced. Otherwise the view is announced.
140 * Also announces some general information about the current location if it has changed recently.
141 */
142 void slotAnnounceCurrentItemTimerTimeout();
143
144 private:
145 /** @see setPlaceholderMessage(). */
146 QString m_placeholderMessage;
147
148 /**
149 * Is started by announceCurrentItem().
150 * If we announce the current item as soon as it changes, we would announce multiple items while loading a folder.
151 * This timer makes sure we only announce the singular currently focused item when things have settled down.
152 */
153 QTimer *m_announceCurrentItemTimer;
154
155 /**
156 * If we want announceCurrentItem() to always announce the current item, we must be aware if this is equal to the previous current item, because
157 * - if the accessibility focus moves to a new item, it is automatically announced, but
158 * - if the focus is still on the item at the same index, the focus does not technically move to a new item even if the file at that index changed, so we
159 * need to instead send change events for the accessible name and accessible description.
160 */
161 int m_lastAnnouncedIndex = -1;
162
163 /**
164 * Is set to true in response to announceDescriptionChange(). When true, the next time slotAnnounceCurrentItemTimerTimeout() is called the description is
165 * also announced. Then this bool is set to false.
166 */
167 bool m_shouldAnnounceLocation = true;
168
169 class AccessibleIdWrapper
170 {
171 public:
172 AccessibleIdWrapper();
173 bool isValid;
174 QAccessible::Id id;
175 };
176 /**
177 * A list that maps the indices of the children of this KItemListViewAccessible to the accessible ids of the matching KItemListDelegateAccessible objects.
178 * For example: m_accessibleDelegates.at(2) would be the AccessibleIdWrapper with an id which can be used to retrieve the QAccessibleObject that represents
179 * the third file in this view.
180 */
181 mutable QVector<AccessibleIdWrapper> m_accessibleDelegates;
182
183 KItemListContainerAccessible *m_parent;
184 };
185
186 #endif