calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / vcl / qt5 / QtAccessibleEventListener.cxx
blobf9a4d7b1a2c148640408bcd834cbe2acf0f77d58
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 // ignore for now, since it somehow causes Orca to become unresponsive quite quickly
63 // TODO: analyze further and fix root cause
65 aState.active = true;
66 break;
68 return;
69 case AccessibleStateType::BUSY:
70 aState.busy = true;
71 break;
72 case AccessibleStateType::CHECKED:
73 aState.checked = true;
74 break;
75 case AccessibleStateType::COLLAPSE:
76 aState.collapsed = true;
77 break;
78 case AccessibleStateType::DEFAULT:
79 aState.defaultButton = true;
80 break;
81 case AccessibleStateType::ENABLED:
82 aState.disabled = true;
83 break;
84 case AccessibleStateType::EDITABLE:
85 aState.editable = true;
86 break;
87 case AccessibleStateType::EXPANDABLE:
88 aState.expandable = true;
89 break;
90 case AccessibleStateType::EXPANDED:
91 aState.expanded = true;
92 break;
93 case AccessibleStateType::FOCUSABLE:
94 aState.focusable = true;
95 break;
96 case AccessibleStateType::FOCUSED:
97 aState.focused = true;
98 break;
99 case AccessibleStateType::INVALID:
100 aState.invalid = true;
101 break;
102 case AccessibleStateType::VISIBLE:
103 aState.invisible = true;
104 break;
105 case AccessibleStateType::MODAL:
106 aState.modal = true;
107 break;
108 case AccessibleStateType::MOVEABLE:
109 aState.movable = true;
110 break;
111 case AccessibleStateType::MULTI_LINE:
112 // comment in Qt's qaccessible.h has this:
113 // "// quint64 singleLine : 1; // we have multi line, this is redundant."
114 case AccessibleStateType::SINGLE_LINE:
115 aState.multiLine = true;
116 break;
117 case AccessibleStateType::MULTI_SELECTABLE:
118 aState.multiSelectable = true;
119 break;
120 case AccessibleStateType::OFFSCREEN:
121 aState.offscreen = true;
122 break;
123 case AccessibleStateType::PRESSED:
124 aState.pressed = true;
125 break;
126 case AccessibleStateType::RESIZABLE:
127 aState.sizeable = true;
128 break;
129 case AccessibleStateType::SELECTABLE:
130 aState.selectable = true;
131 break;
132 case AccessibleStateType::SELECTED:
133 aState.selected = true;
134 break;
135 case AccessibleStateType::SHOWING:
137 // Qt does not have an equivalent for the SHOWING state,
138 // but has separate event types
139 QAccessible::Event eEventType;
140 sal_Int64 nNewState = 0;
141 if ((rEvent.NewValue >>= nNewState) && nNewState == AccessibleStateType::SHOWING)
142 eEventType = QAccessible::ObjectShow;
143 else
144 eEventType = QAccessible::ObjectHide;
145 QAccessible::updateAccessibility(
146 new QAccessibleEvent(pQAccessibleInterface, eEventType));
147 break;
149 // These don't seem to have a matching Qt equivalent
150 case AccessibleStateType::ARMED:
151 case AccessibleStateType::DEFUNC:
152 case AccessibleStateType::HORIZONTAL:
153 case AccessibleStateType::ICONIFIED:
154 case AccessibleStateType::INDETERMINATE:
155 case AccessibleStateType::MANAGES_DESCENDANTS:
156 case AccessibleStateType::OPAQUE:
157 case AccessibleStateType::SENSITIVE:
158 case AccessibleStateType::STALE:
159 case AccessibleStateType::TRANSIENT:
160 case AccessibleStateType::VERTICAL:
161 default:
162 return;
165 QAccessible::updateAccessibility(
166 new QAccessibleStateChangeEvent(pQAccessibleInterface, aState));
169 void QtAccessibleEventListener::notifyEvent(const css::accessibility::AccessibleEventObject& aEvent)
171 QAccessibleInterface* pQAccessibleInterface = m_pAccessibleWidget;
173 Reference<XAccessible> xChild;
174 switch (aEvent.EventId)
176 case AccessibleEventId::NAME_CHANGED:
177 QAccessible::updateAccessibility(
178 new QAccessibleEvent(pQAccessibleInterface, QAccessible::NameChanged));
179 return;
180 case AccessibleEventId::DESCRIPTION_CHANGED:
181 QAccessible::updateAccessibility(
182 new QAccessibleEvent(pQAccessibleInterface, QAccessible::DescriptionChanged));
183 return;
184 case AccessibleEventId::ACTION_CHANGED:
185 QAccessible::updateAccessibility(
186 new QAccessibleEvent(pQAccessibleInterface, QAccessible::ActionChanged));
187 return;
188 case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED:
190 // Qt has a QAccessible::ActiveDescendantChanged event type, but events of
191 // that type are currently just ignored on Qt side and not forwarded to AT-SPI.
192 // Send a state change event for the focused state of the newly
193 // active descendant instead
194 uno::Reference<accessibility::XAccessible> xActiveAccessible;
195 aEvent.NewValue >>= xActiveAccessible;
196 if (!xActiveAccessible.is())
197 return;
199 QObject* pQtAcc = QtAccessibleRegistry::getQObject(xActiveAccessible);
200 QAccessibleInterface* pInterface = QAccessible::queryAccessibleInterface(pQtAcc);
201 QAccessible::State aState;
202 aState.focused = true;
203 QAccessible::updateAccessibility(new QAccessibleStateChangeEvent(pInterface, aState));
204 return;
206 case AccessibleEventId::CARET_CHANGED:
208 sal_Int32 nNewCursorPos = 0;
209 aEvent.NewValue >>= nNewCursorPos;
210 QAccessible::updateAccessibility(
211 new QAccessibleTextCursorEvent(pQAccessibleInterface, nNewCursorPos));
212 return;
214 case AccessibleEventId::CHILD:
216 QAccessible::Event event = QAccessible::InvalidEvent;
217 if (aEvent.OldValue >>= xChild)
218 event = QAccessible::ObjectDestroyed;
219 if (aEvent.NewValue >>= xChild)
220 event = QAccessible::ObjectCreated;
221 if (event != QAccessible::InvalidEvent)
222 QAccessible::updateAccessibility(
223 new QAccessibleEvent(pQAccessibleInterface, event));
224 return;
226 case AccessibleEventId::HYPERTEXT_CHANGED:
227 QAccessible::updateAccessibility(
228 new QAccessibleEvent(pQAccessibleInterface, QAccessible::HypertextChanged));
229 return;
230 case AccessibleEventId::SELECTION_CHANGED:
231 QAccessible::updateAccessibility(
232 new QAccessibleEvent(pQAccessibleInterface, QAccessible::Selection));
233 return;
234 case AccessibleEventId::VISIBLE_DATA_CHANGED:
235 QAccessible::updateAccessibility(
236 new QAccessibleEvent(pQAccessibleInterface, QAccessible::VisibleDataChanged));
237 return;
238 case AccessibleEventId::TEXT_SELECTION_CHANGED:
240 QAccessibleTextInterface* pTextInterface = pQAccessibleInterface->textInterface();
241 if (!pTextInterface)
243 SAL_WARN("vcl.qt", "TEXT_SELECTION_CHANGED event received for object not "
244 "implementing text interface");
245 return;
247 int nStartOffset = 0;
248 int nEndOffset = 0;
249 pTextInterface->selection(0, &nStartOffset, &nEndOffset);
250 QAccessible::updateAccessibility(
251 new QAccessibleTextSelectionEvent(pQAccessibleInterface, nStartOffset, nEndOffset));
252 return;
254 case AccessibleEventId::TEXT_ATTRIBUTE_CHANGED:
255 QAccessible::updateAccessibility(
256 new QAccessibleEvent(pQAccessibleInterface, QAccessible::AttributeChanged));
257 return;
258 case AccessibleEventId::TEXT_CHANGED:
260 TextSegment aDeletedText;
261 TextSegment aInsertedText;
262 if (aEvent.OldValue >>= aDeletedText)
264 QAccessible::updateAccessibility(
265 new QAccessibleTextRemoveEvent(pQAccessibleInterface, aDeletedText.SegmentStart,
266 toQString(aDeletedText.SegmentText)));
268 if (aEvent.NewValue >>= aInsertedText)
270 QAccessible::updateAccessibility(new QAccessibleTextInsertEvent(
271 pQAccessibleInterface, aInsertedText.SegmentStart,
272 toQString(aInsertedText.SegmentText)));
274 return;
276 case AccessibleEventId::TABLE_CAPTION_CHANGED:
277 QAccessible::updateAccessibility(
278 new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableCaptionChanged));
279 return;
280 case AccessibleEventId::TABLE_COLUMN_DESCRIPTION_CHANGED:
281 QAccessible::updateAccessibility(new QAccessibleEvent(
282 pQAccessibleInterface, QAccessible::TableColumnDescriptionChanged));
283 return;
284 case AccessibleEventId::TABLE_COLUMN_HEADER_CHANGED:
285 QAccessible::updateAccessibility(
286 new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableColumnHeaderChanged));
287 return;
288 case AccessibleEventId::TABLE_MODEL_CHANGED:
290 AccessibleTableModelChange aChange;
291 aEvent.NewValue >>= aChange;
293 QAccessibleTableModelChangeEvent::ModelChangeType nType;
294 switch (aChange.Type)
296 case AccessibleTableModelChangeType::COLUMNS_INSERTED:
297 nType = QAccessibleTableModelChangeEvent::ColumnsInserted;
298 break;
299 case AccessibleTableModelChangeType::COLUMNS_REMOVED:
300 nType = QAccessibleTableModelChangeEvent::ColumnsRemoved;
301 break;
302 case AccessibleTableModelChangeType::ROWS_INSERTED:
303 nType = QAccessibleTableModelChangeEvent::RowsInserted;
304 break;
305 case AccessibleTableModelChangeType::ROWS_REMOVED:
306 nType = QAccessibleTableModelChangeEvent::RowsRemoved;
307 break;
308 case AccessibleTableModelChangeType::UPDATE:
309 nType = QAccessibleTableModelChangeEvent::DataChanged;
310 break;
311 default:
312 assert(false && "Unhandled AccessibleTableModelChangeType");
313 return;
315 QAccessibleTableModelChangeEvent* pTableEvent
316 = new QAccessibleTableModelChangeEvent(pQAccessibleInterface, nType);
317 pTableEvent->setFirstRow(aChange.FirstRow);
318 pTableEvent->setLastRow(aChange.LastRow);
319 pTableEvent->setFirstColumn(aChange.FirstColumn);
320 pTableEvent->setLastColumn(aChange.LastColumn);
321 QAccessible::updateAccessibility(pTableEvent);
322 return;
324 case AccessibleEventId::TABLE_ROW_DESCRIPTION_CHANGED:
325 QAccessible::updateAccessibility(new QAccessibleEvent(
326 pQAccessibleInterface, QAccessible::TableRowDescriptionChanged));
327 return;
328 case AccessibleEventId::TABLE_ROW_HEADER_CHANGED:
329 QAccessible::updateAccessibility(
330 new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableRowHeaderChanged));
331 return;
332 case AccessibleEventId::TABLE_SUMMARY_CHANGED:
333 QAccessible::updateAccessibility(
334 new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableSummaryChanged));
335 return;
336 case AccessibleEventId::SELECTION_CHANGED_ADD:
337 case AccessibleEventId::SELECTION_CHANGED_REMOVE:
339 QAccessible::Event eEventType;
340 if (aEvent.EventId == AccessibleEventId::SELECTION_CHANGED_ADD)
341 eEventType = QAccessible::SelectionAdd;
342 else
343 eEventType = QAccessible::SelectionRemove;
345 uno::Reference<accessibility::XAccessible> xChildAcc;
346 aEvent.NewValue >>= xChildAcc;
347 if (!xChildAcc.is())
349 SAL_WARN("vcl.qt",
350 "Selection add/remove event without the (un)selected accessible set");
351 return;
353 Reference<XAccessibleContext> xContext = xChildAcc->getAccessibleContext();
354 if (!xContext.is())
356 SAL_WARN("vcl.qt", "No valid XAccessibleContext for (un)selected accessible.");
357 return;
360 // Qt expects the event to be sent for the (un)selected child
361 QObject* pChildObject = QtAccessibleRegistry::getQObject(xChildAcc);
362 assert(pChildObject);
363 QAccessible::updateAccessibility(new QAccessibleEvent(pChildObject, eEventType));
364 return;
366 case AccessibleEventId::SELECTION_CHANGED_WITHIN:
367 QAccessible::updateAccessibility(
368 new QAccessibleEvent(pQAccessibleInterface, QAccessible::SelectionWithin));
369 return;
370 case AccessibleEventId::PAGE_CHANGED:
371 QAccessible::updateAccessibility(
372 new QAccessibleEvent(pQAccessibleInterface, QAccessible::PageChanged));
373 return;
374 case AccessibleEventId::SECTION_CHANGED:
375 QAccessible::updateAccessibility(
376 new QAccessibleEvent(pQAccessibleInterface, QAccessible::SectionChanged));
377 return;
378 case AccessibleEventId::COLUMN_CHANGED:
379 QAccessible::updateAccessibility(
380 new QAccessibleEvent(pQAccessibleInterface, QAccessible::TextColumnChanged));
381 return;
382 case AccessibleEventId::BOUNDRECT_CHANGED:
383 QAccessible::updateAccessibility(
384 new QAccessibleEvent(pQAccessibleInterface, QAccessible::LocationChanged));
385 return;
386 case AccessibleEventId::STATE_CHANGED:
387 HandleStateChangedEvent(pQAccessibleInterface, aEvent);
388 return;
389 case AccessibleEventId::VALUE_CHANGED:
391 QAccessibleValueInterface* pValueInterface = pQAccessibleInterface->valueInterface();
392 if (pValueInterface)
394 const QVariant aValue = pValueInterface->currentValue();
395 QAccessible::updateAccessibility(
396 new QAccessibleValueChangeEvent(pQAccessibleInterface, aValue));
398 return;
400 case AccessibleEventId::ROLE_CHANGED:
401 case AccessibleEventId::INVALIDATE_ALL_CHILDREN:
402 case AccessibleEventId::CONTENT_FLOWS_FROM_RELATION_CHANGED:
403 case AccessibleEventId::CONTENT_FLOWS_TO_RELATION_CHANGED:
404 case AccessibleEventId::CONTROLLED_BY_RELATION_CHANGED:
405 case AccessibleEventId::CONTROLLER_FOR_RELATION_CHANGED:
406 case AccessibleEventId::LABEL_FOR_RELATION_CHANGED:
407 case AccessibleEventId::LABELED_BY_RELATION_CHANGED:
408 case AccessibleEventId::MEMBER_OF_RELATION_CHANGED:
409 case AccessibleEventId::SUB_WINDOW_OF_RELATION_CHANGED:
410 case AccessibleEventId::LISTBOX_ENTRY_EXPANDED:
411 case AccessibleEventId::LISTBOX_ENTRY_COLLAPSED:
412 case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS:
413 default:
414 SAL_WARN("vcl.qt", "Unmapped AccessibleEventId: " << aEvent.EventId);
415 return;
419 void QtAccessibleEventListener::disposing(const EventObject& /* Source */)
421 assert(m_pAccessibleWidget);
422 m_pAccessibleWidget->invalidate();
425 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */