Update git submodules
[LibreOffice.git] / vcl / qt5 / QtAccessibleWidget.cxx
blob7eadc331383492366cfc34f70c1e25c92688e0ea
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 <QtAccessibleWidget.hxx>
22 #include <QtGui/QAccessibleInterface>
24 #include <QtAccessibleEventListener.hxx>
25 #include <QtAccessibleRegistry.hxx>
26 #include <QtFrame.hxx>
27 #include <QtTools.hxx>
28 #include <QtWidget.hxx>
29 #include <QtXAccessible.hxx>
31 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
32 #include <com/sun/star/accessibility/AccessibleRole.hpp>
33 #include <com/sun/star/accessibility/AccessibleScrollType.hpp>
34 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
35 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
36 #include <com/sun/star/accessibility/XAccessible.hpp>
37 #include <com/sun/star/accessibility/XAccessibleAction.hpp>
38 #include <com/sun/star/accessibility/XAccessibleComponent.hpp>
39 #include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
40 #include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
41 #include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
42 #include <com/sun/star/accessibility/XAccessibleKeyBinding.hpp>
43 #include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
44 #include <com/sun/star/accessibility/XAccessibleSelection.hpp>
45 #include <com/sun/star/accessibility/XAccessibleTable.hpp>
46 #include <com/sun/star/accessibility/XAccessibleTableSelection.hpp>
47 #include <com/sun/star/accessibility/XAccessibleText.hpp>
48 #include <com/sun/star/accessibility/XAccessibleValue.hpp>
49 #include <com/sun/star/beans/PropertyValue.hpp>
50 #include <com/sun/star/lang/DisposedException.hpp>
51 #include <com/sun/star/uno/Sequence.hxx>
53 #include <comphelper/AccessibleImplementationHelper.hxx>
54 #include <o3tl/any.hxx>
55 #include <sal/log.hxx>
56 #include <vcl/accessibility/AccessibleTextAttributeHelper.hxx>
58 using namespace css;
59 using namespace css::accessibility;
60 using namespace css::beans;
61 using namespace css::uno;
63 QtAccessibleWidget::QtAccessibleWidget(const Reference<XAccessible> xAccessible, QObject* pObject)
64 : m_xAccessible(xAccessible)
65 , m_pObject(pObject)
67 Reference<XAccessibleContext> xContext = xAccessible->getAccessibleContext();
68 Reference<XAccessibleEventBroadcaster> xBroadcaster(xContext, UNO_QUERY);
69 if (xBroadcaster.is())
71 Reference<XAccessibleEventListener> xListener(new QtAccessibleEventListener(this));
72 xBroadcaster->addAccessibleEventListener(xListener);
76 void QtAccessibleWidget::invalidate()
78 QtAccessibleRegistry::remove(m_xAccessible);
79 m_xAccessible.clear();
82 Reference<XAccessibleContext> QtAccessibleWidget::getAccessibleContextImpl() const
84 Reference<XAccessibleContext> xAc;
86 if (m_xAccessible.is())
88 try
90 xAc = m_xAccessible->getAccessibleContext();
92 catch (css::lang::DisposedException /*ex*/)
94 SAL_WARN("vcl.qt", "Accessible context disposed already");
96 // sometimes getAccessibleContext throws also RuntimeException if context is no longer alive
97 catch (css::uno::RuntimeException /*ex*/)
99 // so let's catch it here, cuz otherwise soffice falls flat on its face
100 // with FatalError and nothing else
101 SAL_WARN("vcl.qt", "Accessible context no longer alive");
105 return xAc;
108 css::uno::Reference<css::accessibility::XAccessibleTable>
109 QtAccessibleWidget::getAccessibleTableForParent() const
111 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
112 if (!xAcc.is())
113 return nullptr;
115 Reference<XAccessible> xParent = xAcc->getAccessibleParent();
116 if (!xParent.is())
117 return nullptr;
119 Reference<XAccessibleContext> xParentContext = xParent->getAccessibleContext();
120 if (!xParentContext.is())
121 return nullptr;
123 return Reference<XAccessibleTable>(xParentContext, UNO_QUERY);
126 QWindow* QtAccessibleWidget::window() const
128 assert(m_pObject);
129 if (m_pObject->isWidgetType())
131 QWidget* pWidget = static_cast<QWidget*>(m_pObject);
132 QWidget* pWindow = pWidget->window();
133 if (pWindow)
134 return pWindow->windowHandle();
137 QAccessibleInterface* pParent = parent();
138 if (pParent)
139 return pParent->window();
141 return nullptr;
144 int QtAccessibleWidget::childCount() const
146 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
147 if (!xAc.is())
148 return 0;
150 sal_Int64 nChildCount = xAc->getAccessibleChildCount();
151 if (nChildCount > std::numeric_limits<int>::max())
153 SAL_WARN("vcl.qt", "QtAccessibleWidget::childCount: Child count exceeds maximum int value, "
154 "returning max int.");
155 nChildCount = std::numeric_limits<int>::max();
158 return nChildCount;
161 int QtAccessibleWidget::indexOfChild(const QAccessibleInterface* pChild) const
163 const QtAccessibleWidget* pAccessibleWidget = dynamic_cast<const QtAccessibleWidget*>(pChild);
164 if (!pAccessibleWidget)
166 SAL_WARN(
167 "vcl.qt",
168 "QtAccessibleWidget::indexOfChild called with child that is no QtAccessibleWidget");
169 return -1;
172 Reference<XAccessibleContext> xContext = pAccessibleWidget->getAccessibleContextImpl();
173 if (!xContext.is())
174 return -1;
176 sal_Int64 nChildIndex = xContext->getAccessibleIndexInParent();
177 if (nChildIndex > std::numeric_limits<int>::max())
179 // use -2 when the child index is too large to fit into 32 bit to neither use the
180 // valid index of another child nor -1, which would e.g. make the Orca screen reader
181 // interpret the object as being a zombie
182 SAL_WARN("vcl.qt",
183 "QtAccessibleWidget::indexOfChild: Child index exceeds maximum int value, "
184 "returning -2.");
185 nChildIndex = -2;
187 return nChildIndex;
190 namespace
192 sal_Int16 lcl_matchQtTextBoundaryType(QAccessible::TextBoundaryType boundaryType)
194 switch (boundaryType)
196 case QAccessible::CharBoundary:
197 return com::sun::star::accessibility::AccessibleTextType::CHARACTER;
198 case QAccessible::WordBoundary:
199 return com::sun::star::accessibility::AccessibleTextType::WORD;
200 case QAccessible::SentenceBoundary:
201 return com::sun::star::accessibility::AccessibleTextType::SENTENCE;
202 case QAccessible::ParagraphBoundary:
203 return com::sun::star::accessibility::AccessibleTextType::PARAGRAPH;
204 case QAccessible::LineBoundary:
205 return com::sun::star::accessibility::AccessibleTextType::LINE;
206 case QAccessible::NoBoundary:
207 // assert here, better handle it directly at call site
208 assert(false
209 && "No match for QAccessible::NoBoundary, handle it separately at call site.");
210 break;
211 default:
212 break;
215 SAL_WARN("vcl.qt", "Unmatched text boundary type: " << boundaryType);
216 return -1;
219 QAccessible::Relation lcl_matchUnoRelation(short relationType)
221 // Qt semantics is the other way around
222 switch (relationType)
224 #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
225 case AccessibleRelationType::CONTENT_FLOWS_FROM:
226 return QAccessible::FlowsTo;
227 case AccessibleRelationType::CONTENT_FLOWS_TO:
228 return QAccessible::FlowsFrom;
229 #endif
230 case AccessibleRelationType::CONTROLLED_BY:
231 return QAccessible::Controller;
232 case AccessibleRelationType::CONTROLLER_FOR:
233 return QAccessible::Controlled;
234 #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
235 case AccessibleRelationType::DESCRIBED_BY:
236 return QAccessible::DescriptionFor;
237 #endif
238 case AccessibleRelationType::LABELED_BY:
239 return QAccessible::Label;
240 case AccessibleRelationType::LABEL_FOR:
241 return QAccessible::Labelled;
242 case AccessibleRelationType::INVALID:
243 case AccessibleRelationType::MEMBER_OF:
244 case AccessibleRelationType::SUB_WINDOW_OF:
245 case AccessibleRelationType::NODE_CHILD_OF:
246 default:
247 SAL_WARN("vcl.qt", "Unmatched relation: " << relationType);
248 return {};
252 void lcl_appendRelation(QVector<QPair<QAccessibleInterface*, QAccessible::Relation>>* relations,
253 AccessibleRelation aRelation, QAccessible::Relation match)
255 QAccessible::Relation aQRelation = lcl_matchUnoRelation(aRelation.RelationType);
256 // skip in case there's no Qt relation matching the filter
257 if (!(aQRelation & match))
258 return;
260 sal_uInt32 nTargetCount = aRelation.TargetSet.getLength();
262 for (sal_uInt32 i = 0; i < nTargetCount; i++)
264 Reference<XAccessible> xAccessible(aRelation.TargetSet[i], uno::UNO_QUERY);
265 relations->append(
266 { QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xAccessible)),
267 aQRelation });
272 QVector<QPair<QAccessibleInterface*, QAccessible::Relation>>
273 QtAccessibleWidget::relations(QAccessible::Relation match) const
275 QVector<QPair<QAccessibleInterface*, QAccessible::Relation>> relations;
277 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
278 if (!xAc.is())
279 return relations;
281 Reference<XAccessibleRelationSet> xRelationSet = xAc->getAccessibleRelationSet();
282 if (xRelationSet.is())
284 int count = xRelationSet->getRelationCount();
285 for (int i = 0; i < count; i++)
287 AccessibleRelation aRelation = xRelationSet->getRelation(i);
288 lcl_appendRelation(&relations, aRelation, match);
292 return relations;
295 QAccessibleInterface* QtAccessibleWidget::focusChild() const
297 /* if (m_pWindow->HasChildPathFocus())
298 return QAccessible::queryAccessibleInterface(
299 new QtXAccessible(m_xAccessible->getAccessibleContext()->getAccessibleChild(index))); */
300 return QAccessible::queryAccessibleInterface(object());
303 QRect QtAccessibleWidget::rect() const
305 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
306 if (!xAc.is())
307 return QRect();
309 Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY);
310 awt::Point aPoint = xAccessibleComponent->getLocationOnScreen();
311 awt::Size aSize = xAccessibleComponent->getSize();
313 return QRect(aPoint.X, aPoint.Y, aSize.Width, aSize.Height);
316 QAccessibleInterface* QtAccessibleWidget::parent() const
318 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
319 if (!xAc.is())
320 return nullptr;
322 if (xAc->getAccessibleParent().is())
323 return QAccessible::queryAccessibleInterface(
324 QtAccessibleRegistry::getQObject(xAc->getAccessibleParent()));
326 // go via the QObject hierarchy; some a11y objects like the application
327 // (at the root of the a11y hierarchy) are handled solely by Qt and have
328 // no LO-internal a11y objects associated with them
329 QObject* pObj = object();
330 if (pObj && pObj->parent())
331 return QAccessible::queryAccessibleInterface(pObj->parent());
333 // return app as parent for top-level objects
334 return QAccessible::queryAccessibleInterface(qApp);
337 QAccessibleInterface* QtAccessibleWidget::child(int index) const
339 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
340 if (!xAc.is())
341 return nullptr;
343 if (index < 0 || index >= xAc->getAccessibleChildCount())
345 SAL_WARN("vcl.qt", "QtAccessibleWidget::child called with invalid index: " << index);
346 return nullptr;
349 return QAccessible::queryAccessibleInterface(
350 QtAccessibleRegistry::getQObject(xAc->getAccessibleChild(index)));
353 QString QtAccessibleWidget::text(QAccessible::Text text) const
355 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
356 if (!xAc.is())
357 return QString();
359 switch (text)
361 case QAccessible::Name:
362 return toQString(xAc->getAccessibleName());
363 case QAccessible::Description:
364 case QAccessible::DebugDescription:
365 return toQString(xAc->getAccessibleDescription());
366 case QAccessible::Value:
367 case QAccessible::Help:
368 case QAccessible::Accelerator:
369 case QAccessible::UserText:
370 default:
371 return QString("Unknown");
374 QAccessible::Role QtAccessibleWidget::role() const
376 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
377 if (!xAc.is())
378 return QAccessible::NoRole;
380 switch (xAc->getAccessibleRole())
382 case AccessibleRole::UNKNOWN:
383 return QAccessible::NoRole;
384 case AccessibleRole::ALERT:
385 return QAccessible::AlertMessage;
386 case AccessibleRole::COLUMN_HEADER:
387 return QAccessible::ColumnHeader;
388 case AccessibleRole::CANVAS:
389 return QAccessible::Canvas;
390 case AccessibleRole::CHECK_BOX:
391 return QAccessible::CheckBox;
392 case AccessibleRole::CHECK_MENU_ITEM:
393 return QAccessible::MenuItem;
394 case AccessibleRole::COLOR_CHOOSER:
395 return QAccessible::ColorChooser;
396 case AccessibleRole::COMBO_BOX:
397 return QAccessible::ComboBox;
398 case AccessibleRole::DATE_EDITOR:
399 return QAccessible::EditableText;
400 case AccessibleRole::DESKTOP_ICON:
401 return QAccessible::Graphic;
402 case AccessibleRole::DESKTOP_PANE:
403 case AccessibleRole::DIRECTORY_PANE:
404 return QAccessible::Pane;
405 case AccessibleRole::DIALOG:
406 return QAccessible::Dialog;
407 case AccessibleRole::DOCUMENT:
408 return QAccessible::Document;
409 case AccessibleRole::EMBEDDED_OBJECT:
410 return QAccessible::UserRole;
411 case AccessibleRole::END_NOTE:
412 return QAccessible::Note;
413 case AccessibleRole::FILE_CHOOSER:
414 return QAccessible::Dialog;
415 case AccessibleRole::FILLER:
416 return QAccessible::Whitespace;
417 case AccessibleRole::FONT_CHOOSER:
418 return QAccessible::UserRole;
419 case AccessibleRole::FOOTER:
420 return QAccessible::Footer;
421 case AccessibleRole::FOOTNOTE:
422 return QAccessible::Note;
423 case AccessibleRole::FRAME: // top-level window with title bar
424 return QAccessible::Window;
425 case AccessibleRole::GLASS_PANE:
426 return QAccessible::UserRole;
427 case AccessibleRole::GRAPHIC:
428 return QAccessible::Graphic;
429 case AccessibleRole::GROUP_BOX:
430 return QAccessible::Grouping;
431 case AccessibleRole::HEADER:
432 return QAccessible::UserRole;
433 case AccessibleRole::HEADING:
434 return QAccessible::Heading;
435 case AccessibleRole::HYPER_LINK:
436 return QAccessible::Link;
437 case AccessibleRole::ICON:
438 return QAccessible::Graphic;
439 case AccessibleRole::INTERNAL_FRAME:
440 return QAccessible::UserRole;
441 case AccessibleRole::LABEL:
442 return QAccessible::StaticText;
443 case AccessibleRole::LAYERED_PANE:
444 return QAccessible::Pane;
445 case AccessibleRole::LIST:
446 return QAccessible::List;
447 case AccessibleRole::LIST_ITEM:
448 return QAccessible::ListItem;
449 case AccessibleRole::MENU:
450 case AccessibleRole::MENU_BAR:
451 return QAccessible::MenuBar;
452 case AccessibleRole::MENU_ITEM:
453 return QAccessible::MenuItem;
454 case AccessibleRole::NOTIFICATION:
455 return QAccessible::Notification;
456 case AccessibleRole::OPTION_PANE:
457 return QAccessible::Pane;
458 case AccessibleRole::PAGE_TAB:
459 return QAccessible::PageTab;
460 case AccessibleRole::PAGE_TAB_LIST:
461 return QAccessible::PageTabList;
462 case AccessibleRole::PANEL:
463 return QAccessible::Pane;
464 case AccessibleRole::PARAGRAPH:
465 case AccessibleRole::BLOCK_QUOTE:
466 return QAccessible::Paragraph;
467 case AccessibleRole::PASSWORD_TEXT:
468 // Qt API doesn't have a separate role to distinguish password edits,
469 // but a 'passwordEdit' state
470 return QAccessible::EditableText;
471 case AccessibleRole::POPUP_MENU:
472 return QAccessible::PopupMenu;
473 case AccessibleRole::PUSH_BUTTON:
474 return QAccessible::Button;
475 case AccessibleRole::PROGRESS_BAR:
476 return QAccessible::ProgressBar;
477 case AccessibleRole::RADIO_BUTTON:
478 return QAccessible::RadioButton;
479 case AccessibleRole::RADIO_MENU_ITEM:
480 return QAccessible::MenuItem;
481 case AccessibleRole::ROW_HEADER:
482 return QAccessible::RowHeader;
483 case AccessibleRole::ROOT_PANE:
484 return QAccessible::Pane;
485 case AccessibleRole::SCROLL_BAR:
486 return QAccessible::ScrollBar;
487 case AccessibleRole::SCROLL_PANE:
488 return QAccessible::Pane;
489 case AccessibleRole::SHAPE:
490 return QAccessible::Graphic;
491 case AccessibleRole::SEPARATOR:
492 return QAccessible::Separator;
493 case AccessibleRole::SLIDER:
494 return QAccessible::Slider;
495 case AccessibleRole::SPIN_BOX:
496 return QAccessible::SpinBox;
497 case AccessibleRole::SPLIT_PANE:
498 return QAccessible::Pane;
499 case AccessibleRole::STATUS_BAR:
500 return QAccessible::StatusBar;
501 case AccessibleRole::TABLE:
502 return QAccessible::Table;
503 case AccessibleRole::TABLE_CELL:
504 return QAccessible::Cell;
505 case AccessibleRole::TEXT:
506 return QAccessible::EditableText;
507 case AccessibleRole::TEXT_FRAME:
508 return QAccessible::UserRole;
509 case AccessibleRole::TOGGLE_BUTTON:
510 return QAccessible::Button;
511 case AccessibleRole::TOOL_BAR:
512 return QAccessible::ToolBar;
513 case AccessibleRole::TOOL_TIP:
514 return QAccessible::ToolTip;
515 case AccessibleRole::TREE:
516 return QAccessible::Tree;
517 case AccessibleRole::VIEW_PORT:
518 return QAccessible::UserRole;
519 case AccessibleRole::BUTTON_DROPDOWN:
520 return QAccessible::ButtonDropDown;
521 case AccessibleRole::BUTTON_MENU:
522 return QAccessible::ButtonMenu;
523 case AccessibleRole::CAPTION:
524 return QAccessible::StaticText;
525 case AccessibleRole::CHART:
526 return QAccessible::Chart;
527 case AccessibleRole::EDIT_BAR:
528 return QAccessible::Equation;
529 case AccessibleRole::FORM:
530 return QAccessible::Form;
531 case AccessibleRole::IMAGE_MAP:
532 return QAccessible::Graphic;
533 case AccessibleRole::NOTE:
534 return QAccessible::Note;
535 case AccessibleRole::RULER:
536 return QAccessible::UserRole;
537 case AccessibleRole::SECTION:
538 return QAccessible::Section;
539 case AccessibleRole::TREE_ITEM:
540 return QAccessible::TreeItem;
541 case AccessibleRole::TREE_TABLE:
542 return QAccessible::Tree;
543 case AccessibleRole::COMMENT:
544 return QAccessible::Note;
545 case AccessibleRole::COMMENT_END:
546 return QAccessible::UserRole;
547 case AccessibleRole::DOCUMENT_PRESENTATION:
548 return QAccessible::Document;
549 case AccessibleRole::DOCUMENT_SPREADSHEET:
550 return QAccessible::Document;
551 case AccessibleRole::DOCUMENT_TEXT:
552 return QAccessible::Document;
553 case AccessibleRole::STATIC:
554 return QAccessible::StaticText;
555 case AccessibleRole::WINDOW: // top-level window without title bar
556 return QAccessible::Window;
559 SAL_WARN("vcl.qt", "Unmapped role: " << getAccessibleContextImpl()->getAccessibleRole());
560 return QAccessible::NoRole;
563 namespace
565 void lcl_addState(QAccessible::State* state, sal_Int64 nState)
567 switch (nState)
569 case AccessibleStateType::INVALID:
570 state->invalid = true;
571 break;
572 case AccessibleStateType::ACTIVE:
573 state->active = true;
574 break;
575 case AccessibleStateType::ARMED:
576 // No match
577 break;
578 case AccessibleStateType::BUSY:
579 state->busy = true;
580 break;
581 case AccessibleStateType::CHECKABLE:
582 state->checkable = true;
583 break;
584 case AccessibleStateType::CHECKED:
585 state->checked = true;
586 break;
587 case AccessibleStateType::EDITABLE:
588 state->editable = true;
589 break;
590 case AccessibleStateType::ENABLED:
591 state->disabled = false;
592 break;
593 case AccessibleStateType::EXPANDABLE:
594 state->expandable = true;
595 break;
596 case AccessibleStateType::EXPANDED:
597 state->expanded = true;
598 break;
599 case AccessibleStateType::FOCUSABLE:
600 state->focusable = true;
601 break;
602 case AccessibleStateType::FOCUSED:
603 state->focused = true;
604 break;
605 case AccessibleStateType::HORIZONTAL:
606 // No match
607 break;
608 case AccessibleStateType::ICONIFIED:
609 // No match
610 break;
611 case AccessibleStateType::INDETERMINATE:
612 state->checkStateMixed = true;
613 break;
614 case AccessibleStateType::MANAGES_DESCENDANTS:
615 // No match
616 break;
617 case AccessibleStateType::MODAL:
618 state->modal = true;
619 break;
620 case AccessibleStateType::MOVEABLE:
621 state->movable = true;
622 break;
623 case AccessibleStateType::MULTI_LINE:
624 state->multiLine = true;
625 break;
626 case AccessibleStateType::OPAQUE:
627 // No match
628 break;
629 case AccessibleStateType::PRESSED:
630 state->pressed = true;
631 break;
632 case AccessibleStateType::RESIZABLE:
633 state->sizeable = true;
634 break;
635 case AccessibleStateType::SELECTABLE:
636 state->selectable = true;
637 break;
638 case AccessibleStateType::SELECTED:
639 state->selected = true;
640 break;
641 case AccessibleStateType::SENSITIVE:
642 // No match
643 break;
644 case AccessibleStateType::SHOWING:
645 // No match
646 break;
647 case AccessibleStateType::SINGLE_LINE:
648 // No match
649 break;
650 case AccessibleStateType::STALE:
651 // No match
652 break;
653 case AccessibleStateType::TRANSIENT:
654 // No match
655 break;
656 case AccessibleStateType::VERTICAL:
657 // No match
658 break;
659 case AccessibleStateType::VISIBLE:
660 state->invisible = false;
661 break;
662 case AccessibleStateType::DEFAULT:
663 // No match
664 break;
665 case AccessibleStateType::DEFUNC:
666 state->invalid = true;
667 break;
668 case AccessibleStateType::MULTI_SELECTABLE:
669 state->multiSelectable = true;
670 break;
671 default:
672 SAL_WARN("vcl.qt", "Unmapped state: " << nState);
673 break;
678 QAccessible::State QtAccessibleWidget::state() const
680 QAccessible::State state;
682 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
683 if (!xAc.is())
684 return state;
686 sal_Int64 nStateSet(xAc->getAccessibleStateSet());
688 for (int i = 0; i < 63; ++i)
690 sal_Int64 nState = sal_Int64(1) << i;
691 if (nStateSet & nState)
692 lcl_addState(&state, nState);
695 if (xAc->getAccessibleRole() == AccessibleRole::PASSWORD_TEXT)
696 state.passwordEdit = true;
698 return state;
701 QColor QtAccessibleWidget::foregroundColor() const
703 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
704 if (!xAc.is())
705 return QColor();
707 Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY);
708 return toQColor(Color(ColorTransparency, xAccessibleComponent->getForeground()));
711 QColor QtAccessibleWidget::backgroundColor() const
713 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
714 if (!xAc.is())
715 return QColor();
717 Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY);
718 return toQColor(Color(ColorTransparency, xAccessibleComponent->getBackground()));
721 void* QtAccessibleWidget::interface_cast(QAccessible::InterfaceType t)
723 if (t == QAccessible::ActionInterface && accessibleProvidesInterface<XAccessibleAction>())
724 return static_cast<QAccessibleActionInterface*>(this);
725 if (t == QAccessible::TextInterface && accessibleProvidesInterface<XAccessibleText>())
726 return static_cast<QAccessibleTextInterface*>(this);
727 if (t == QAccessible::EditableTextInterface
728 && accessibleProvidesInterface<XAccessibleEditableText>())
729 return static_cast<QAccessibleEditableTextInterface*>(this);
730 if (t == QAccessible::ValueInterface && accessibleProvidesInterface<XAccessibleValue>())
731 return static_cast<QAccessibleValueInterface*>(this);
732 if (t == QAccessible::TableCellInterface)
734 // parent must be a table
735 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
736 if (xTable.is())
737 return static_cast<QAccessibleTableCellInterface*>(this);
739 if (t == QAccessible::TableInterface && accessibleProvidesInterface<XAccessibleTable>())
740 return static_cast<QAccessibleTableInterface*>(this);
741 #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
742 if (t == QAccessible::SelectionInterface && accessibleProvidesInterface<XAccessibleSelection>())
743 return static_cast<QAccessibleSelectionInterface*>(this);
744 #endif
745 return nullptr;
748 bool QtAccessibleWidget::isValid() const
750 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
751 return xAc.is();
754 QObject* QtAccessibleWidget::object() const { return m_pObject; }
756 void QtAccessibleWidget::setText(QAccessible::Text /* t */, const QString& /* text */) {}
758 QAccessibleInterface* QtAccessibleWidget::childAt(int x, int y) const
760 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
761 if (!xAc.is())
762 return nullptr;
764 Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY);
765 // convert from screen to local coordinates
766 QPoint aLocalCoords = QPoint(x, y) - rect().topLeft();
767 return QAccessible::queryAccessibleInterface(
768 QtAccessibleRegistry::getQObject(xAccessibleComponent->getAccessibleAtPoint(
769 awt::Point(aLocalCoords.x(), aLocalCoords.y()))));
772 QAccessibleInterface* QtAccessibleWidget::customFactory(const QString& classname, QObject* object)
774 if (classname == QLatin1String("QtWidget") && object && object->isWidgetType())
776 QtWidget* pWidget = static_cast<QtWidget*>(object);
777 vcl::Window* pWindow = pWidget->frame().GetWindow();
779 if (pWindow)
781 css::uno::Reference<XAccessible> xAcc = pWindow->GetAccessible();
782 // insert into registry so the association between the XAccessible and the QtWidget
783 // is remembered rather than creating a different QtXAccessible when a QObject is needed later
784 QtAccessibleRegistry::insert(xAcc, object);
785 return new QtAccessibleWidget(xAcc, object);
788 if (classname == QLatin1String("QtXAccessible") && object)
790 QtXAccessible* pXAccessible = static_cast<QtXAccessible*>(object);
791 if (pXAccessible->m_xAccessible.is())
793 QtAccessibleWidget* pRet = new QtAccessibleWidget(pXAccessible->m_xAccessible, object);
794 // clear the reference in the QtXAccessible, no longer needed now that the QtAccessibleWidget holds one
795 pXAccessible->m_xAccessible.clear();
796 return pRet;
800 return nullptr;
803 // QAccessibleActionInterface
804 QStringList QtAccessibleWidget::actionNames() const
806 QStringList actionNames;
807 Reference<XAccessibleAction> xAccessibleAction(getAccessibleContextImpl(), UNO_QUERY);
808 if (!xAccessibleAction.is())
809 return actionNames;
811 int count = xAccessibleAction->getAccessibleActionCount();
812 for (int i = 0; i < count; i++)
814 OUString desc = xAccessibleAction->getAccessibleActionDescription(i);
815 actionNames.append(toQString(desc));
817 return actionNames;
820 void QtAccessibleWidget::doAction(const QString& actionName)
822 Reference<XAccessibleAction> xAccessibleAction(getAccessibleContextImpl(), UNO_QUERY);
823 if (!xAccessibleAction.is())
824 return;
826 int index = actionNames().indexOf(actionName);
827 if (index == -1)
828 return;
829 xAccessibleAction->doAccessibleAction(index);
832 QStringList QtAccessibleWidget::keyBindingsForAction(const QString& actionName) const
834 QStringList keyBindings;
835 Reference<XAccessibleAction> xAccessibleAction(getAccessibleContextImpl(), UNO_QUERY);
836 if (!xAccessibleAction.is())
837 return keyBindings;
839 int index = actionNames().indexOf(actionName);
840 if (index == -1)
841 return keyBindings;
843 Reference<XAccessibleKeyBinding> xKeyBinding
844 = xAccessibleAction->getAccessibleActionKeyBinding(index);
846 if (!xKeyBinding.is())
847 return keyBindings;
849 int count = xKeyBinding->getAccessibleKeyBindingCount();
850 for (int i = 0; i < count; i++)
852 Sequence<awt::KeyStroke> keyStroke = xKeyBinding->getAccessibleKeyBinding(i);
853 keyBindings.append(toQString(comphelper::GetkeyBindingStrByXkeyBinding(keyStroke)));
855 return keyBindings;
858 // QAccessibleTextInterface
859 void QtAccessibleWidget::addSelection(int /* startOffset */, int /* endOffset */)
861 SAL_INFO("vcl.qt", "Unsupported QAccessibleTextInterface::addSelection");
864 // Text attributes are returned in format specified in IAccessible2 spec, since that
865 // is what Qt handles:
866 // https://wiki.linuxfoundation.org/accessibility/iaccessible2/textattributes
867 QString QtAccessibleWidget::attributes(int offset, int* startOffset, int* endOffset) const
869 if (startOffset == nullptr || endOffset == nullptr)
870 return QString();
872 *startOffset = -1;
873 *endOffset = -1;
875 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
876 if (!xText.is())
877 return QString();
879 // handle special values for offset the same way base class's QAccessibleTextWidget::attributes does
880 // (as defined in IAccessible 2: -1 -> length, -2 -> cursor position)
881 if (offset == -2)
882 offset = cursorPosition();
884 const int nTextLength = characterCount();
885 if (offset == -1 || offset == nTextLength)
886 offset = nTextLength - 1;
888 if (offset < 0 || offset > nTextLength)
890 SAL_WARN("vcl.qt", "QtAccessibleWidget::attributes called with invalid offset: " << offset);
891 return QString();
894 // Qt doesn't have the strict separation into text and object attributes, but also
895 // supports text-specific attributes that are object attributes according to the
896 // IAccessible2 spec.
897 sal_Int32 nStart = 0;
898 sal_Int32 nEnd = 0;
899 const OUString aRet = AccessibleTextAttributeHelper::GetIAccessible2TextAttributes(
900 xText, IA2AttributeType::TextAttributes | IA2AttributeType::ObjectAttributes,
901 static_cast<sal_Int32>(offset), nStart, nEnd);
902 *startOffset = static_cast<int>(nStart);
903 *endOffset = static_cast<int>(nEnd);
904 return toQString(aRet);
907 int QtAccessibleWidget::characterCount() const
909 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
910 if (xText.is())
911 return xText->getCharacterCount();
912 return 0;
915 QRect QtAccessibleWidget::characterRect(int nOffset) const
917 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
918 if (!xText.is())
919 return QRect();
921 if (nOffset < 0 || nOffset > xText->getCharacterCount())
923 SAL_WARN("vcl.qt",
924 "QtAccessibleWidget::characterRect called with invalid offset: " << nOffset);
925 return QRect();
928 const awt::Rectangle aBounds = xText->getCharacterBounds(nOffset);
929 const QRect aRect(aBounds.X, aBounds.Y, aBounds.Width, aBounds.Height);
930 // convert to screen coordinates
931 const QRect aScreenPos = rect();
932 return aRect.translated(aScreenPos.x(), aScreenPos.y());
935 int QtAccessibleWidget::cursorPosition() const
937 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
938 if (xText.is())
939 return xText->getCaretPosition();
940 return 0;
943 int QtAccessibleWidget::offsetAtPoint(const QPoint& rPoint) const
945 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
946 if (!xText.is())
947 return -1;
949 // convert from screen to local coordinates
950 QPoint aLocalCoords = rPoint - rect().topLeft();
951 awt::Point aPoint(aLocalCoords.x(), aLocalCoords.y());
952 return xText->getIndexAtPoint(aPoint);
955 void QtAccessibleWidget::removeSelection(int /* selectionIndex */)
957 SAL_INFO("vcl.qt", "Unsupported QAccessibleTextInterface::removeSelection");
960 void QtAccessibleWidget::scrollToSubstring(int startIndex, int endIndex)
962 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
963 if (!xText.is())
964 return;
966 sal_Int32 nTextLength = xText->getCharacterCount();
967 if (startIndex < 0 || startIndex > nTextLength || endIndex < 0 || endIndex > nTextLength)
969 SAL_WARN("vcl.qt", "QtAccessibleWidget::scrollToSubstring called with invalid offset.");
970 return;
973 xText->scrollSubstringTo(startIndex, endIndex, AccessibleScrollType_SCROLL_ANYWHERE);
976 void QtAccessibleWidget::selection(int selectionIndex, int* startOffset, int* endOffset) const
978 if (!startOffset && !endOffset)
979 return;
981 Reference<XAccessibleText> xText;
982 if (selectionIndex == 0)
983 xText = Reference<XAccessibleText>(getAccessibleContextImpl(), UNO_QUERY);
985 if (startOffset)
986 *startOffset = xText.is() ? xText->getSelectionStart() : 0;
987 if (endOffset)
988 *endOffset = xText.is() ? xText->getSelectionEnd() : 0;
991 int QtAccessibleWidget::selectionCount() const
993 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
994 if (xText.is() && !xText->getSelectedText().isEmpty())
995 return 1; // Only 1 selection supported atm
996 return 0;
999 void QtAccessibleWidget::setCursorPosition(int position)
1001 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1002 if (!xText.is())
1003 return;
1005 if (position < 0 || position > xText->getCharacterCount())
1007 SAL_WARN("vcl.qt",
1008 "QtAccessibleWidget::setCursorPosition called with invalid offset: " << position);
1009 return;
1012 xText->setCaretPosition(position);
1015 void QtAccessibleWidget::setSelection(int /* selectionIndex */, int startOffset, int endOffset)
1017 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1018 if (!xText.is())
1019 return;
1021 sal_Int32 nTextLength = xText->getCharacterCount();
1022 if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength)
1024 SAL_WARN("vcl.qt", "QtAccessibleWidget::setSelection called with invalid offset.");
1025 return;
1028 xText->setSelection(startOffset, endOffset);
1031 QString QtAccessibleWidget::text(int startOffset, int endOffset) const
1033 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1034 if (!xText.is())
1035 return QString();
1037 sal_Int32 nTextLength = xText->getCharacterCount();
1038 if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength)
1040 SAL_WARN("vcl.qt", "QtAccessibleWidget::text called with invalid offset.");
1041 return QString();
1044 return toQString(xText->getTextRange(startOffset, endOffset));
1047 QString QtAccessibleWidget::textAfterOffset(int nOffset,
1048 QAccessible::TextBoundaryType eBoundaryType,
1049 int* pStartOffset, int* pEndOffset) const
1051 if (pStartOffset == nullptr || pEndOffset == nullptr)
1052 return QString();
1054 *pStartOffset = -1;
1055 *pEndOffset = -1;
1057 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1058 if (!xText.is())
1059 return QString();
1061 const int nCharCount = characterCount();
1062 // -1 is special value for text length
1063 if (nOffset == -1)
1064 nOffset = nCharCount;
1065 else if (nOffset < -1 || nOffset > nCharCount)
1067 SAL_WARN("vcl.qt",
1068 "QtAccessibleWidget::textAfterOffset called with invalid offset: " << nOffset);
1069 return QString();
1072 if (eBoundaryType == QAccessible::NoBoundary)
1074 if (nOffset == nCharCount)
1075 return QString();
1076 *pStartOffset = nOffset + 1;
1077 *pEndOffset = nCharCount;
1078 return text(nOffset + 1, nCharCount);
1081 sal_Int16 nUnoBoundaryType = lcl_matchQtTextBoundaryType(eBoundaryType);
1082 assert(nUnoBoundaryType > 0);
1083 const TextSegment aSegment = xText->getTextBehindIndex(nOffset, nUnoBoundaryType);
1084 *pStartOffset = aSegment.SegmentStart;
1085 *pEndOffset = aSegment.SegmentEnd;
1086 return toQString(aSegment.SegmentText);
1089 QString QtAccessibleWidget::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType,
1090 int* startOffset, int* endOffset) const
1092 if (startOffset == nullptr || endOffset == nullptr)
1093 return QString();
1095 const int nCharCount = characterCount();
1096 if (boundaryType == QAccessible::NoBoundary)
1098 *startOffset = 0;
1099 *endOffset = nCharCount;
1100 return text(0, nCharCount);
1103 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1104 if (!xText.is())
1105 return QString();
1107 sal_Int16 nUnoBoundaryType = lcl_matchQtTextBoundaryType(boundaryType);
1108 assert(nUnoBoundaryType > 0);
1110 // special value of -1 for offset means text length
1111 if (offset == -1)
1112 offset = nCharCount;
1114 if (offset < 0 || offset > nCharCount)
1116 SAL_WARN("vcl.qt",
1117 "QtAccessibleWidget::textAtOffset called with invalid offset: " << offset);
1118 return QString();
1121 const TextSegment segment = xText->getTextAtIndex(offset, nUnoBoundaryType);
1122 *startOffset = segment.SegmentStart;
1123 *endOffset = segment.SegmentEnd;
1124 return toQString(segment.SegmentText);
1127 QString QtAccessibleWidget::textBeforeOffset(int nOffset,
1128 QAccessible::TextBoundaryType eBoundaryType,
1129 int* pStartOffset, int* pEndOffset) const
1131 if (pStartOffset == nullptr || pEndOffset == nullptr)
1132 return QString();
1134 *pStartOffset = -1;
1135 *pEndOffset = -1;
1137 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1138 if (!xText.is())
1139 return QString();
1141 const int nCharCount = characterCount();
1142 // -1 is special value for text length
1143 if (nOffset == -1)
1144 nOffset = nCharCount;
1145 else if (nOffset < -1 || nOffset > nCharCount)
1147 SAL_WARN("vcl.qt",
1148 "QtAccessibleWidget::textBeforeOffset called with invalid offset: " << nOffset);
1149 return QString();
1152 if (eBoundaryType == QAccessible::NoBoundary)
1154 *pStartOffset = 0;
1155 *pEndOffset = nOffset;
1156 return text(0, nOffset);
1159 sal_Int16 nUnoBoundaryType = lcl_matchQtTextBoundaryType(eBoundaryType);
1160 assert(nUnoBoundaryType > 0);
1161 const TextSegment aSegment = xText->getTextBeforeIndex(nOffset, nUnoBoundaryType);
1162 *pStartOffset = aSegment.SegmentStart;
1163 *pEndOffset = aSegment.SegmentEnd;
1164 return toQString(aSegment.SegmentText);
1167 // QAccessibleEditableTextInterface
1169 void QtAccessibleWidget::deleteText(int startOffset, int endOffset)
1171 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1172 if (!xAc.is())
1173 return;
1175 Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY);
1176 if (!xEditableText.is())
1177 return;
1179 sal_Int32 nTextLength = xEditableText->getCharacterCount();
1180 if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength)
1182 SAL_WARN("vcl.qt", "QtAccessibleWidget::deleteText called with invalid offset.");
1183 return;
1186 xEditableText->deleteText(startOffset, endOffset);
1189 void QtAccessibleWidget::insertText(int offset, const QString& text)
1191 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1192 if (!xAc.is())
1193 return;
1195 Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY);
1196 if (!xEditableText.is())
1197 return;
1199 if (offset < 0 || offset > xEditableText->getCharacterCount())
1201 SAL_WARN("vcl.qt", "QtAccessibleWidget::insertText called with invalid offset: " << offset);
1202 return;
1205 xEditableText->insertText(toOUString(text), offset);
1208 void QtAccessibleWidget::replaceText(int startOffset, int endOffset, const QString& text)
1210 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1211 if (!xAc.is())
1212 return;
1214 Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY);
1215 if (!xEditableText.is())
1216 return;
1218 sal_Int32 nTextLength = xEditableText->getCharacterCount();
1219 if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength)
1221 SAL_WARN("vcl.qt", "QtAccessibleWidget::replaceText called with invalid offset.");
1222 return;
1225 xEditableText->replaceText(startOffset, endOffset, toOUString(text));
1228 // QAccessibleValueInterface
1229 QVariant QtAccessibleWidget::currentValue() const
1231 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1232 if (!xAc.is())
1233 return QVariant();
1235 Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
1236 if (!xValue.is())
1237 return QVariant();
1238 double aDouble = 0;
1239 xValue->getCurrentValue() >>= aDouble;
1240 return QVariant(aDouble);
1243 QVariant QtAccessibleWidget::maximumValue() const
1245 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1246 if (!xAc.is())
1247 return QVariant();
1249 Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
1250 if (!xValue.is())
1251 return QVariant();
1252 double aDouble = 0;
1253 xValue->getMaximumValue() >>= aDouble;
1254 return QVariant(aDouble);
1257 QVariant QtAccessibleWidget::minimumStepSize() const
1259 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1260 if (!xAc.is())
1261 return QVariant();
1263 Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
1264 if (!xValue.is())
1265 return QVariant();
1266 double dMinStep = 0;
1267 xValue->getMinimumIncrement() >>= dMinStep;
1268 return QVariant(dMinStep);
1271 QVariant QtAccessibleWidget::minimumValue() const
1273 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1274 if (!xAc.is())
1275 return QVariant();
1277 Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
1278 if (!xValue.is())
1279 return QVariant();
1280 double aDouble = 0;
1281 xValue->getMinimumValue() >>= aDouble;
1282 return QVariant(aDouble);
1285 void QtAccessibleWidget::setCurrentValue(const QVariant& value)
1287 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1288 if (!xAc.is())
1289 return;
1291 Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
1292 if (!xValue.is())
1293 return;
1295 // Different types of numerical values for XAccessibleValue are possible.
1296 // If current value has an integer type, also use that for the new value, to make
1297 // sure underlying implementations expecting that can handle the value properly.
1298 const Any aCurrentValue = xValue->getCurrentValue();
1299 if (aCurrentValue.getValueTypeClass() == css::uno::TypeClass::TypeClass_LONG)
1300 xValue->setCurrentValue(Any(static_cast<sal_Int32>(value.toInt())));
1301 else if (aCurrentValue.getValueTypeClass() == css::uno::TypeClass::TypeClass_HYPER)
1302 xValue->setCurrentValue(Any(static_cast<sal_Int64>(value.toLongLong())));
1303 else
1304 xValue->setCurrentValue(Any(value.toDouble()));
1307 // QAccessibleTableInterface
1308 QAccessibleInterface* QtAccessibleWidget::caption() const
1310 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1311 if (!xAc.is())
1312 return nullptr;
1314 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1315 if (!xTable.is())
1316 return nullptr;
1317 return QAccessible::queryAccessibleInterface(
1318 QtAccessibleRegistry::getQObject(xTable->getAccessibleCaption()));
1321 QAccessibleInterface* QtAccessibleWidget::cellAt(int row, int column) const
1323 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1324 if (!xAc.is())
1325 return nullptr;
1327 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1328 if (!xTable.is())
1329 return nullptr;
1331 if (row < 0 || row >= xTable->getAccessibleRowCount() || column < 0
1332 || column >= xTable->getAccessibleColumnCount())
1334 SAL_WARN("vcl.qt", "QtAccessibleWidget::cellAt called with invalid row/column index ("
1335 << row << ", " << column << ")");
1336 return nullptr;
1339 return QAccessible::queryAccessibleInterface(
1340 QtAccessibleRegistry::getQObject(xTable->getAccessibleCellAt(row, column)));
1343 int QtAccessibleWidget::columnCount() const
1345 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1346 if (!xAc.is())
1347 return 0;
1349 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1350 if (!xTable.is())
1351 return 0;
1352 return xTable->getAccessibleColumnCount();
1355 QString QtAccessibleWidget::columnDescription(int column) const
1357 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1358 if (!xAc.is())
1359 return QString();
1361 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1362 if (!xTable.is())
1363 return QString();
1364 return toQString(xTable->getAccessibleColumnDescription(column));
1367 bool QtAccessibleWidget::isColumnSelected(int nColumn) const
1369 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1370 if (!xAc.is())
1371 return false;
1373 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1374 if (!xTable.is())
1375 return false;
1377 if (nColumn < 0 || nColumn >= xTable->getAccessibleColumnCount())
1379 SAL_WARN("vcl.qt", "QtAccessibleWidget::isColumnSelected called with invalid column index "
1380 << nColumn);
1381 return false;
1384 return xTable->isAccessibleColumnSelected(nColumn);
1387 bool QtAccessibleWidget::isRowSelected(int nRow) const
1389 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1390 if (!xAc.is())
1391 return false;
1393 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1394 if (!xTable.is())
1395 return false;
1397 if (nRow < 0 || nRow >= xTable->getAccessibleRowCount())
1399 SAL_WARN("vcl.qt",
1400 "QtAccessibleWidget::isRowSelected called with invalid row index " << nRow);
1401 return false;
1404 return xTable->isAccessibleRowSelected(nRow);
1407 void QtAccessibleWidget::modelChange(QAccessibleTableModelChangeEvent*) {}
1409 int QtAccessibleWidget::rowCount() const
1411 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1412 if (!xAc.is())
1413 return 0;
1415 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1416 if (!xTable.is())
1417 return 0;
1418 return xTable->getAccessibleRowCount();
1421 QString QtAccessibleWidget::rowDescription(int row) const
1423 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1424 if (!xAc.is())
1425 return QString();
1427 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1428 if (!xTable.is())
1429 return QString();
1430 return toQString(xTable->getAccessibleRowDescription(row));
1433 bool QtAccessibleWidget::selectColumn(int column)
1435 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1436 if (!xAc.is())
1437 return false;
1439 if (column < 0 || column >= columnCount())
1441 SAL_WARN("vcl.qt",
1442 "QtAccessibleWidget::selectColumn called with invalid column index " << column);
1443 return false;
1446 Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY);
1447 if (!xTableSelection.is())
1448 return false;
1449 return xTableSelection->selectColumn(column);
1452 bool QtAccessibleWidget::selectRow(int row)
1454 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1455 if (!xAc.is())
1456 return false;
1458 if (row < 0 || row >= rowCount())
1460 SAL_WARN("vcl.qt", "QtAccessibleWidget::selectRow called with invalid row index " << row);
1461 return false;
1464 Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY);
1465 if (!xTableSelection.is())
1466 return false;
1467 return xTableSelection->selectRow(row);
1470 int QtAccessibleWidget::selectedCellCount() const { return selectedItemCount(); }
1472 QList<QAccessibleInterface*> QtAccessibleWidget::selectedCells() const { return selectedItems(); }
1474 int QtAccessibleWidget::selectedColumnCount() const
1476 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1477 if (!xAc.is())
1478 return 0;
1480 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1481 if (!xTable.is())
1482 return 0;
1483 return xTable->getSelectedAccessibleColumns().getLength();
1486 QList<int> QtAccessibleWidget::selectedColumns() const
1488 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1489 if (!xAc.is())
1490 return QList<int>();
1492 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1493 if (!xTable.is())
1494 return QList<int>();
1495 return toQList(xTable->getSelectedAccessibleColumns());
1498 int QtAccessibleWidget::selectedRowCount() const
1500 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1501 if (!xAc.is())
1502 return 0;
1504 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1505 if (!xTable.is())
1506 return 0;
1507 return xTable->getSelectedAccessibleRows().getLength();
1510 QList<int> QtAccessibleWidget::selectedRows() const
1512 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1513 if (!xAc.is())
1514 return QList<int>();
1516 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1517 if (!xTable.is())
1518 return QList<int>();
1519 return toQList(xTable->getSelectedAccessibleRows());
1522 QAccessibleInterface* QtAccessibleWidget::summary() const
1524 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1525 if (!xAc.is())
1526 return nullptr;
1528 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1529 if (!xTable.is())
1530 return nullptr;
1531 return QAccessible::queryAccessibleInterface(
1532 QtAccessibleRegistry::getQObject(xTable->getAccessibleSummary()));
1535 bool QtAccessibleWidget::unselectColumn(int column)
1537 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1538 if (!xAc.is())
1539 return false;
1541 Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY);
1542 if (!xTableSelection.is())
1543 return false;
1544 return xTableSelection->unselectColumn(column);
1547 bool QtAccessibleWidget::unselectRow(int row)
1549 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1550 if (!xAc.is())
1551 return false;
1553 Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY);
1554 if (!xTableSelection.is())
1555 return false;
1556 return xTableSelection->unselectRow(row);
1559 // QAccessibleTableCellInterface
1560 QList<QAccessibleInterface*> QtAccessibleWidget::columnHeaderCells() const
1562 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
1563 if (!xTable.is())
1564 return QList<QAccessibleInterface*>();
1566 Reference<XAccessibleTable> xHeaders = xTable->getAccessibleColumnHeaders();
1567 if (!xHeaders.is())
1568 return QList<QAccessibleInterface*>();
1570 const sal_Int32 nCol = columnIndex();
1571 QList<QAccessibleInterface*> aHeaderCells;
1572 for (sal_Int32 nRow = 0; nRow < xHeaders->getAccessibleRowCount(); nRow++)
1574 Reference<XAccessible> xCell = xHeaders->getAccessibleCellAt(nRow, nCol);
1575 QAccessibleInterface* pInterface
1576 = QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xCell));
1577 aHeaderCells.push_back(pInterface);
1579 return aHeaderCells;
1582 int QtAccessibleWidget::columnIndex() const
1584 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1585 if (!xAcc.is())
1586 return -1;
1588 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
1589 if (!xTable.is())
1590 return -1;
1592 const sal_Int64 nIndexInParent = xAcc->getAccessibleIndexInParent();
1593 return xTable->getAccessibleColumn(nIndexInParent);
1596 bool QtAccessibleWidget::isSelected() const
1598 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1599 if (!xAcc.is())
1600 return false;
1602 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
1603 if (!xTable.is())
1604 return false;
1606 const sal_Int32 nColumn = columnIndex();
1607 const sal_Int32 nRow = rowIndex();
1608 return xTable->isAccessibleSelected(nRow, nColumn);
1611 int QtAccessibleWidget::columnExtent() const
1613 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1614 if (!xAcc.is())
1615 return -1;
1617 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
1618 if (!xTable.is())
1619 return -1;
1621 const sal_Int32 nColumn = columnIndex();
1622 const sal_Int32 nRow = rowIndex();
1623 return xTable->getAccessibleColumnExtentAt(nRow, nColumn);
1626 QList<QAccessibleInterface*> QtAccessibleWidget::rowHeaderCells() const
1628 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
1629 if (!xTable.is())
1630 return QList<QAccessibleInterface*>();
1632 Reference<XAccessibleTable> xHeaders = xTable->getAccessibleRowHeaders();
1633 if (!xHeaders.is())
1634 return QList<QAccessibleInterface*>();
1636 const sal_Int32 nRow = rowIndex();
1637 QList<QAccessibleInterface*> aHeaderCells;
1638 for (sal_Int32 nCol = 0; nCol < xHeaders->getAccessibleColumnCount(); nCol++)
1640 Reference<XAccessible> xCell = xHeaders->getAccessibleCellAt(nRow, nCol);
1641 QAccessibleInterface* pInterface
1642 = QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xCell));
1643 aHeaderCells.push_back(pInterface);
1645 return aHeaderCells;
1648 int QtAccessibleWidget::rowExtent() const
1650 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1651 if (!xAcc.is())
1652 return -1;
1654 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
1655 if (!xTable.is())
1656 return -1;
1658 const sal_Int32 nColumn = columnIndex();
1659 const sal_Int32 nRow = rowIndex();
1660 return xTable->getAccessibleRowExtentAt(nRow, nColumn);
1663 int QtAccessibleWidget::rowIndex() const
1665 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1666 if (!xAcc.is())
1667 return -1;
1669 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
1670 if (!xTable.is())
1671 return -1;
1673 const sal_Int64 nIndexInParent = xAcc->getAccessibleIndexInParent();
1674 return xTable->getAccessibleRow(nIndexInParent);
1677 QAccessibleInterface* QtAccessibleWidget::table() const
1679 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
1680 if (!xTable.is())
1681 return nullptr;
1683 Reference<XAccessible> xTableAcc(xTable, UNO_QUERY);
1684 if (!xTableAcc.is())
1685 return nullptr;
1687 return QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xTableAcc));
1690 // QAccessibleSelectionInterface
1691 int QtAccessibleWidget::selectedItemCount() const
1693 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1694 if (!xAcc.is())
1695 return 0;
1697 Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
1698 if (!xSelection.is())
1699 return 0;
1701 sal_Int64 nSelected = xSelection->getSelectedAccessibleChildCount();
1702 if (nSelected > std::numeric_limits<int>::max())
1704 SAL_WARN("vcl.qt",
1705 "QtAccessibleWidget::selectedItemCount: Cell count exceeds maximum int value, "
1706 "using max int.");
1707 nSelected = std::numeric_limits<int>::max();
1709 return nSelected;
1712 QList<QAccessibleInterface*> QtAccessibleWidget::selectedItems() const
1714 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1715 if (!xAcc.is())
1716 return QList<QAccessibleInterface*>();
1718 Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
1719 if (!xSelection.is())
1720 return QList<QAccessibleInterface*>();
1722 QList<QAccessibleInterface*> aSelectedItems;
1723 sal_Int64 nSelected = xSelection->getSelectedAccessibleChildCount();
1724 if (nSelected > std::numeric_limits<int>::max())
1726 SAL_WARN("vcl.qt",
1727 "QtAccessibleWidget::selectedItems: Cell count exceeds maximum int value, "
1728 "using max int.");
1729 nSelected = std::numeric_limits<int>::max();
1731 for (sal_Int64 i = 0; i < nSelected; i++)
1733 Reference<XAccessible> xChild = xSelection->getSelectedAccessibleChild(i);
1734 QAccessibleInterface* pInterface
1735 = QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xChild));
1736 aSelectedItems.push_back(pInterface);
1738 return aSelectedItems;
1741 #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
1742 QAccessibleInterface* QtAccessibleWidget::selectedItem(int nSelectionIndex) const
1744 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1745 if (!xAcc.is())
1746 return nullptr;
1748 Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
1749 if (!xSelection.is())
1750 return nullptr;
1752 if (nSelectionIndex < 0 || nSelectionIndex >= xSelection->getSelectedAccessibleChildCount())
1754 SAL_WARN("vcl.qt",
1755 "QtAccessibleWidget::selectedItem called with invalid index: " << nSelectionIndex);
1756 return nullptr;
1759 Reference<XAccessible> xChild = xSelection->getSelectedAccessibleChild(nSelectionIndex);
1760 if (!xChild)
1761 return nullptr;
1763 return QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xChild));
1766 bool QtAccessibleWidget::isSelected(QAccessibleInterface* pItem) const
1768 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1769 if (!xAcc.is())
1770 return false;
1772 Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
1773 if (!xSelection.is())
1774 return false;
1776 int nChildIndex = indexOfChild(pItem);
1777 if (nChildIndex < 0)
1778 return false;
1780 return xSelection->isAccessibleChildSelected(nChildIndex);
1783 bool QtAccessibleWidget::select(QAccessibleInterface* pItem)
1785 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1786 if (!xAcc.is())
1787 return false;
1789 Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
1790 if (!xSelection.is())
1791 return false;
1793 int nChildIndex = indexOfChild(pItem);
1794 if (nChildIndex < 0)
1795 return false;
1797 xSelection->selectAccessibleChild(nChildIndex);
1798 return true;
1801 bool QtAccessibleWidget::unselect(QAccessibleInterface* pItem)
1803 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1804 if (!xAcc.is())
1805 return false;
1807 Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
1808 if (!xSelection.is())
1809 return false;
1811 int nChildIndex = indexOfChild(pItem);
1812 if (nChildIndex < 0)
1813 return false;
1815 xSelection->deselectAccessibleChild(nChildIndex);
1816 return true;
1819 bool QtAccessibleWidget::selectAll()
1821 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1822 if (!xAcc.is())
1823 return false;
1825 Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
1826 if (!xSelection.is())
1827 return false;
1829 xSelection->selectAllAccessibleChildren();
1830 return true;
1833 bool QtAccessibleWidget::clear()
1835 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1836 if (!xAcc.is())
1837 return false;
1839 Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
1840 if (!xSelection.is())
1841 return false;
1843 xSelection->clearAccessibleSelection();
1844 return true;
1846 #endif
1848 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */