Update git submodules
[LibreOffice.git] / vcl / qt5 / QtAccessibleEventListener.cxx
blobc5d64d4650ed81452298fbbd86b834c026b9233c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <QtAccessibleEventListener.hxx>
21 #include <QtAccessibleRegistry.hxx>
22 #include <QtTools.hxx>
24 #include <sal/log.hxx>
26 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
27 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
28 #include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
29 #include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
30 #include <com/sun/star/accessibility/TextSegment.hpp>
32 #include <QtGui/QAccessible>
33 #include <QtGui/QAccessibleTextSelectionEvent>
35 using namespace css;
36 using namespace css::accessibility;
37 using namespace css::lang;
38 using namespace css::uno;
40 QtAccessibleEventListener::QtAccessibleEventListener(QtAccessibleWidget* pAccessibleWidget)
41 : m_pAccessibleWidget(pAccessibleWidget)
45 void QtAccessibleEventListener::HandleStateChangedEvent(
46 QAccessibleInterface* pQAccessibleInterface,
47 const css::accessibility::AccessibleEventObject& rEvent)
49 QAccessible::State aState;
51 sal_Int64 nState = 0;
52 rEvent.NewValue >>= nState;
53 // States in 'QAccessibleStateChangeEvent' indicate what states have changed, so if e.g.
54 // an object loses focus (not just if it gains it), 'focus' state needs to be set to 'true',
55 // so retrieve the old/previous value from the event if necessary.
56 if (nState == AccessibleStateType::INVALID)
57 rEvent.OldValue >>= nState;
59 switch (nState)
61 case AccessibleStateType::ACTIVE:
62 aState.active = true;
63 break;
64 case AccessibleStateType::BUSY:
65 aState.busy = true;
66 break;
67 case AccessibleStateType::CHECKED:
68 aState.checked = true;
69 break;
70 case AccessibleStateType::COLLAPSE:
71 aState.collapsed = true;
72 break;
73 case AccessibleStateType::DEFAULT:
74 aState.defaultButton = true;
75 break;
76 case AccessibleStateType::ENABLED:
77 aState.disabled = true;
78 break;
79 case AccessibleStateType::EDITABLE:
80 aState.editable = true;
81 break;
82 case AccessibleStateType::EXPANDABLE:
83 aState.expandable = true;
84 break;
85 case AccessibleStateType::EXPANDED:
86 aState.expanded = true;
87 break;
88 case AccessibleStateType::FOCUSABLE:
89 aState.focusable = true;
90 break;
91 case AccessibleStateType::FOCUSED:
92 aState.focused = true;
93 break;
94 case AccessibleStateType::INVALID:
95 aState.invalid = true;
96 break;
97 case AccessibleStateType::VISIBLE:
98 aState.invisible = true;
99 break;
100 case AccessibleStateType::MODAL:
101 aState.modal = true;
102 break;
103 case AccessibleStateType::MOVEABLE:
104 aState.movable = true;
105 break;
106 case AccessibleStateType::MULTI_LINE:
107 // comment in Qt's qaccessible.h has this:
108 // "// quint64 singleLine : 1; // we have multi line, this is redundant."
109 case AccessibleStateType::SINGLE_LINE:
110 aState.multiLine = true;
111 break;
112 case AccessibleStateType::MULTI_SELECTABLE:
113 aState.multiSelectable = true;
114 break;
115 case AccessibleStateType::OFFSCREEN:
116 aState.offscreen = true;
117 break;
118 case AccessibleStateType::PRESSED:
119 aState.pressed = true;
120 break;
121 case AccessibleStateType::RESIZABLE:
122 aState.sizeable = true;
123 break;
124 case AccessibleStateType::SELECTABLE:
125 aState.selectable = true;
126 break;
127 case AccessibleStateType::SELECTED:
128 aState.selected = true;
129 break;
130 case AccessibleStateType::SHOWING:
132 // Qt does not have an equivalent for the SHOWING state,
133 // but has separate event types
134 QAccessible::Event eEventType;
135 sal_Int64 nNewState = 0;
136 if ((rEvent.NewValue >>= nNewState) && nNewState == AccessibleStateType::SHOWING)
137 eEventType = QAccessible::ObjectShow;
138 else
139 eEventType = QAccessible::ObjectHide;
140 QAccessible::updateAccessibility(
141 new QAccessibleEvent(pQAccessibleInterface, eEventType));
142 break;
144 // These don't seem to have a matching Qt equivalent
145 case AccessibleStateType::ARMED:
146 case AccessibleStateType::DEFUNC:
147 case AccessibleStateType::HORIZONTAL:
148 case AccessibleStateType::ICONIFIED:
149 case AccessibleStateType::INDETERMINATE:
150 case AccessibleStateType::MANAGES_DESCENDANTS:
151 case AccessibleStateType::OPAQUE:
152 case AccessibleStateType::SENSITIVE:
153 case AccessibleStateType::STALE:
154 case AccessibleStateType::TRANSIENT:
155 case AccessibleStateType::VERTICAL:
156 default:
157 return;
160 QAccessible::updateAccessibility(
161 new QAccessibleStateChangeEvent(pQAccessibleInterface, aState));
164 void QtAccessibleEventListener::notifyEvent(const css::accessibility::AccessibleEventObject& aEvent)
166 QAccessibleInterface* pQAccessibleInterface = m_pAccessibleWidget;
168 switch (aEvent.EventId)
170 case AccessibleEventId::NAME_CHANGED:
171 QAccessible::updateAccessibility(
172 new QAccessibleEvent(pQAccessibleInterface, QAccessible::NameChanged));
173 return;
174 case AccessibleEventId::DESCRIPTION_CHANGED:
175 QAccessible::updateAccessibility(
176 new QAccessibleEvent(pQAccessibleInterface, QAccessible::DescriptionChanged));
177 return;
178 case AccessibleEventId::ACTION_CHANGED:
179 QAccessible::updateAccessibility(
180 new QAccessibleEvent(pQAccessibleInterface, QAccessible::ActionChanged));
181 return;
182 case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED:
184 // Qt has a QAccessible::ActiveDescendantChanged event type, but events of
185 // that type are currently just ignored on Qt side and not forwarded to AT-SPI.
186 // Send a state change event for the focused state of the newly
187 // active descendant instead
188 uno::Reference<accessibility::XAccessible> xActiveAccessible;
189 aEvent.NewValue >>= xActiveAccessible;
190 if (!xActiveAccessible.is())
191 return;
193 QObject* pQtAcc = QtAccessibleRegistry::getQObject(xActiveAccessible);
194 QAccessibleInterface* pInterface = QAccessible::queryAccessibleInterface(pQtAcc);
195 QAccessible::State aState;
196 aState.focused = true;
197 QAccessible::updateAccessibility(new QAccessibleStateChangeEvent(pInterface, aState));
198 return;
200 case AccessibleEventId::CARET_CHANGED:
202 sal_Int32 nNewCursorPos = 0;
203 aEvent.NewValue >>= nNewCursorPos;
204 QAccessible::updateAccessibility(
205 new QAccessibleTextCursorEvent(pQAccessibleInterface, nNewCursorPos));
206 return;
208 case AccessibleEventId::CHILD:
210 Reference<XAccessible> xChild;
211 if (aEvent.NewValue >>= xChild)
213 QAccessible::updateAccessibility(new QAccessibleEvent(
214 QtAccessibleRegistry::getQObject(xChild), QAccessible::ObjectCreated));
215 return;
217 if (aEvent.OldValue >>= xChild)
219 QAccessible::updateAccessibility(new QAccessibleEvent(
220 QtAccessibleRegistry::getQObject(xChild), QAccessible::ObjectDestroyed));
221 return;
223 SAL_WARN("vcl.qt",
224 "Ignoring invalid AccessibleEventId::CHILD event without any child set.");
225 return;
227 case AccessibleEventId::HYPERTEXT_CHANGED:
228 QAccessible::updateAccessibility(
229 new QAccessibleEvent(pQAccessibleInterface, QAccessible::HypertextChanged));
230 return;
231 case AccessibleEventId::SELECTION_CHANGED:
232 QAccessible::updateAccessibility(
233 new QAccessibleEvent(pQAccessibleInterface, QAccessible::Selection));
234 return;
235 case AccessibleEventId::VISIBLE_DATA_CHANGED:
236 QAccessible::updateAccessibility(
237 new QAccessibleEvent(pQAccessibleInterface, QAccessible::VisibleDataChanged));
238 return;
239 case AccessibleEventId::TEXT_SELECTION_CHANGED:
241 QAccessibleTextInterface* pTextInterface = pQAccessibleInterface->textInterface();
242 if (!pTextInterface)
244 SAL_WARN("vcl.qt", "TEXT_SELECTION_CHANGED event received for object not "
245 "implementing text interface");
246 return;
248 int nStartOffset = 0;
249 int nEndOffset = 0;
250 pTextInterface->selection(0, &nStartOffset, &nEndOffset);
251 QAccessible::updateAccessibility(
252 new QAccessibleTextSelectionEvent(pQAccessibleInterface, nStartOffset, nEndOffset));
253 return;
255 case AccessibleEventId::TEXT_ATTRIBUTE_CHANGED:
256 QAccessible::updateAccessibility(
257 new QAccessibleEvent(pQAccessibleInterface, QAccessible::AttributeChanged));
258 return;
259 case AccessibleEventId::TEXT_CHANGED:
261 TextSegment aDeletedText;
262 TextSegment aInsertedText;
263 if (aEvent.OldValue >>= aDeletedText)
265 QAccessible::updateAccessibility(
266 new QAccessibleTextRemoveEvent(pQAccessibleInterface, aDeletedText.SegmentStart,
267 toQString(aDeletedText.SegmentText)));
269 if (aEvent.NewValue >>= aInsertedText)
271 QAccessible::updateAccessibility(new QAccessibleTextInsertEvent(
272 pQAccessibleInterface, aInsertedText.SegmentStart,
273 toQString(aInsertedText.SegmentText)));
275 return;
277 case AccessibleEventId::TABLE_CAPTION_CHANGED:
278 QAccessible::updateAccessibility(
279 new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableCaptionChanged));
280 return;
281 case AccessibleEventId::TABLE_COLUMN_DESCRIPTION_CHANGED:
282 QAccessible::updateAccessibility(new QAccessibleEvent(
283 pQAccessibleInterface, QAccessible::TableColumnDescriptionChanged));
284 return;
285 case AccessibleEventId::TABLE_COLUMN_HEADER_CHANGED:
286 QAccessible::updateAccessibility(
287 new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableColumnHeaderChanged));
288 return;
289 case AccessibleEventId::TABLE_MODEL_CHANGED:
291 AccessibleTableModelChange aChange;
292 aEvent.NewValue >>= aChange;
294 QAccessibleTableModelChangeEvent::ModelChangeType nType;
295 switch (aChange.Type)
297 case AccessibleTableModelChangeType::COLUMNS_INSERTED:
298 nType = QAccessibleTableModelChangeEvent::ColumnsInserted;
299 break;
300 case AccessibleTableModelChangeType::COLUMNS_REMOVED:
301 nType = QAccessibleTableModelChangeEvent::ColumnsRemoved;
302 break;
303 case AccessibleTableModelChangeType::ROWS_INSERTED:
304 nType = QAccessibleTableModelChangeEvent::RowsInserted;
305 break;
306 case AccessibleTableModelChangeType::ROWS_REMOVED:
307 nType = QAccessibleTableModelChangeEvent::RowsRemoved;
308 break;
309 case AccessibleTableModelChangeType::UPDATE:
310 nType = QAccessibleTableModelChangeEvent::DataChanged;
311 break;
312 default:
313 assert(false && "Unhandled AccessibleTableModelChangeType");
314 return;
316 QAccessibleTableModelChangeEvent* pTableEvent
317 = new QAccessibleTableModelChangeEvent(pQAccessibleInterface, nType);
318 pTableEvent->setFirstRow(aChange.FirstRow);
319 pTableEvent->setLastRow(aChange.LastRow);
320 pTableEvent->setFirstColumn(aChange.FirstColumn);
321 pTableEvent->setLastColumn(aChange.LastColumn);
322 QAccessible::updateAccessibility(pTableEvent);
323 return;
325 case AccessibleEventId::TABLE_ROW_DESCRIPTION_CHANGED:
326 QAccessible::updateAccessibility(new QAccessibleEvent(
327 pQAccessibleInterface, QAccessible::TableRowDescriptionChanged));
328 return;
329 case AccessibleEventId::TABLE_ROW_HEADER_CHANGED:
330 QAccessible::updateAccessibility(
331 new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableRowHeaderChanged));
332 return;
333 case AccessibleEventId::TABLE_SUMMARY_CHANGED:
334 QAccessible::updateAccessibility(
335 new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableSummaryChanged));
336 return;
337 case AccessibleEventId::SELECTION_CHANGED_ADD:
338 case AccessibleEventId::SELECTION_CHANGED_REMOVE:
340 QAccessible::Event eEventType;
341 if (aEvent.EventId == AccessibleEventId::SELECTION_CHANGED_ADD)
342 eEventType = QAccessible::SelectionAdd;
343 else
344 eEventType = QAccessible::SelectionRemove;
346 uno::Reference<accessibility::XAccessible> xChildAcc;
347 aEvent.NewValue >>= xChildAcc;
348 if (!xChildAcc.is())
350 SAL_WARN("vcl.qt",
351 "Selection add/remove event without the (un)selected accessible set");
352 return;
354 Reference<XAccessibleContext> xContext = xChildAcc->getAccessibleContext();
355 if (!xContext.is())
357 SAL_WARN("vcl.qt", "No valid XAccessibleContext for (un)selected accessible.");
358 return;
361 // Qt expects the event to be sent for the (un)selected child
362 QObject* pChildObject = QtAccessibleRegistry::getQObject(xChildAcc);
363 assert(pChildObject);
364 QAccessible::updateAccessibility(new QAccessibleEvent(pChildObject, eEventType));
365 return;
367 case AccessibleEventId::SELECTION_CHANGED_WITHIN:
368 QAccessible::updateAccessibility(
369 new QAccessibleEvent(pQAccessibleInterface, QAccessible::SelectionWithin));
370 return;
371 case AccessibleEventId::PAGE_CHANGED:
372 QAccessible::updateAccessibility(
373 new QAccessibleEvent(pQAccessibleInterface, QAccessible::PageChanged));
374 return;
375 case AccessibleEventId::SECTION_CHANGED:
376 QAccessible::updateAccessibility(
377 new QAccessibleEvent(pQAccessibleInterface, QAccessible::SectionChanged));
378 return;
379 case AccessibleEventId::COLUMN_CHANGED:
380 QAccessible::updateAccessibility(
381 new QAccessibleEvent(pQAccessibleInterface, QAccessible::TextColumnChanged));
382 return;
383 case AccessibleEventId::BOUNDRECT_CHANGED:
384 QAccessible::updateAccessibility(
385 new QAccessibleEvent(pQAccessibleInterface, QAccessible::LocationChanged));
386 return;
387 case AccessibleEventId::STATE_CHANGED:
388 HandleStateChangedEvent(pQAccessibleInterface, aEvent);
389 return;
390 case AccessibleEventId::VALUE_CHANGED:
392 QAccessibleValueInterface* pValueInterface = pQAccessibleInterface->valueInterface();
393 if (pValueInterface)
395 const QVariant aValue = pValueInterface->currentValue();
396 QAccessible::updateAccessibility(
397 new QAccessibleValueChangeEvent(pQAccessibleInterface, aValue));
399 return;
401 case AccessibleEventId::ROLE_CHANGED:
402 case AccessibleEventId::INVALIDATE_ALL_CHILDREN:
403 case AccessibleEventId::CONTENT_FLOWS_FROM_RELATION_CHANGED:
404 case AccessibleEventId::CONTENT_FLOWS_TO_RELATION_CHANGED:
405 case AccessibleEventId::CONTROLLED_BY_RELATION_CHANGED:
406 case AccessibleEventId::CONTROLLER_FOR_RELATION_CHANGED:
407 case AccessibleEventId::LABEL_FOR_RELATION_CHANGED:
408 case AccessibleEventId::LABELED_BY_RELATION_CHANGED:
409 case AccessibleEventId::MEMBER_OF_RELATION_CHANGED:
410 case AccessibleEventId::SUB_WINDOW_OF_RELATION_CHANGED:
411 case AccessibleEventId::LISTBOX_ENTRY_EXPANDED:
412 case AccessibleEventId::LISTBOX_ENTRY_COLLAPSED:
413 case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS:
414 default:
415 SAL_WARN("vcl.qt", "Unmapped AccessibleEventId: " << aEvent.EventId);
416 return;
420 void QtAccessibleEventListener::disposing(const EventObject& /* Source */)
422 assert(m_pAccessibleWidget);
423 m_pAccessibleWidget->invalidate();
426 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */