2 * SPDX-FileCopyrightText: 2012 Amandeep Singh <aman.dedman@gmail.com>
3 * SPDX-FileCopyrightText: 2024 Felix Ernst <felixernst@kde.org>
5 * SPDX-License-Identifier: GPL-2.0-or-later
8 #include "kitemlistdelegateaccessible.h"
9 #include "kitemviews/kfileitemlistwidget.h"
10 #include "kitemviews/kfileitemmodel.h"
11 #include "kitemviews/kitemlistcontroller.h"
12 #include "kitemviews/kitemlistselectionmanager.h"
13 #include "kitemviews/kitemlistview.h"
14 #include "kitemviews/private/kitemlistviewlayouter.h"
16 #include <KLocalizedString>
18 #include <QGraphicsScene>
19 #include <QGraphicsView>
21 KItemListDelegateAccessible::KItemListDelegateAccessible(KItemListView
*view
, int index
)
25 Q_ASSERT(index
>= 0 && index
< view
->model()->count());
28 void *KItemListDelegateAccessible::interface_cast(QAccessible::InterfaceType type
)
30 if (type
== QAccessible::TableCellInterface
) {
31 return static_cast<QAccessibleTableCellInterface
*>(this);
36 int KItemListDelegateAccessible::columnExtent() const
41 int KItemListDelegateAccessible::rowExtent() const
46 QList
<QAccessibleInterface
*> KItemListDelegateAccessible::rowHeaderCells() const
48 return QList
<QAccessibleInterface
*>();
51 QList
<QAccessibleInterface
*> KItemListDelegateAccessible::columnHeaderCells() const
53 return QList
<QAccessibleInterface
*>();
56 int KItemListDelegateAccessible::columnIndex() const
58 return m_view
->m_layouter
->itemColumn(m_index
);
61 int KItemListDelegateAccessible::rowIndex() const
63 return m_view
->m_layouter
->itemRow(m_index
);
66 bool KItemListDelegateAccessible::isSelected() const
68 return m_view
->controller()->selectionManager()->isSelected(m_index
);
71 QAccessibleInterface
*KItemListDelegateAccessible::table() const
73 return QAccessible::queryAccessibleInterface(m_view
);
76 QAccessible::Role
KItemListDelegateAccessible::role() const
78 return QAccessible::ListItem
; // We could also return "Cell" here which would then announce the exact row and column of the item. However, different from
79 // applications that actually have a strong cell workflow -- like LibreOfficeCalc -- we have no advantage of announcing the row or column aside from us
80 // generally being interested in announcing that users in Icon View mode need to use the Left and Right arrow keys to arrive at every item. There are ways
81 // for users to figure this out regardless by paying attention to the index that is being announced for each list item. In KitemListViewAccessible in icon
82 // view mode it is also mentioned that the items are positioned in a grid, so the two-dimensionality should be clear enough.
85 QAccessible::State
KItemListDelegateAccessible::state() const
87 QAccessible::State state
;
89 state
.selectable
= true;
91 state
.selected
= true;
94 state
.focusable
= true;
95 if (m_view
->controller()->selectionManager()->currentItem() == m_index
) {
100 if (m_view
->controller()->selectionBehavior() == KItemListController::MultiSelection
) {
101 state
.multiSelectable
= true;
104 if (m_view
->supportsItemExpanding() && m_view
->model()->isExpandable(m_index
)) {
105 state
.expandable
= true;
106 state
.expanded
= m_view
->model()->isExpanded(m_index
);
107 state
.collapsed
= !state
.expanded
;
113 bool KItemListDelegateAccessible::isExpandable() const
115 return m_view
->model()->isExpandable(m_index
);
118 QRect
KItemListDelegateAccessible::rect() const
120 QRect rect
= m_view
->itemRect(m_index
).toRect();
126 rect
.translate(m_view
->mapToScene(QPointF(0.0, 0.0)).toPoint());
127 rect
.translate(m_view
->scene()->views()[0]->mapToGlobal(QPoint(0, 0)));
131 QString
KItemListDelegateAccessible::text(QAccessible::Text t
) const
133 const QHash
<QByteArray
, QVariant
> data
= m_view
->model()->data(m_index
);
135 case QAccessible::Name
: {
136 return data
["text"].toString();
138 case QAccessible::Description
: {
141 if (data
["isHidden"].toBool()) {
142 description
+= i18nc("@info", "hidden");
145 QString mimeType
{data
["type"].toString()};
146 if (mimeType
.isEmpty()) {
147 const KFileItemModel
*model
= qobject_cast
<KFileItemModel
*>(m_view
->model());
149 mimeType
= model
->fileItem(m_index
).mimeComment();
151 Q_ASSERT_X(!mimeType
.isEmpty(), "KItemListDelegateAccessible::text", "Unable to retrieve mime type.");
154 if (data
["isLink"].toBool()) {
155 QString linkDestination
{data
["destination"].toString()};
156 if (linkDestination
.isEmpty()) {
157 const KFileItemModel
*model
= qobject_cast
<KFileItemModel
*>(m_view
->model());
159 linkDestination
= model
->fileItem(m_index
).linkDest();
161 Q_ASSERT_X(!linkDestination
.isEmpty(), "KItemListDelegateAccessible::text", "Unable to retrieve link destination.");
164 description
+= i18nc("@info enumeration saying this is a link to $1, %1 is mimeType", ", link to %1 at %2", mimeType
, linkDestination
);
166 description
+= i18nc("@info enumeration, %1 is mimeType", ", %1", mimeType
);
168 const QList
<QByteArray
> additionallyShownInformation
{m_view
->visibleRoles()};
169 const KItemModelBase
*model
= m_view
->model();
170 for (const auto &roleInformation
: additionallyShownInformation
) {
171 if (roleInformation
== "text") {
174 KFileItemListWidgetInformant informant
;
175 const auto roleText
{informant
.roleText(roleInformation
, data
, KFileItemListWidgetInformant::ForUsageAs::SpokenText
)};
176 if (roleText
.isEmpty()) {
177 continue; // No need to announce roles which are empty for this item.
180 // i18n: The text starts with a comma because multiple occurences of this text can follow after each others as an enumeration.
181 // Normally it would make sense to have a colon between property and value to make the relation between the property and its property value
182 // clear, however this is accessible text that will be read out by screen readers. That's why there is only a space between the two here,
183 // because screen readers would read the colon literally as "colon", which is just a waste of time for users who might go through a list of
184 // hundreds of items. So, if you want to add any more punctation there to improve structure, try to make sure that it will not lead to annoying
185 // announcements when read out by a screen reader.
186 i18nc("@info accessibility enumeration, %1 is property, %2 is value", ", %1 %2", model
->roleDescription(roleInformation
), roleText
);
197 void KItemListDelegateAccessible::setText(QAccessible::Text
, const QString
&)
201 QAccessibleInterface
*KItemListDelegateAccessible::child(int) const
206 bool KItemListDelegateAccessible::isValid() const
208 return m_view
&& (m_index
>= 0) && (m_index
< m_view
->model()->count());
211 QAccessibleInterface
*KItemListDelegateAccessible::childAt(int, int) const
216 int KItemListDelegateAccessible::childCount() const
221 int KItemListDelegateAccessible::indexOfChild(const QAccessibleInterface
*child
) const
227 QAccessibleInterface
*KItemListDelegateAccessible::parent() const
229 return QAccessible::queryAccessibleInterface(m_view
);
232 int KItemListDelegateAccessible::index() const
237 QObject
*KItemListDelegateAccessible::object() const