calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / vcl / qt5 / QtAccessibleWidget.cxx
blobe2807dd6fecf52c868e396917d2899df43408e15
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/awt/FontSlant.hpp>
50 #include <com/sun/star/awt/FontUnderline.hpp>
51 #include <com/sun/star/awt/FontWeight.hpp>
52 #include <com/sun/star/beans/PropertyValue.hpp>
53 #include <com/sun/star/lang/DisposedException.hpp>
54 #include <com/sun/star/uno/Sequence.hxx>
56 #include <comphelper/AccessibleImplementationHelper.hxx>
57 #include <o3tl/any.hxx>
58 #include <sal/log.hxx>
60 using namespace css;
61 using namespace css::accessibility;
62 using namespace css::beans;
63 using namespace css::uno;
65 QtAccessibleWidget::QtAccessibleWidget(const Reference<XAccessible> xAccessible, QObject* pObject)
66 : m_xAccessible(xAccessible)
67 , m_pObject(pObject)
69 Reference<XAccessibleContext> xContext = xAccessible->getAccessibleContext();
70 Reference<XAccessibleEventBroadcaster> xBroadcaster(xContext, UNO_QUERY);
71 if (xBroadcaster.is())
73 Reference<XAccessibleEventListener> xListener(new QtAccessibleEventListener(this));
74 xBroadcaster->addAccessibleEventListener(xListener);
78 void QtAccessibleWidget::invalidate()
80 QtAccessibleRegistry::remove(m_xAccessible);
81 m_xAccessible.clear();
84 Reference<XAccessibleContext> QtAccessibleWidget::getAccessibleContextImpl() const
86 Reference<XAccessibleContext> xAc;
88 if (m_xAccessible.is())
90 try
92 xAc = m_xAccessible->getAccessibleContext();
94 catch (css::lang::DisposedException /*ex*/)
96 SAL_WARN("vcl.qt", "Accessible context disposed already");
98 // sometimes getAccessibleContext throws also RuntimeException if context is no longer alive
99 catch (css::uno::RuntimeException /*ex*/)
101 // so let's catch it here, cuz otherwise soffice falls flat on its face
102 // with FatalError and nothing else
103 SAL_WARN("vcl.qt", "Accessible context no longer alive");
107 return xAc;
110 css::uno::Reference<css::accessibility::XAccessibleTable>
111 QtAccessibleWidget::getAccessibleTableForParent() const
113 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
114 if (!xAcc.is())
115 return nullptr;
117 Reference<XAccessible> xParent = xAcc->getAccessibleParent();
118 if (!xParent.is())
119 return nullptr;
121 Reference<XAccessibleContext> xParentContext = xParent->getAccessibleContext();
122 if (!xParentContext.is())
123 return nullptr;
125 return Reference<XAccessibleTable>(xParentContext, UNO_QUERY);
128 QWindow* QtAccessibleWidget::window() const
130 assert(m_pObject);
131 if (m_pObject->isWidgetType())
133 QWidget* pWidget = static_cast<QWidget*>(m_pObject);
134 QWidget* pWindow = pWidget->window();
135 if (pWindow)
136 return pWindow->windowHandle();
139 QAccessibleInterface* pParent = parent();
140 if (pParent)
141 return pParent->window();
143 return nullptr;
146 int QtAccessibleWidget::childCount() const
148 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
149 if (!xAc.is())
150 return 0;
152 sal_Int64 nChildCount = xAc->getAccessibleChildCount();
153 if (nChildCount > std::numeric_limits<int>::max())
155 SAL_WARN("vcl.qt", "QtAccessibleWidget::childCount: Child count exceeds maximum int value, "
156 "returning max int.");
157 nChildCount = std::numeric_limits<int>::max();
160 return nChildCount;
163 int QtAccessibleWidget::indexOfChild(const QAccessibleInterface* pChild) const
165 const QtAccessibleWidget* pAccessibleWidget = dynamic_cast<const QtAccessibleWidget*>(pChild);
166 if (!pAccessibleWidget)
168 SAL_WARN(
169 "vcl.qt",
170 "QtAccessibleWidget::indexOfChild called with child that is no QtAccessibleWidget");
171 return -1;
174 Reference<XAccessibleContext> xContext = pAccessibleWidget->getAccessibleContextImpl();
175 if (!xContext.is())
176 return -1;
178 sal_Int64 nChildIndex = xContext->getAccessibleIndexInParent();
179 if (nChildIndex > std::numeric_limits<int>::max())
181 // use -2 when the child index is too large to fit into 32 bit to neither use the
182 // valid index of another child nor -1, which would e.g. make the Orca screen reader
183 // interpret the object as being a zombie
184 SAL_WARN("vcl.qt",
185 "QtAccessibleWidget::indexOfChild: Child index exceeds maximum int value, "
186 "returning -2.");
187 nChildIndex = -2;
189 return nChildIndex;
192 namespace
194 sal_Int16 lcl_matchQtTextBoundaryType(QAccessible::TextBoundaryType boundaryType)
196 switch (boundaryType)
198 case QAccessible::CharBoundary:
199 return com::sun::star::accessibility::AccessibleTextType::CHARACTER;
200 case QAccessible::WordBoundary:
201 return com::sun::star::accessibility::AccessibleTextType::WORD;
202 case QAccessible::SentenceBoundary:
203 return com::sun::star::accessibility::AccessibleTextType::SENTENCE;
204 case QAccessible::ParagraphBoundary:
205 return com::sun::star::accessibility::AccessibleTextType::PARAGRAPH;
206 case QAccessible::LineBoundary:
207 return com::sun::star::accessibility::AccessibleTextType::LINE;
208 case QAccessible::NoBoundary:
209 // assert here, better handle it directly at call site
210 assert(false
211 && "No match for QAccessible::NoBoundary, handle it separately at call site.");
212 break;
213 default:
214 break;
217 SAL_WARN("vcl.qt", "Unmatched text boundary type: " << boundaryType);
218 return -1;
221 QAccessible::Relation lcl_matchUnoRelation(short relationType)
223 switch (relationType)
225 case AccessibleRelationType::CONTROLLER_FOR:
226 return QAccessible::Controller;
227 case AccessibleRelationType::CONTROLLED_BY:
228 return QAccessible::Controlled;
229 case AccessibleRelationType::LABEL_FOR:
230 return QAccessible::Label;
231 case AccessibleRelationType::LABELED_BY:
232 return QAccessible::Labelled;
233 case AccessibleRelationType::INVALID:
234 case AccessibleRelationType::CONTENT_FLOWS_FROM:
235 case AccessibleRelationType::CONTENT_FLOWS_TO:
236 case AccessibleRelationType::MEMBER_OF:
237 case AccessibleRelationType::SUB_WINDOW_OF:
238 case AccessibleRelationType::NODE_CHILD_OF:
239 case AccessibleRelationType::DESCRIBED_BY:
240 default:
241 SAL_WARN("vcl.qt", "Unmatched relation: " << relationType);
242 return {};
246 short lcl_matchQtRelation(QAccessible::Relation relationType)
248 switch (relationType)
250 case QAccessible::Controller:
251 return AccessibleRelationType::CONTROLLER_FOR;
252 case QAccessible::Controlled:
253 return AccessibleRelationType::CONTROLLED_BY;
254 case QAccessible::Label:
255 return AccessibleRelationType::LABEL_FOR;
256 case QAccessible::Labelled:
257 return AccessibleRelationType::LABELED_BY;
258 default:
259 SAL_WARN("vcl.qt", "Unmatched relation: " << relationType);
261 return 0;
264 void lcl_appendRelation(QVector<QPair<QAccessibleInterface*, QAccessible::Relation>>* relations,
265 AccessibleRelation aRelation)
267 QAccessible::Relation aQRelation = lcl_matchUnoRelation(aRelation.RelationType);
268 // skip in case there's no matching Qt relation
269 if (!(aQRelation & QAccessible::AllRelations))
270 return;
272 sal_uInt32 nTargetCount = aRelation.TargetSet.getLength();
274 for (sal_uInt32 i = 0; i < nTargetCount; i++)
276 Reference<XAccessible> xAccessible(aRelation.TargetSet[i], uno::UNO_QUERY);
277 relations->append(
278 { QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xAccessible)),
279 aQRelation });
284 QVector<QPair<QAccessibleInterface*, QAccessible::Relation>>
285 QtAccessibleWidget::relations(QAccessible::Relation match) const
287 QVector<QPair<QAccessibleInterface*, QAccessible::Relation>> relations;
289 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
290 if (!xAc.is())
291 return relations;
293 Reference<XAccessibleRelationSet> xRelationSet = xAc->getAccessibleRelationSet();
294 if (xRelationSet.is())
296 if (match == QAccessible::AllRelations)
298 int count = xRelationSet->getRelationCount();
299 for (int i = 0; i < count; i++)
301 AccessibleRelation aRelation = xRelationSet->getRelation(i);
302 lcl_appendRelation(&relations, aRelation);
305 else
307 AccessibleRelation aRelation = xRelationSet->getRelation(lcl_matchQtRelation(match));
308 lcl_appendRelation(&relations, aRelation);
312 return relations;
315 QAccessibleInterface* QtAccessibleWidget::focusChild() const
317 /* if (m_pWindow->HasChildPathFocus())
318 return QAccessible::queryAccessibleInterface(
319 new QtXAccessible(m_xAccessible->getAccessibleContext()->getAccessibleChild(index))); */
320 return QAccessible::queryAccessibleInterface(object());
323 QRect QtAccessibleWidget::rect() const
325 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
326 if (!xAc.is())
327 return QRect();
329 Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY);
330 awt::Point aPoint = xAccessibleComponent->getLocationOnScreen();
331 awt::Size aSize = xAccessibleComponent->getSize();
333 return QRect(aPoint.X, aPoint.Y, aSize.Width, aSize.Height);
336 QAccessibleInterface* QtAccessibleWidget::parent() const
338 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
339 if (!xAc.is())
340 return nullptr;
342 if (xAc->getAccessibleParent().is())
343 return QAccessible::queryAccessibleInterface(
344 QtAccessibleRegistry::getQObject(xAc->getAccessibleParent()));
346 // go via the QObject hierarchy; some a11y objects like the application
347 // (at the root of the a11y hierarchy) are handled solely by Qt and have
348 // no LO-internal a11y objects associated with them
349 QObject* pObj = object();
350 if (pObj && pObj->parent())
351 return QAccessible::queryAccessibleInterface(pObj->parent());
353 return nullptr;
356 QAccessibleInterface* QtAccessibleWidget::child(int index) const
358 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
359 if (!xAc.is())
360 return nullptr;
361 return QAccessible::queryAccessibleInterface(
362 QtAccessibleRegistry::getQObject(xAc->getAccessibleChild(index)));
365 QString QtAccessibleWidget::text(QAccessible::Text text) const
367 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
368 if (!xAc.is())
369 return QString();
371 switch (text)
373 case QAccessible::Name:
374 return toQString(xAc->getAccessibleName());
375 case QAccessible::Description:
376 case QAccessible::DebugDescription:
377 return toQString(xAc->getAccessibleDescription());
378 case QAccessible::Value:
379 case QAccessible::Help:
380 case QAccessible::Accelerator:
381 case QAccessible::UserText:
382 default:
383 return QString("Unknown");
386 QAccessible::Role QtAccessibleWidget::role() const
388 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
389 if (!xAc.is())
390 return QAccessible::NoRole;
392 switch (xAc->getAccessibleRole())
394 case AccessibleRole::UNKNOWN:
395 return QAccessible::NoRole;
396 case AccessibleRole::ALERT:
397 return QAccessible::AlertMessage;
398 case AccessibleRole::COLUMN_HEADER:
399 return QAccessible::ColumnHeader;
400 case AccessibleRole::CANVAS:
401 return QAccessible::Canvas;
402 case AccessibleRole::CHECK_BOX:
403 return QAccessible::CheckBox;
404 case AccessibleRole::CHECK_MENU_ITEM:
405 return QAccessible::MenuItem;
406 case AccessibleRole::COLOR_CHOOSER:
407 return QAccessible::ColorChooser;
408 case AccessibleRole::COMBO_BOX:
409 return QAccessible::ComboBox;
410 case AccessibleRole::DATE_EDITOR:
411 return QAccessible::EditableText;
412 case AccessibleRole::DESKTOP_ICON:
413 return QAccessible::Graphic;
414 case AccessibleRole::DESKTOP_PANE:
415 case AccessibleRole::DIRECTORY_PANE:
416 return QAccessible::Pane;
417 case AccessibleRole::DIALOG:
418 return QAccessible::Dialog;
419 case AccessibleRole::DOCUMENT:
420 return QAccessible::Document;
421 case AccessibleRole::EMBEDDED_OBJECT:
422 return QAccessible::UserRole;
423 case AccessibleRole::END_NOTE:
424 return QAccessible::Note;
425 case AccessibleRole::FILE_CHOOSER:
426 return QAccessible::Dialog;
427 case AccessibleRole::FILLER:
428 return QAccessible::Whitespace;
429 case AccessibleRole::FONT_CHOOSER:
430 return QAccessible::UserRole;
431 case AccessibleRole::FOOTER:
432 return QAccessible::Footer;
433 case AccessibleRole::FOOTNOTE:
434 return QAccessible::Note;
435 case AccessibleRole::FRAME: // top-level window with title bar
436 return QAccessible::Window;
437 case AccessibleRole::GLASS_PANE:
438 return QAccessible::UserRole;
439 case AccessibleRole::GRAPHIC:
440 return QAccessible::Graphic;
441 case AccessibleRole::GROUP_BOX:
442 return QAccessible::Grouping;
443 case AccessibleRole::HEADER:
444 return QAccessible::UserRole;
445 case AccessibleRole::HEADING:
446 return QAccessible::Heading;
447 case AccessibleRole::HYPER_LINK:
448 return QAccessible::Link;
449 case AccessibleRole::ICON:
450 return QAccessible::Graphic;
451 case AccessibleRole::INTERNAL_FRAME:
452 return QAccessible::UserRole;
453 case AccessibleRole::LABEL:
454 return QAccessible::StaticText;
455 case AccessibleRole::LAYERED_PANE:
456 return QAccessible::Pane;
457 case AccessibleRole::LIST:
458 return QAccessible::List;
459 case AccessibleRole::LIST_ITEM:
460 return QAccessible::ListItem;
461 case AccessibleRole::MENU:
462 case AccessibleRole::MENU_BAR:
463 return QAccessible::MenuBar;
464 case AccessibleRole::MENU_ITEM:
465 return QAccessible::MenuItem;
466 case AccessibleRole::NOTIFICATION:
467 #if QT_VERSION >= QT_VERSION_CHECK(5, 12, 5)
468 return QAccessible::Notification;
469 #else
470 return QAccessible::StaticText;
471 #endif
472 case AccessibleRole::OPTION_PANE:
473 return QAccessible::Pane;
474 case AccessibleRole::PAGE_TAB:
475 return QAccessible::PageTab;
476 case AccessibleRole::PAGE_TAB_LIST:
477 return QAccessible::PageTabList;
478 case AccessibleRole::PANEL:
479 return QAccessible::Pane;
480 case AccessibleRole::PARAGRAPH:
481 return QAccessible::Paragraph;
482 case AccessibleRole::PASSWORD_TEXT:
483 return QAccessible::EditableText;
484 case AccessibleRole::POPUP_MENU:
485 return QAccessible::PopupMenu;
486 case AccessibleRole::PUSH_BUTTON:
487 return QAccessible::Button;
488 case AccessibleRole::PROGRESS_BAR:
489 return QAccessible::ProgressBar;
490 case AccessibleRole::RADIO_BUTTON:
491 return QAccessible::RadioButton;
492 case AccessibleRole::RADIO_MENU_ITEM:
493 return QAccessible::MenuItem;
494 case AccessibleRole::ROW_HEADER:
495 return QAccessible::RowHeader;
496 case AccessibleRole::ROOT_PANE:
497 return QAccessible::Pane;
498 case AccessibleRole::SCROLL_BAR:
499 return QAccessible::ScrollBar;
500 case AccessibleRole::SCROLL_PANE:
501 return QAccessible::Pane;
502 case AccessibleRole::SHAPE:
503 return QAccessible::Graphic;
504 case AccessibleRole::SEPARATOR:
505 return QAccessible::Separator;
506 case AccessibleRole::SLIDER:
507 return QAccessible::Slider;
508 case AccessibleRole::SPIN_BOX:
509 return QAccessible::SpinBox;
510 case AccessibleRole::SPLIT_PANE:
511 return QAccessible::Pane;
512 case AccessibleRole::STATUS_BAR:
513 return QAccessible::StatusBar;
514 case AccessibleRole::TABLE:
515 return QAccessible::Table;
516 case AccessibleRole::TABLE_CELL:
517 return QAccessible::Cell;
518 case AccessibleRole::TEXT:
519 return QAccessible::EditableText;
520 case AccessibleRole::TEXT_FRAME:
521 return QAccessible::UserRole;
522 case AccessibleRole::TOGGLE_BUTTON:
523 return QAccessible::Button;
524 case AccessibleRole::TOOL_BAR:
525 return QAccessible::ToolBar;
526 case AccessibleRole::TOOL_TIP:
527 return QAccessible::ToolTip;
528 case AccessibleRole::TREE:
529 return QAccessible::Tree;
530 case AccessibleRole::VIEW_PORT:
531 return QAccessible::UserRole;
532 case AccessibleRole::BUTTON_DROPDOWN:
533 return QAccessible::ButtonDropDown;
534 case AccessibleRole::BUTTON_MENU:
535 return QAccessible::ButtonMenu;
536 case AccessibleRole::CAPTION:
537 return QAccessible::StaticText;
538 case AccessibleRole::CHART:
539 return QAccessible::Chart;
540 case AccessibleRole::EDIT_BAR:
541 return QAccessible::Equation;
542 case AccessibleRole::FORM:
543 return QAccessible::Form;
544 case AccessibleRole::IMAGE_MAP:
545 return QAccessible::Graphic;
546 case AccessibleRole::NOTE:
547 return QAccessible::Note;
548 case AccessibleRole::RULER:
549 return QAccessible::UserRole;
550 case AccessibleRole::SECTION:
551 return QAccessible::Section;
552 case AccessibleRole::TREE_ITEM:
553 return QAccessible::TreeItem;
554 case AccessibleRole::TREE_TABLE:
555 return QAccessible::Tree;
556 case AccessibleRole::COMMENT:
557 return QAccessible::Note;
558 case AccessibleRole::COMMENT_END:
559 return QAccessible::UserRole;
560 case AccessibleRole::DOCUMENT_PRESENTATION:
561 return QAccessible::Document;
562 case AccessibleRole::DOCUMENT_SPREADSHEET:
563 return QAccessible::Document;
564 case AccessibleRole::DOCUMENT_TEXT:
565 return QAccessible::Document;
566 case AccessibleRole::STATIC:
567 return QAccessible::StaticText;
568 case AccessibleRole::WINDOW: // top-level window without title bar
569 return QAccessible::Window;
572 SAL_WARN("vcl.qt", "Unmapped role: " << getAccessibleContextImpl()->getAccessibleRole());
573 return QAccessible::NoRole;
576 namespace
578 void lcl_addState(QAccessible::State* state, sal_Int64 nState)
580 switch (nState)
582 case AccessibleStateType::INVALID:
583 state->invalid = true;
584 break;
585 case AccessibleStateType::ACTIVE:
586 state->active = true;
587 break;
588 case AccessibleStateType::ARMED:
589 // No match
590 break;
591 case AccessibleStateType::BUSY:
592 state->busy = true;
593 break;
594 case AccessibleStateType::CHECKED:
595 state->checked = true;
596 break;
597 case AccessibleStateType::EDITABLE:
598 state->editable = true;
599 break;
600 case AccessibleStateType::ENABLED:
601 state->disabled = false;
602 break;
603 case AccessibleStateType::EXPANDABLE:
604 state->expandable = true;
605 break;
606 case AccessibleStateType::EXPANDED:
607 state->expanded = true;
608 break;
609 case AccessibleStateType::FOCUSABLE:
610 state->focusable = true;
611 break;
612 case AccessibleStateType::FOCUSED:
613 state->focused = true;
614 break;
615 case AccessibleStateType::HORIZONTAL:
616 // No match
617 break;
618 case AccessibleStateType::ICONIFIED:
619 // No match
620 break;
621 case AccessibleStateType::INDETERMINATE:
622 // No match
623 break;
624 case AccessibleStateType::MANAGES_DESCENDANTS:
625 // No match
626 break;
627 case AccessibleStateType::MODAL:
628 state->modal = true;
629 break;
630 case AccessibleStateType::MOVEABLE:
631 state->movable = true;
632 break;
633 case AccessibleStateType::MULTI_LINE:
634 state->multiLine = true;
635 break;
636 case AccessibleStateType::OPAQUE:
637 // No match
638 break;
639 case AccessibleStateType::PRESSED:
640 state->pressed = true;
641 break;
642 case AccessibleStateType::RESIZABLE:
643 state->sizeable = true;
644 break;
645 case AccessibleStateType::SELECTABLE:
646 state->selectable = true;
647 break;
648 case AccessibleStateType::SELECTED:
649 state->selected = true;
650 break;
651 case AccessibleStateType::SENSITIVE:
652 // No match
653 break;
654 case AccessibleStateType::SHOWING:
655 // No match
656 break;
657 case AccessibleStateType::SINGLE_LINE:
658 // No match
659 break;
660 case AccessibleStateType::STALE:
661 // No match
662 break;
663 case AccessibleStateType::TRANSIENT:
664 // No match
665 break;
666 case AccessibleStateType::VERTICAL:
667 // No match
668 break;
669 case AccessibleStateType::VISIBLE:
670 state->invisible = false;
671 break;
672 case AccessibleStateType::DEFAULT:
673 // No match
674 break;
675 case AccessibleStateType::DEFUNC:
676 state->invalid = true;
677 break;
678 case AccessibleStateType::MULTI_SELECTABLE:
679 state->multiSelectable = true;
680 break;
681 default:
682 SAL_WARN("vcl.qt", "Unmapped state: " << nState);
683 break;
688 QAccessible::State QtAccessibleWidget::state() const
690 QAccessible::State state;
692 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
693 if (!xAc.is())
694 return state;
696 sal_Int64 nStateSet(xAc->getAccessibleStateSet());
698 for (int i = 0; i < 63; ++i)
700 sal_Int64 nState = sal_Int64(1) << i;
701 if (nStateSet & nState)
702 lcl_addState(&state, nState);
705 return state;
708 QColor QtAccessibleWidget::foregroundColor() const
710 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
711 if (!xAc.is())
712 return QColor();
714 Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY);
715 return toQColor(Color(ColorTransparency, xAccessibleComponent->getForeground()));
718 QColor QtAccessibleWidget::backgroundColor() const
720 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
721 if (!xAc.is())
722 return QColor();
724 Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY);
725 return toQColor(Color(ColorTransparency, xAccessibleComponent->getBackground()));
728 void* QtAccessibleWidget::interface_cast(QAccessible::InterfaceType t)
730 if (t == QAccessible::ActionInterface && accessibleProvidesInterface<XAccessibleAction>())
731 return static_cast<QAccessibleActionInterface*>(this);
732 if (t == QAccessible::TextInterface && accessibleProvidesInterface<XAccessibleText>())
733 return static_cast<QAccessibleTextInterface*>(this);
734 if (t == QAccessible::EditableTextInterface
735 && accessibleProvidesInterface<XAccessibleEditableText>())
736 return static_cast<QAccessibleEditableTextInterface*>(this);
737 if (t == QAccessible::ValueInterface && accessibleProvidesInterface<XAccessibleValue>())
738 return static_cast<QAccessibleValueInterface*>(this);
739 if (t == QAccessible::TableCellInterface)
741 // parent must be a table
742 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
743 if (xTable.is())
744 return static_cast<QAccessibleTableCellInterface*>(this);
746 if (t == QAccessible::TableInterface && accessibleProvidesInterface<XAccessibleTable>())
747 return static_cast<QAccessibleTableInterface*>(this);
748 return nullptr;
751 bool QtAccessibleWidget::isValid() const
753 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
754 return xAc.is();
757 QObject* QtAccessibleWidget::object() const { return m_pObject; }
759 void QtAccessibleWidget::setText(QAccessible::Text /* t */, const QString& /* text */) {}
761 QAccessibleInterface* QtAccessibleWidget::childAt(int x, int y) const
763 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
764 if (!xAc.is())
765 return nullptr;
767 Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY);
768 // convert from screen to local coordinates
769 QPoint aLocalCoords = QPoint(x, y) - rect().topLeft();
770 return QAccessible::queryAccessibleInterface(
771 QtAccessibleRegistry::getQObject(xAccessibleComponent->getAccessibleAtPoint(
772 awt::Point(aLocalCoords.x(), aLocalCoords.y()))));
775 QAccessibleInterface* QtAccessibleWidget::customFactory(const QString& classname, QObject* object)
777 if (classname == QLatin1String("QtWidget") && object && object->isWidgetType())
779 QtWidget* pWidget = static_cast<QtWidget*>(object);
780 vcl::Window* pWindow = pWidget->frame().GetWindow();
782 if (pWindow)
784 css::uno::Reference<XAccessible> xAcc = pWindow->GetAccessible();
785 // insert into registry so the association between the XAccessible and the QtWidget
786 // is remembered rather than creating a different QtXAccessible when a QObject is needed later
787 QtAccessibleRegistry::insert(xAcc, object);
788 return new QtAccessibleWidget(xAcc, object);
791 if (classname == QLatin1String("QtXAccessible") && object)
793 QtXAccessible* pXAccessible = static_cast<QtXAccessible*>(object);
794 if (pXAccessible->m_xAccessible.is())
796 QtAccessibleWidget* pRet = new QtAccessibleWidget(pXAccessible->m_xAccessible, object);
797 // clear the reference in the QtXAccessible, no longer needed now that the QtAccessibleWidget holds one
798 pXAccessible->m_xAccessible.clear();
799 return pRet;
803 return nullptr;
806 // QAccessibleActionInterface
807 QStringList QtAccessibleWidget::actionNames() const
809 QStringList actionNames;
810 Reference<XAccessibleAction> xAccessibleAction(getAccessibleContextImpl(), UNO_QUERY);
811 if (!xAccessibleAction.is())
812 return actionNames;
814 int count = xAccessibleAction->getAccessibleActionCount();
815 for (int i = 0; i < count; i++)
817 OUString desc = xAccessibleAction->getAccessibleActionDescription(i);
818 actionNames.append(toQString(desc));
820 return actionNames;
823 void QtAccessibleWidget::doAction(const QString& actionName)
825 Reference<XAccessibleAction> xAccessibleAction(getAccessibleContextImpl(), UNO_QUERY);
826 if (!xAccessibleAction.is())
827 return;
829 int index = actionNames().indexOf(actionName);
830 if (index == -1)
831 return;
832 xAccessibleAction->doAccessibleAction(index);
835 QStringList QtAccessibleWidget::keyBindingsForAction(const QString& actionName) const
837 QStringList keyBindings;
838 Reference<XAccessibleAction> xAccessibleAction(getAccessibleContextImpl(), UNO_QUERY);
839 if (!xAccessibleAction.is())
840 return keyBindings;
842 int index = actionNames().indexOf(actionName);
843 if (index == -1)
844 return keyBindings;
846 Reference<XAccessibleKeyBinding> xKeyBinding
847 = xAccessibleAction->getAccessibleActionKeyBinding(index);
849 if (!xKeyBinding.is())
850 return keyBindings;
852 int count = xKeyBinding->getAccessibleKeyBindingCount();
853 for (int i = 0; i < count; i++)
855 Sequence<awt::KeyStroke> keyStroke = xKeyBinding->getAccessibleKeyBinding(i);
856 keyBindings.append(toQString(comphelper::GetkeyBindingStrByXkeyBinding(keyStroke)));
858 return keyBindings;
861 // QAccessibleTextInterface
862 void QtAccessibleWidget::addSelection(int /* startOffset */, int /* endOffset */)
864 SAL_INFO("vcl.qt", "Unsupported QAccessibleTextInterface::addSelection");
867 namespace
869 OUString lcl_convertFontWeight(double fontWeight)
871 if (fontWeight == awt::FontWeight::THIN || fontWeight == awt::FontWeight::ULTRALIGHT)
872 return "100";
873 if (fontWeight == awt::FontWeight::LIGHT)
874 return "200";
875 if (fontWeight == awt::FontWeight::SEMILIGHT)
876 return "300";
877 if (fontWeight == awt::FontWeight::NORMAL)
878 return "normal";
879 if (fontWeight == awt::FontWeight::SEMIBOLD)
880 return "500";
881 if (fontWeight == awt::FontWeight::BOLD)
882 return "bold";
883 if (fontWeight == awt::FontWeight::ULTRABOLD)
884 return "800";
885 if (fontWeight == awt::FontWeight::BLACK)
886 return "900";
888 // awt::FontWeight::DONTKNOW || fontWeight == awt::FontWeight::NORMAL
889 return "normal";
892 OUString lcl_ConvertFontSlant(awt::FontSlant eFontSlant)
894 switch (eFontSlant)
896 case awt::FontSlant::FontSlant_NONE:
897 return "normal";
898 case awt::FontSlant::FontSlant_OBLIQUE:
899 case awt::FontSlant::FontSlant_REVERSE_OBLIQUE:
900 return "oblique";
901 case awt::FontSlant::FontSlant_ITALIC:
902 case awt::FontSlant::FontSlant_REVERSE_ITALIC:
903 return "italic";
904 case awt::FontSlant::FontSlant_DONTKNOW:
905 case awt::FontSlant::FontSlant_MAKE_FIXED_SIZE:
906 default:
907 return "";
911 // s. https://wiki.linuxfoundation.org/accessibility/iaccessible2/textattributes
912 // for values
913 void lcl_ConvertFontUnderline(sal_Int16 nFontUnderline, OUString& rUnderlineStyle,
914 OUString& rUnderlineType, OUString& rUnderlineWidth)
916 rUnderlineStyle = u"";
917 rUnderlineType = u"single";
918 rUnderlineWidth = u"auto";
920 switch (nFontUnderline)
922 case awt::FontUnderline::BOLD:
923 rUnderlineWidth = u"bold";
924 return;
925 case awt::FontUnderline::BOLDDASH:
926 rUnderlineWidth = u"bold";
927 rUnderlineStyle = u"dash";
928 return;
929 case awt::FontUnderline::BOLDDASHDOT:
930 rUnderlineWidth = u"bold";
931 rUnderlineStyle = u"dot-dash";
932 return;
933 case awt::FontUnderline::BOLDDASHDOTDOT:
934 rUnderlineWidth = u"bold";
935 rUnderlineStyle = u"dot-dot-dash";
936 return;
937 case awt::FontUnderline::BOLDDOTTED:
938 rUnderlineWidth = u"bold";
939 rUnderlineStyle = u"dotted";
940 return;
941 case awt::FontUnderline::BOLDLONGDASH:
942 rUnderlineWidth = u"bold";
943 rUnderlineStyle = u"long-dash";
944 return;
945 case awt::FontUnderline::BOLDWAVE:
946 rUnderlineWidth = u"bold";
947 rUnderlineStyle = u"wave";
948 return;
949 case awt::FontUnderline::DASH:
950 rUnderlineStyle = u"dash";
951 return;
952 case awt::FontUnderline::DASHDOT:
953 rUnderlineStyle = u"dot-dash";
954 return;
955 case awt::FontUnderline::DASHDOTDOT:
956 rUnderlineStyle = u"dot-dot-dash";
957 return;
958 case awt::FontUnderline::DONTKNOW:
959 rUnderlineWidth = u"";
960 rUnderlineStyle = u"";
961 rUnderlineType = u"";
962 return;
963 case awt::FontUnderline::DOTTED:
964 rUnderlineStyle = u"dotted";
965 return;
966 case awt::FontUnderline::DOUBLE:
967 rUnderlineType = u"double";
968 return;
969 case awt::FontUnderline::DOUBLEWAVE:
970 rUnderlineStyle = u"wave";
971 rUnderlineType = u"double";
972 return;
973 case awt::FontUnderline::LONGDASH:
974 rUnderlineStyle = u"long-dash";
975 return;
976 case awt::FontUnderline::NONE:
977 rUnderlineWidth = u"none";
978 rUnderlineStyle = u"none";
979 rUnderlineType = u"none";
980 return;
981 case awt::FontUnderline::SINGLE:
982 rUnderlineType = u"single";
983 return;
984 case awt::FontUnderline::SMALLWAVE:
985 case awt::FontUnderline::WAVE:
986 rUnderlineStyle = u"wave";
987 return;
988 default:
989 assert(false && "Unhandled font underline type");
993 /** Converts Color to "rgb(r,g,b)" as specified in https://wiki.linuxfoundation.org/accessibility/iaccessible2/textattributes. */
994 OUString lcl_ConvertColor(Color aColor)
996 return u"rgb(" + OUString::number(aColor.GetRed()) + u"," + OUString::number(aColor.GetGreen())
997 + u"," + OUString::number(aColor.GetBlue()) + u")";
1001 // Text attributes are returned in format specified in IAccessible2 spec, since that
1002 // is what Qt handles:
1003 // https://wiki.linuxfoundation.org/accessibility/iaccessible2/textattributes
1004 QString QtAccessibleWidget::attributes(int offset, int* startOffset, int* endOffset) const
1006 if (startOffset == nullptr || endOffset == nullptr)
1007 return QString();
1009 *startOffset = -1;
1010 *endOffset = -1;
1012 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1013 if (!xText.is())
1014 return QString();
1016 // handle special values for offset the same way base class's QAccessibleTextWidget::attributes does
1017 // (as defined in IAccessible 2: -1 -> length, -2 -> cursor position)
1018 if (offset == -2)
1019 offset = cursorPosition();
1021 const int nTextLength = characterCount();
1022 if (offset == -1 || offset == nTextLength)
1023 offset = nTextLength - 1;
1025 if (offset < 0 || offset > nTextLength)
1027 SAL_WARN("vcl.qt", "QtAccessibleWidget::attributes called with invalid offset: " << offset);
1028 return QString();
1031 const Sequence<PropertyValue> attribs
1032 = xText->getCharacterAttributes(offset, Sequence<OUString>());
1033 OUString aRet;
1034 for (PropertyValue const& prop : attribs)
1036 OUString sAttribute;
1037 OUString sValue;
1038 if (prop.Name == "CharBackColor")
1040 sAttribute = "background-color";
1041 sValue = lcl_ConvertColor(
1042 Color(ColorTransparency, *o3tl::doAccess<sal_Int32>(prop.Value)));
1044 else if (prop.Name == "CharColor")
1046 sAttribute = "color";
1047 sValue = lcl_ConvertColor(
1048 Color(ColorTransparency, *o3tl::doAccess<sal_Int32>(prop.Value)));
1050 else if (prop.Name == "CharFontName")
1052 sAttribute = "font-family";
1053 sValue = *o3tl::doAccess<OUString>(prop.Value);
1055 else if (prop.Name == "CharHeight")
1057 sAttribute = "font-size";
1058 sValue = OUString::number(*o3tl::doAccess<double>(prop.Value)) + "pt";
1060 else if (prop.Name == "CharPosture")
1062 sAttribute = "font-style";
1063 const awt::FontSlant eFontSlant = *o3tl::doAccess<awt::FontSlant>(prop.Value);
1064 sValue = lcl_ConvertFontSlant(eFontSlant);
1066 else if (prop.Name == "CharUnderline")
1068 OUString sUnderlineStyle;
1069 OUString sUnderlineType;
1070 OUString sUnderlineWidth;
1071 const sal_Int16 nUnderline = *o3tl::doAccess<sal_Int16>(prop.Value);
1072 lcl_ConvertFontUnderline(nUnderline, sUnderlineStyle, sUnderlineType, sUnderlineWidth);
1074 // leave 'sAttribute' and 'sName' empty, set all attributes here
1075 if (!sUnderlineStyle.isEmpty())
1076 aRet += u"text-underline-style:" + sUnderlineStyle + ";";
1077 if (!sUnderlineType.isEmpty())
1078 aRet += u"text-underline-type:" + sUnderlineType + ";";
1079 if (!sUnderlineWidth.isEmpty())
1080 aRet += u"text-underline-width:" + sUnderlineWidth + ";";
1082 else if (prop.Name == "CharWeight")
1084 sAttribute = "font-weight";
1085 sValue = lcl_convertFontWeight(*o3tl::doAccess<double>(prop.Value));
1088 if (!sAttribute.isEmpty() && !sValue.isEmpty())
1089 aRet += sAttribute + ":" + sValue + ";";
1092 accessibility::TextSegment aAttributeRun
1093 = xText->getTextAtIndex(offset, accessibility::AccessibleTextType::ATTRIBUTE_RUN);
1094 *startOffset = aAttributeRun.SegmentStart;
1095 *endOffset = aAttributeRun.SegmentEnd;
1096 return toQString(aRet);
1099 int QtAccessibleWidget::characterCount() const
1101 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1102 if (xText.is())
1103 return xText->getCharacterCount();
1104 return 0;
1107 QRect QtAccessibleWidget::characterRect(int nOffset) const
1109 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1110 if (!xText.is())
1111 return QRect();
1113 if (nOffset < 0 || nOffset > xText->getCharacterCount())
1115 SAL_WARN("vcl.qt",
1116 "QtAccessibleWidget::characterRect called with invalid offset: " << nOffset);
1117 return QRect();
1120 const awt::Rectangle aBounds = xText->getCharacterBounds(nOffset);
1121 const QRect aRect(aBounds.X, aBounds.Y, aBounds.Width, aBounds.Height);
1122 // convert to screen coordinates
1123 const QRect aScreenPos = rect();
1124 return aRect.translated(aScreenPos.x(), aScreenPos.y());
1127 int QtAccessibleWidget::cursorPosition() const
1129 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1130 if (xText.is())
1131 return xText->getCaretPosition();
1132 return 0;
1135 int QtAccessibleWidget::offsetAtPoint(const QPoint& rPoint) const
1137 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1138 if (!xText.is())
1139 return -1;
1141 // convert from screen to local coordinates
1142 QPoint aLocalCoords = rPoint - rect().topLeft();
1143 awt::Point aPoint(aLocalCoords.x(), aLocalCoords.y());
1144 return xText->getIndexAtPoint(aPoint);
1147 void QtAccessibleWidget::removeSelection(int /* selectionIndex */)
1149 SAL_INFO("vcl.qt", "Unsupported QAccessibleTextInterface::removeSelection");
1152 void QtAccessibleWidget::scrollToSubstring(int startIndex, int endIndex)
1154 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1155 if (!xText.is())
1156 return;
1158 sal_Int32 nTextLength = xText->getCharacterCount();
1159 if (startIndex < 0 || startIndex > nTextLength || endIndex < 0 || endIndex > nTextLength)
1161 SAL_WARN("vcl.qt", "QtAccessibleWidget::scrollToSubstring called with invalid offset.");
1162 return;
1165 xText->scrollSubstringTo(startIndex, endIndex, AccessibleScrollType_SCROLL_ANYWHERE);
1168 void QtAccessibleWidget::selection(int selectionIndex, int* startOffset, int* endOffset) const
1170 if (!startOffset && !endOffset)
1171 return;
1173 Reference<XAccessibleText> xText;
1174 if (selectionIndex == 0)
1175 xText = Reference<XAccessibleText>(getAccessibleContextImpl(), UNO_QUERY);
1177 if (startOffset)
1178 *startOffset = xText.is() ? xText->getSelectionStart() : 0;
1179 if (endOffset)
1180 *endOffset = xText.is() ? xText->getSelectionEnd() : 0;
1183 int QtAccessibleWidget::selectionCount() const
1185 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1186 if (xText.is() && !xText->getSelectedText().isEmpty())
1187 return 1; // Only 1 selection supported atm
1188 return 0;
1191 void QtAccessibleWidget::setCursorPosition(int position)
1193 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1194 if (!xText.is())
1195 return;
1197 if (position < 0 || position > xText->getCharacterCount())
1199 SAL_WARN("vcl.qt",
1200 "QtAccessibleWidget::setCursorPosition called with invalid offset: " << position);
1201 return;
1204 xText->setCaretPosition(position);
1207 void QtAccessibleWidget::setSelection(int /* selectionIndex */, int startOffset, int endOffset)
1209 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1210 if (!xText.is())
1211 return;
1213 sal_Int32 nTextLength = xText->getCharacterCount();
1214 if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength)
1216 SAL_WARN("vcl.qt", "QtAccessibleWidget::setSelection called with invalid offset.");
1217 return;
1220 xText->setSelection(startOffset, endOffset);
1223 QString QtAccessibleWidget::text(int startOffset, int endOffset) const
1225 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1226 if (!xText.is())
1227 return QString();
1229 sal_Int32 nTextLength = xText->getCharacterCount();
1230 if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength)
1232 SAL_WARN("vcl.qt", "QtAccessibleWidget::text called with invalid offset.");
1233 return QString();
1236 return toQString(xText->getTextRange(startOffset, endOffset));
1239 QString QtAccessibleWidget::textAfterOffset(int nOffset,
1240 QAccessible::TextBoundaryType eBoundaryType,
1241 int* pStartOffset, int* pEndOffset) const
1243 if (pStartOffset == nullptr || pEndOffset == nullptr)
1244 return QString();
1246 *pStartOffset = -1;
1247 *pEndOffset = -1;
1249 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1250 if (!xText.is())
1251 return QString();
1253 const int nCharCount = characterCount();
1254 // -1 is special value for text length
1255 if (nOffset == -1)
1256 nOffset = nCharCount;
1257 else if (nOffset < -1 || nOffset > nCharCount)
1259 SAL_WARN("vcl.qt",
1260 "QtAccessibleWidget::textAfterOffset called with invalid offset: " << nOffset);
1261 return QString();
1264 if (eBoundaryType == QAccessible::NoBoundary)
1266 if (nOffset == nCharCount)
1267 return QString();
1268 *pStartOffset = nOffset + 1;
1269 *pEndOffset = nCharCount;
1270 return text(nOffset + 1, nCharCount);
1273 sal_Int16 nUnoBoundaryType = lcl_matchQtTextBoundaryType(eBoundaryType);
1274 assert(nUnoBoundaryType > 0);
1275 const TextSegment aSegment = xText->getTextBehindIndex(nOffset, nUnoBoundaryType);
1276 *pStartOffset = aSegment.SegmentStart;
1277 *pEndOffset = aSegment.SegmentEnd;
1278 return toQString(aSegment.SegmentText);
1281 QString QtAccessibleWidget::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType,
1282 int* startOffset, int* endOffset) const
1284 if (startOffset == nullptr || endOffset == nullptr)
1285 return QString();
1287 const int nCharCount = characterCount();
1288 if (boundaryType == QAccessible::NoBoundary)
1290 *startOffset = 0;
1291 *endOffset = nCharCount;
1292 return text(0, nCharCount);
1295 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1296 if (!xText.is())
1297 return QString();
1299 sal_Int16 nUnoBoundaryType = lcl_matchQtTextBoundaryType(boundaryType);
1300 assert(nUnoBoundaryType > 0);
1302 // special value of -1 for offset means text length
1303 if (offset == -1)
1304 offset = nCharCount;
1306 if (offset < 0 || offset > nCharCount)
1308 SAL_WARN("vcl.qt",
1309 "QtAccessibleWidget::textAtOffset called with invalid offset: " << offset);
1310 return QString();
1313 const TextSegment segment = xText->getTextAtIndex(offset, nUnoBoundaryType);
1314 *startOffset = segment.SegmentStart;
1315 *endOffset = segment.SegmentEnd;
1316 return toQString(segment.SegmentText);
1319 QString QtAccessibleWidget::textBeforeOffset(int nOffset,
1320 QAccessible::TextBoundaryType eBoundaryType,
1321 int* pStartOffset, int* pEndOffset) const
1323 if (pStartOffset == nullptr || pEndOffset == nullptr)
1324 return QString();
1326 *pStartOffset = -1;
1327 *pEndOffset = -1;
1329 Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
1330 if (!xText.is())
1331 return QString();
1333 const int nCharCount = characterCount();
1334 // -1 is special value for text length
1335 if (nOffset == -1)
1336 nOffset = nCharCount;
1337 else if (nOffset < -1 || nOffset > nCharCount)
1339 SAL_WARN("vcl.qt",
1340 "QtAccessibleWidget::textBeforeOffset called with invalid offset: " << nOffset);
1341 return QString();
1344 if (eBoundaryType == QAccessible::NoBoundary)
1346 *pStartOffset = 0;
1347 *pEndOffset = nOffset;
1348 return text(0, nOffset);
1351 sal_Int16 nUnoBoundaryType = lcl_matchQtTextBoundaryType(eBoundaryType);
1352 assert(nUnoBoundaryType > 0);
1353 const TextSegment aSegment = xText->getTextBeforeIndex(nOffset, nUnoBoundaryType);
1354 *pStartOffset = aSegment.SegmentStart;
1355 *pEndOffset = aSegment.SegmentEnd;
1356 return toQString(aSegment.SegmentText);
1359 // QAccessibleEditableTextInterface
1361 void QtAccessibleWidget::deleteText(int startOffset, int endOffset)
1363 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1364 if (!xAc.is())
1365 return;
1367 Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY);
1368 if (!xEditableText.is())
1369 return;
1371 sal_Int32 nTextLength = xEditableText->getCharacterCount();
1372 if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength)
1374 SAL_WARN("vcl.qt", "QtAccessibleWidget::deleteText called with invalid offset.");
1375 return;
1378 xEditableText->deleteText(startOffset, endOffset);
1381 void QtAccessibleWidget::insertText(int offset, const QString& text)
1383 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1384 if (!xAc.is())
1385 return;
1387 Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY);
1388 if (!xEditableText.is())
1389 return;
1391 if (offset < 0 || offset > xEditableText->getCharacterCount())
1393 SAL_WARN("vcl.qt", "QtAccessibleWidget::insertText called with invalid offset: " << offset);
1394 return;
1397 xEditableText->insertText(toOUString(text), offset);
1400 void QtAccessibleWidget::replaceText(int startOffset, int endOffset, const QString& text)
1402 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1403 if (!xAc.is())
1404 return;
1406 Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY);
1407 if (!xEditableText.is())
1408 return;
1410 sal_Int32 nTextLength = xEditableText->getCharacterCount();
1411 if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength)
1413 SAL_WARN("vcl.qt", "QtAccessibleWidget::replaceText called with invalid offset.");
1414 return;
1417 xEditableText->replaceText(startOffset, endOffset, toOUString(text));
1420 // QAccessibleValueInterface
1421 QVariant QtAccessibleWidget::currentValue() const
1423 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1424 if (!xAc.is())
1425 return QVariant();
1427 Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
1428 if (!xValue.is())
1429 return QVariant();
1430 double aDouble = 0;
1431 xValue->getCurrentValue() >>= aDouble;
1432 return QVariant(aDouble);
1435 QVariant QtAccessibleWidget::maximumValue() const
1437 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1438 if (!xAc.is())
1439 return QVariant();
1441 Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
1442 if (!xValue.is())
1443 return QVariant();
1444 double aDouble = 0;
1445 xValue->getMaximumValue() >>= aDouble;
1446 return QVariant(aDouble);
1449 QVariant QtAccessibleWidget::minimumStepSize() const
1451 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1452 if (!xAc.is())
1453 return QVariant();
1455 Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
1456 if (!xValue.is())
1457 return QVariant();
1458 double dMinStep = 0;
1459 xValue->getMinimumIncrement() >>= dMinStep;
1460 return QVariant(dMinStep);
1463 QVariant QtAccessibleWidget::minimumValue() const
1465 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1466 if (!xAc.is())
1467 return QVariant();
1469 Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
1470 if (!xValue.is())
1471 return QVariant();
1472 double aDouble = 0;
1473 xValue->getMinimumValue() >>= aDouble;
1474 return QVariant(aDouble);
1477 void QtAccessibleWidget::setCurrentValue(const QVariant& value)
1479 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1480 if (!xAc.is())
1481 return;
1483 Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
1484 if (!xValue.is())
1485 return;
1486 xValue->setCurrentValue(Any(value.toDouble()));
1489 // QAccessibleTableInterface
1490 QAccessibleInterface* QtAccessibleWidget::caption() const
1492 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1493 if (!xAc.is())
1494 return nullptr;
1496 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1497 if (!xTable.is())
1498 return nullptr;
1499 return QAccessible::queryAccessibleInterface(
1500 QtAccessibleRegistry::getQObject(xTable->getAccessibleCaption()));
1503 QAccessibleInterface* QtAccessibleWidget::cellAt(int row, int column) const
1505 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1506 if (!xAc.is())
1507 return nullptr;
1509 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1510 if (!xTable.is())
1511 return nullptr;
1513 if (row < 0 || row >= xTable->getAccessibleRowCount() || column < 0
1514 || column >= xTable->getAccessibleColumnCount())
1516 SAL_WARN("vcl.qt", "QtAccessibleWidget::cellAt called with invalid row/column index ("
1517 << row << ", " << column << ")");
1518 return nullptr;
1521 return QAccessible::queryAccessibleInterface(
1522 QtAccessibleRegistry::getQObject(xTable->getAccessibleCellAt(row, column)));
1525 int QtAccessibleWidget::columnCount() const
1527 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1528 if (!xAc.is())
1529 return 0;
1531 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1532 if (!xTable.is())
1533 return 0;
1534 return xTable->getAccessibleColumnCount();
1537 QString QtAccessibleWidget::columnDescription(int column) const
1539 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1540 if (!xAc.is())
1541 return QString();
1543 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1544 if (!xTable.is())
1545 return QString();
1546 return toQString(xTable->getAccessibleColumnDescription(column));
1549 bool QtAccessibleWidget::isColumnSelected(int nColumn) const
1551 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1552 if (!xAc.is())
1553 return false;
1555 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1556 if (!xTable.is())
1557 return false;
1559 if (nColumn < 0 || nColumn >= xTable->getAccessibleColumnCount())
1561 SAL_WARN("vcl.qt", "QtAccessibleWidget::isColumnSelected called with invalid column index "
1562 << nColumn);
1563 return false;
1566 return xTable->isAccessibleColumnSelected(nColumn);
1569 bool QtAccessibleWidget::isRowSelected(int nRow) const
1571 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1572 if (!xAc.is())
1573 return false;
1575 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1576 if (!xTable.is())
1577 return false;
1579 if (nRow < 0 || nRow >= xTable->getAccessibleRowCount())
1581 SAL_WARN("vcl.qt",
1582 "QtAccessibleWidget::isRowSelected called with invalid row index " << nRow);
1583 return false;
1586 return xTable->isAccessibleRowSelected(nRow);
1589 void QtAccessibleWidget::modelChange(QAccessibleTableModelChangeEvent*) {}
1591 int QtAccessibleWidget::rowCount() const
1593 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1594 if (!xAc.is())
1595 return 0;
1597 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1598 if (!xTable.is())
1599 return 0;
1600 return xTable->getAccessibleRowCount();
1603 QString QtAccessibleWidget::rowDescription(int row) const
1605 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1606 if (!xAc.is())
1607 return QString();
1609 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1610 if (!xTable.is())
1611 return QString();
1612 return toQString(xTable->getAccessibleRowDescription(row));
1615 bool QtAccessibleWidget::selectColumn(int column)
1617 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1618 if (!xAc.is())
1619 return false;
1621 if (column < 0 || column >= columnCount())
1623 SAL_WARN("vcl.qt",
1624 "QtAccessibleWidget::selectColumn called with invalid column index " << column);
1625 return false;
1628 Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY);
1629 if (!xTableSelection.is())
1630 return false;
1631 return xTableSelection->selectColumn(column);
1634 bool QtAccessibleWidget::selectRow(int row)
1636 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1637 if (!xAc.is())
1638 return false;
1640 if (row < 0 || row >= rowCount())
1642 SAL_WARN("vcl.qt", "QtAccessibleWidget::selectRow called with invalid row index " << row);
1643 return false;
1646 Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY);
1647 if (!xTableSelection.is())
1648 return false;
1649 return xTableSelection->selectRow(row);
1652 int QtAccessibleWidget::selectedCellCount() const
1654 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1655 if (!xAcc.is())
1656 return 0;
1658 Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
1659 if (!xSelection.is())
1660 return 0;
1662 sal_Int64 nSelected = xSelection->getSelectedAccessibleChildCount();
1663 if (nSelected > std::numeric_limits<int>::max())
1665 SAL_WARN("vcl.qt",
1666 "QtAccessibleWidget::selectedCellCount: Cell count exceeds maximum int value, "
1667 "using max int.");
1668 nSelected = std::numeric_limits<int>::max();
1670 return nSelected;
1673 QList<QAccessibleInterface*> QtAccessibleWidget::selectedCells() const
1675 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1676 if (!xAcc.is())
1677 return QList<QAccessibleInterface*>();
1679 Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
1680 if (!xSelection.is())
1681 return QList<QAccessibleInterface*>();
1683 QList<QAccessibleInterface*> aSelectedCells;
1684 sal_Int64 nSelected = xSelection->getSelectedAccessibleChildCount();
1685 if (nSelected > std::numeric_limits<int>::max())
1687 SAL_WARN("vcl.qt",
1688 "QtAccessibleWidget::selectedCells: Cell count exceeds maximum int value, "
1689 "using max int.");
1690 nSelected = std::numeric_limits<int>::max();
1692 for (sal_Int64 i = 0; i < nSelected; i++)
1694 Reference<XAccessible> xChild = xSelection->getSelectedAccessibleChild(i);
1695 QAccessibleInterface* pInterface
1696 = QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xChild));
1697 aSelectedCells.push_back(pInterface);
1699 return aSelectedCells;
1702 int QtAccessibleWidget::selectedColumnCount() const
1704 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1705 if (!xAc.is())
1706 return 0;
1708 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1709 if (!xTable.is())
1710 return 0;
1711 return xTable->getSelectedAccessibleColumns().getLength();
1714 QList<int> QtAccessibleWidget::selectedColumns() const
1716 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1717 if (!xAc.is())
1718 return QList<int>();
1720 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1721 if (!xTable.is())
1722 return QList<int>();
1723 return toQList(xTable->getSelectedAccessibleColumns());
1726 int QtAccessibleWidget::selectedRowCount() const
1728 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1729 if (!xAc.is())
1730 return 0;
1732 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1733 if (!xTable.is())
1734 return 0;
1735 return xTable->getSelectedAccessibleRows().getLength();
1738 QList<int> QtAccessibleWidget::selectedRows() const
1740 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1741 if (!xAc.is())
1742 return QList<int>();
1744 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1745 if (!xTable.is())
1746 return QList<int>();
1747 return toQList(xTable->getSelectedAccessibleRows());
1750 QAccessibleInterface* QtAccessibleWidget::summary() const
1752 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1753 if (!xAc.is())
1754 return nullptr;
1756 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1757 if (!xTable.is())
1758 return nullptr;
1759 return QAccessible::queryAccessibleInterface(
1760 QtAccessibleRegistry::getQObject(xTable->getAccessibleSummary()));
1763 bool QtAccessibleWidget::unselectColumn(int column)
1765 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1766 if (!xAc.is())
1767 return false;
1769 Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY);
1770 if (!xTableSelection.is())
1771 return false;
1772 return xTableSelection->unselectColumn(column);
1775 bool QtAccessibleWidget::unselectRow(int row)
1777 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1778 if (!xAc.is())
1779 return false;
1781 Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY);
1782 if (!xTableSelection.is())
1783 return false;
1784 return xTableSelection->unselectRow(row);
1787 // QAccessibleTableCellInterface
1788 QList<QAccessibleInterface*> QtAccessibleWidget::columnHeaderCells() const
1790 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
1791 if (!xTable.is())
1792 return QList<QAccessibleInterface*>();
1794 Reference<XAccessibleTable> xHeaders = xTable->getAccessibleColumnHeaders();
1795 if (!xHeaders.is())
1796 return QList<QAccessibleInterface*>();
1798 const sal_Int32 nCol = columnIndex();
1799 QList<QAccessibleInterface*> aHeaderCells;
1800 for (sal_Int32 nRow = 0; nRow < xHeaders->getAccessibleRowCount(); nRow++)
1802 Reference<XAccessible> xCell = xHeaders->getAccessibleCellAt(nRow, nCol);
1803 QAccessibleInterface* pInterface
1804 = QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xCell));
1805 aHeaderCells.push_back(pInterface);
1807 return aHeaderCells;
1810 int QtAccessibleWidget::columnIndex() const
1812 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1813 if (!xAcc.is())
1814 return -1;
1816 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
1817 if (!xTable.is())
1818 return -1;
1820 const sal_Int64 nIndexInParent = xAcc->getAccessibleIndexInParent();
1821 return xTable->getAccessibleColumn(nIndexInParent);
1824 bool QtAccessibleWidget::isSelected() const
1826 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1827 if (!xAcc.is())
1828 return false;
1830 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
1831 if (!xTable.is())
1832 return false;
1834 const sal_Int32 nColumn = columnIndex();
1835 const sal_Int32 nRow = rowIndex();
1836 return xTable->isAccessibleSelected(nRow, nColumn);
1839 int QtAccessibleWidget::columnExtent() const
1841 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1842 if (!xAcc.is())
1843 return -1;
1845 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
1846 if (!xTable.is())
1847 return -1;
1849 const sal_Int32 nColumn = columnIndex();
1850 const sal_Int32 nRow = rowIndex();
1851 return xTable->getAccessibleColumnExtentAt(nRow, nColumn);
1854 QList<QAccessibleInterface*> QtAccessibleWidget::rowHeaderCells() const
1856 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
1857 if (!xTable.is())
1858 return QList<QAccessibleInterface*>();
1860 Reference<XAccessibleTable> xHeaders = xTable->getAccessibleRowHeaders();
1861 if (!xHeaders.is())
1862 return QList<QAccessibleInterface*>();
1864 const sal_Int32 nRow = rowIndex();
1865 QList<QAccessibleInterface*> aHeaderCells;
1866 for (sal_Int32 nCol = 0; nCol < xHeaders->getAccessibleColumnCount(); nCol++)
1868 Reference<XAccessible> xCell = xHeaders->getAccessibleCellAt(nRow, nCol);
1869 QAccessibleInterface* pInterface
1870 = QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xCell));
1871 aHeaderCells.push_back(pInterface);
1873 return aHeaderCells;
1876 int QtAccessibleWidget::rowExtent() const
1878 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1879 if (!xAcc.is())
1880 return -1;
1882 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
1883 if (!xTable.is())
1884 return -1;
1886 const sal_Int32 nColumn = columnIndex();
1887 const sal_Int32 nRow = rowIndex();
1888 return xTable->getAccessibleRowExtentAt(nRow, nColumn);
1891 int QtAccessibleWidget::rowIndex() const
1893 Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
1894 if (!xAcc.is())
1895 return -1;
1897 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
1898 if (!xTable.is())
1899 return -1;
1901 const sal_Int64 nIndexInParent = xAcc->getAccessibleIndexInParent();
1902 return xTable->getAccessibleRow(nIndexInParent);
1905 QAccessibleInterface* QtAccessibleWidget::table() const
1907 Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
1908 if (!xTable.is())
1909 return nullptr;
1911 Reference<XAccessible> xTableAcc(xTable, UNO_QUERY);
1912 if (!xTableAcc.is())
1913 return nullptr;
1915 return QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xTableAcc));
1918 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */