1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <Qt5AccessibleWidget.hxx>
21 #include <Qt5AccessibleWidget.moc>
22
23 #include <QtGui/QAccessibleInterface>
24
25 #include <Qt5AccessibleEventListener.hxx>
26 #include <Qt5Frame.hxx>
27 #include <Qt5Tools.hxx>
28 #include <Qt5Widget.hxx>
29 #include <Qt5XAccessible.hxx>
30
31 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
32 #include <com/sun/star/accessibility/AccessibleRole.hpp>
33 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
34 #include <com/sun/star/accessibility/XAccessible.hpp>
35 #include <com/sun/star/accessibility/XAccessibleAction.hpp>
36 #include <com/sun/star/accessibility/XAccessibleComponent.hpp>
37 #include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
38 #include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
39 #include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
40 #include <com/sun/star/accessibility/XAccessibleKeyBinding.hpp>
41 #include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
42 #include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
43 #include <com/sun/star/accessibility/XAccessibleTable.hpp>
44 #include <com/sun/star/accessibility/XAccessibleTableSelection.hpp>
45 #include <com/sun/star/accessibility/XAccessibleText.hpp>
46 #include <com/sun/star/accessibility/XAccessibleValue.hpp>
47 #include <com/sun/star/awt/FontWeight.hpp>
48 #include <com/sun/star/beans/PropertyValue.hpp>
49 #include <com/sun/star/lang/DisposedException.hpp>
50 #include <com/sun/star/uno/Sequence.hxx>
51
52 #include <comphelper/AccessibleImplementationHelper.hxx>
53 #include <sal/log.hxx>
54 #include <vcl/popupmenuwindow.hxx>
55
56 using namespace css;
57 using namespace css::accessibility;
58 using namespace css::beans;
59 using namespace css::uno;
60
Qt5AccessibleWidget(const Reference<XAccessible> xAccessible,QObject * pObject)61 Qt5AccessibleWidget::Qt5AccessibleWidget(const Reference<XAccessible> xAccessible, QObject* pObject)
62 : m_xAccessible(xAccessible)
63 , m_pObject(pObject)
64 {
65 Reference<XAccessibleContext> xContext = xAccessible->getAccessibleContext();
66 Reference<XAccessibleEventBroadcaster> xBroadcaster(xContext, UNO_QUERY);
67 if (xBroadcaster.is())
68 {
69 Reference<XAccessibleEventListener> xListener(
70 new Qt5AccessibleEventListener(xAccessible, this));
71 xBroadcaster->addAccessibleEventListener(xListener);
72 }
73 }
74
getAccessibleContextImpl() const75 Reference<XAccessibleContext> Qt5AccessibleWidget::getAccessibleContextImpl() const
76 {
77 Reference<XAccessibleContext> xAc;
78
79 if (m_xAccessible.is())
80 {
81 try
82 {
83 xAc = m_xAccessible->getAccessibleContext();
84 }
85 catch (css::lang::DisposedException /*ex*/)
86 {
87 SAL_WARN("vcl.qt5", "Accessible context disposed already");
88 }
89 // sometimes getAccessibleContext throws also RuntimeException if context is no longer alive
90 catch (css::uno::RuntimeException /*ex*/)
91 {
92 // so let's catch it here, cuz otherwise soffice falls flat on its face
93 // with FatalError and nothing else
94 SAL_WARN("vcl.qt5", "Accessible context no longer alive");
95 }
96 }
97
98 return xAc;
99 }
100
window() const101 QWindow* Qt5AccessibleWidget::window() const { return nullptr; }
102
childCount() const103 int Qt5AccessibleWidget::childCount() const
104 {
105 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
106 if (!xAc.is())
107 return 0;
108
109 return xAc->getAccessibleChildCount();
110 }
111
indexOfChild(const QAccessibleInterface *) const112 int Qt5AccessibleWidget::indexOfChild(const QAccessibleInterface* /* child */) const { return 0; }
113
114 namespace
115 {
lcl_matchUnoRelation(short relationType)116 QAccessible::Relation lcl_matchUnoRelation(short relationType)
117 {
118 switch (relationType)
119 {
120 case AccessibleRelationType::CONTROLLER_FOR:
121 return QAccessible::Controller;
122 case AccessibleRelationType::CONTROLLED_BY:
123 return QAccessible::Controlled;
124 case AccessibleRelationType::LABEL_FOR:
125 return QAccessible::Label;
126 case AccessibleRelationType::LABELED_BY:
127 return QAccessible::Labelled;
128 case AccessibleRelationType::INVALID:
129 case AccessibleRelationType::CONTENT_FLOWS_FROM:
130 case AccessibleRelationType::CONTENT_FLOWS_TO:
131 case AccessibleRelationType::MEMBER_OF:
132 case AccessibleRelationType::SUB_WINDOW_OF:
133 case AccessibleRelationType::NODE_CHILD_OF:
134 case AccessibleRelationType::DESCRIBED_BY:
135 default:
136 SAL_WARN("vcl.qt5", "Unmatched relation: " << relationType);
137 return nullptr;
138 }
139 }
140
lcl_matchQtRelation(QAccessible::Relation relationType)141 short lcl_matchQtRelation(QAccessible::Relation relationType)
142 {
143 switch (relationType)
144 {
145 case QAccessible::Controller:
146 return AccessibleRelationType::CONTROLLER_FOR;
147 case QAccessible::Controlled:
148 return AccessibleRelationType::CONTROLLED_BY;
149 case QAccessible::Label:
150 return AccessibleRelationType::LABEL_FOR;
151 case QAccessible::Labelled:
152 return AccessibleRelationType::LABELED_BY;
153 default:
154 SAL_WARN("vcl.qt5", "Unmatched relation: " << relationType);
155 }
156 return 0;
157 }
158
lcl_appendRelation(QVector<QPair<QAccessibleInterface *,QAccessible::Relation>> * relations,AccessibleRelation aRelation)159 void lcl_appendRelation(QVector<QPair<QAccessibleInterface*, QAccessible::Relation>>* relations,
160 AccessibleRelation aRelation)
161 {
162 QAccessible::Relation aQRelation = lcl_matchUnoRelation(aRelation.RelationType);
163 sal_uInt32 nTargetCount = aRelation.TargetSet.getLength();
164
165 for (sal_uInt32 i = 0; i < nTargetCount; i++)
166 {
167 Reference<XAccessible> xAccessible(aRelation.TargetSet[i], uno::UNO_QUERY);
168 relations->append(
169 { QAccessible::queryAccessibleInterface(new Qt5XAccessible(xAccessible)), aQRelation });
170 }
171 }
172 }
173
174 QVector<QPair<QAccessibleInterface*, QAccessible::Relation>>
relations(QAccessible::Relation match) const175 Qt5AccessibleWidget::relations(QAccessible::Relation match) const
176 {
177 QVector<QPair<QAccessibleInterface*, QAccessible::Relation>> relations;
178
179 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
180 if (!xAc.is())
181 return relations;
182
183 Reference<XAccessibleRelationSet> xRelationSet = xAc->getAccessibleRelationSet();
184 if (xRelationSet.is())
185 {
186 if (match == QAccessible::AllRelations)
187 {
188 int count = xRelationSet->getRelationCount();
189 for (int i = 0; i < count; i++)
190 {
191 AccessibleRelation aRelation = xRelationSet->getRelation(i);
192 lcl_appendRelation(&relations, aRelation);
193 }
194 }
195 else
196 {
197 AccessibleRelation aRelation = xRelationSet->getRelation(lcl_matchQtRelation(match));
198 lcl_appendRelation(&relations, aRelation);
199 }
200 }
201
202 return relations;
203 }
204
focusChild() const205 QAccessibleInterface* Qt5AccessibleWidget::focusChild() const
206 {
207 /* if (m_pWindow->HasChildPathFocus())
208 return QAccessible::queryAccessibleInterface(
209 new Qt5XAccessible(m_xAccessible->getAccessibleContext()->getAccessibleChild(index))); */
210 return QAccessible::queryAccessibleInterface(object());
211 }
212
rect() const213 QRect Qt5AccessibleWidget::rect() const
214 {
215 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
216 if (!xAc.is())
217 return QRect();
218
219 Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY);
220 awt::Point aPoint = xAccessibleComponent->getLocation();
221 awt::Size aSize = xAccessibleComponent->getSize();
222
223 return QRect(aPoint.X, aPoint.Y, aSize.Width, aSize.Height);
224 }
225
parent() const226 QAccessibleInterface* Qt5AccessibleWidget::parent() const
227 {
228 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
229 if (!xAc.is())
230 return nullptr;
231
232 return QAccessible::queryAccessibleInterface(new Qt5XAccessible(xAc->getAccessibleParent()));
233 }
child(int index) const234 QAccessibleInterface* Qt5AccessibleWidget::child(int index) const
235 {
236 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
237 if (!xAc.is())
238 return nullptr;
239
240 return QAccessible::queryAccessibleInterface(
241 new Qt5XAccessible(xAc->getAccessibleChild(index)));
242 }
243
text(QAccessible::Text text) const244 QString Qt5AccessibleWidget::text(QAccessible::Text text) const
245 {
246 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
247 if (!xAc.is())
248 return QString();
249
250 switch (text)
251 {
252 case QAccessible::Name:
253 return toQString(xAc->getAccessibleName());
254 case QAccessible::Description:
255 case QAccessible::DebugDescription:
256 return toQString(xAc->getAccessibleDescription());
257 case QAccessible::Value:
258 case QAccessible::Help:
259 case QAccessible::Accelerator:
260 case QAccessible::UserText:
261 default:
262 return QString("Unknown");
263 }
264 }
role() const265 QAccessible::Role Qt5AccessibleWidget::role() const
266 {
267 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
268 if (!xAc.is())
269 return QAccessible::NoRole;
270
271 switch (xAc->getAccessibleRole())
272 {
273 case AccessibleRole::UNKNOWN:
274 return QAccessible::NoRole;
275
276 case AccessibleRole::ALERT:
277 return QAccessible::AlertMessage;
278
279 case AccessibleRole::COLUMN_HEADER:
280 return QAccessible::ColumnHeader;
281
282 case AccessibleRole::CANVAS:
283 return QAccessible::Canvas;
284
285 case AccessibleRole::CHECK_BOX:
286 return QAccessible::CheckBox;
287
288 case AccessibleRole::CHECK_MENU_ITEM:
289 return QAccessible::MenuItem;
290
291 case AccessibleRole::COLOR_CHOOSER:
292 return QAccessible::ColorChooser;
293
294 case AccessibleRole::COMBO_BOX:
295 return QAccessible::ComboBox;
296
297 case AccessibleRole::DATE_EDITOR:
298 return QAccessible::EditableText;
299
300 case AccessibleRole::DESKTOP_ICON:
301 return QAccessible::Graphic;
302
303 case AccessibleRole::DESKTOP_PANE:
304 case AccessibleRole::DIRECTORY_PANE:
305 return QAccessible::Pane;
306
307 case AccessibleRole::DIALOG:
308 return QAccessible::Dialog;
309
310 case AccessibleRole::DOCUMENT:
311 return QAccessible::Document;
312
313 case AccessibleRole::EMBEDDED_OBJECT:
314 return QAccessible::UserRole;
315
316 case AccessibleRole::END_NOTE:
317 return QAccessible::Note;
318
319 case AccessibleRole::FILLER:
320 return QAccessible::Whitespace;
321
322 case AccessibleRole::FONT_CHOOSER:
323 return QAccessible::UserRole;
324
325 case AccessibleRole::FOOTER:
326 return QAccessible::Footer;
327
328 case AccessibleRole::FOOTNOTE:
329 return QAccessible::Note;
330
331 case AccessibleRole::FRAME: // top-level window with title bar
332 return QAccessible::Window;
333
334 case AccessibleRole::GLASS_PANE:
335 return QAccessible::UserRole;
336
337 case AccessibleRole::GRAPHIC:
338 return QAccessible::Graphic;
339
340 case AccessibleRole::GROUP_BOX:
341 return QAccessible::Grouping;
342
343 case AccessibleRole::HEADER:
344 return QAccessible::UserRole;
345
346 case AccessibleRole::HEADING:
347 return QAccessible::Heading;
348
349 case AccessibleRole::HYPER_LINK:
350 return QAccessible::Link;
351
352 case AccessibleRole::ICON:
353 return QAccessible::Graphic;
354
355 case AccessibleRole::INTERNAL_FRAME:
356 return QAccessible::UserRole;
357
358 case AccessibleRole::LABEL:
359 return QAccessible::StaticText;
360
361 case AccessibleRole::LAYERED_PANE:
362 return QAccessible::Pane;
363
364 case AccessibleRole::LIST:
365 return QAccessible::List;
366
367 case AccessibleRole::LIST_ITEM:
368 return QAccessible::ListItem;
369
370 case AccessibleRole::MENU:
371 case AccessibleRole::MENU_BAR:
372 return QAccessible::MenuBar;
373
374 case AccessibleRole::MENU_ITEM:
375 return QAccessible::MenuItem;
376
377 case AccessibleRole::OPTION_PANE:
378 return QAccessible::Pane;
379
380 case AccessibleRole::PAGE_TAB:
381 return QAccessible::PageTab;
382
383 case AccessibleRole::PAGE_TAB_LIST:
384 return QAccessible::PageTabList;
385
386 case AccessibleRole::PANEL:
387 return QAccessible::Pane;
388
389 case AccessibleRole::PARAGRAPH:
390 return QAccessible::Paragraph;
391
392 case AccessibleRole::PASSWORD_TEXT:
393 return QAccessible::EditableText;
394
395 case AccessibleRole::POPUP_MENU:
396 return QAccessible::PopupMenu;
397
398 case AccessibleRole::PUSH_BUTTON:
399 return QAccessible::Button;
400
401 case AccessibleRole::PROGRESS_BAR:
402 return QAccessible::ProgressBar;
403
404 case AccessibleRole::RADIO_BUTTON:
405 return QAccessible::RadioButton;
406
407 case AccessibleRole::RADIO_MENU_ITEM:
408 return QAccessible::MenuItem;
409
410 case AccessibleRole::ROW_HEADER:
411 return QAccessible::RowHeader;
412
413 case AccessibleRole::ROOT_PANE:
414 return QAccessible::Pane;
415
416 case AccessibleRole::SCROLL_BAR:
417 return QAccessible::ScrollBar;
418
419 case AccessibleRole::SCROLL_PANE:
420 return QAccessible::Pane;
421
422 case AccessibleRole::SHAPE:
423 return QAccessible::Graphic;
424
425 case AccessibleRole::SEPARATOR:
426 return QAccessible::Separator;
427
428 case AccessibleRole::SLIDER:
429 return QAccessible::Slider;
430
431 case AccessibleRole::SPIN_BOX:
432 return QAccessible::SpinBox;
433
434 case AccessibleRole::SPLIT_PANE:
435 return QAccessible::Pane;
436
437 case AccessibleRole::STATUS_BAR:
438 return QAccessible::StatusBar;
439
440 case AccessibleRole::TABLE:
441 return QAccessible::Table;
442
443 case AccessibleRole::TABLE_CELL:
444 return QAccessible::Cell;
445
446 case AccessibleRole::TEXT:
447 return QAccessible::EditableText;
448
449 case AccessibleRole::TEXT_FRAME:
450 return QAccessible::UserRole;
451
452 case AccessibleRole::TOGGLE_BUTTON:
453 return QAccessible::Button;
454
455 case AccessibleRole::TOOL_BAR:
456 return QAccessible::ToolBar;
457
458 case AccessibleRole::TOOL_TIP:
459 return QAccessible::ToolTip;
460
461 case AccessibleRole::TREE:
462 return QAccessible::Tree;
463
464 case AccessibleRole::VIEW_PORT:
465 return QAccessible::UserRole;
466
467 case AccessibleRole::BUTTON_DROPDOWN:
468 return QAccessible::Button;
469
470 case AccessibleRole::BUTTON_MENU:
471 return QAccessible::Button;
472
473 case AccessibleRole::CAPTION:
474 return QAccessible::StaticText;
475
476 case AccessibleRole::CHART:
477 return QAccessible::Chart;
478
479 case AccessibleRole::EDIT_BAR:
480 return QAccessible::Equation;
481
482 case AccessibleRole::FORM:
483 return QAccessible::Form;
484
485 case AccessibleRole::IMAGE_MAP:
486 return QAccessible::Graphic;
487
488 case AccessibleRole::NOTE:
489 return QAccessible::Note;
490
491 case AccessibleRole::RULER:
492 return QAccessible::UserRole;
493
494 case AccessibleRole::SECTION:
495 return QAccessible::Section;
496
497 case AccessibleRole::TREE_ITEM:
498 return QAccessible::TreeItem;
499
500 case AccessibleRole::TREE_TABLE:
501 return QAccessible::Tree;
502
503 case AccessibleRole::COMMENT:
504 return QAccessible::Note;
505
506 case AccessibleRole::COMMENT_END:
507 return QAccessible::UserRole;
508
509 case AccessibleRole::DOCUMENT_PRESENTATION:
510 return QAccessible::Document;
511
512 case AccessibleRole::DOCUMENT_SPREADSHEET:
513 return QAccessible::Document;
514
515 case AccessibleRole::DOCUMENT_TEXT:
516 return QAccessible::Document;
517
518 case AccessibleRole::STATIC:
519 return QAccessible::StaticText;
520
521 /* Ignore window objects for sub-menus, combo- and list boxes,
522 * which are exposed as children of their parents.
523 */
524 case AccessibleRole::WINDOW: // top-level window without title bar
525 {
526 return QAccessible::Window;
527 }
528 }
529
530 SAL_WARN("vcl.qt5",
531 "Unmapped role: " << m_xAccessible->getAccessibleContext()->getAccessibleRole());
532 return QAccessible::NoRole;
533 }
534
535 namespace
536 {
lcl_addState(QAccessible::State * state,sal_Int16 nState)537 void lcl_addState(QAccessible::State* state, sal_Int16 nState)
538 {
539 switch (nState)
540 {
541 case AccessibleStateType::INVALID:
542 state->invalid = true;
543 break;
544 case AccessibleStateType::ACTIVE:
545 state->active = true;
546 break;
547 case AccessibleStateType::ARMED:
548 // No match
549 break;
550 case AccessibleStateType::BUSY:
551 state->busy = true;
552 break;
553 case AccessibleStateType::CHECKED:
554 state->checked = true;
555 break;
556 case AccessibleStateType::EDITABLE:
557 state->editable = true;
558 break;
559 case AccessibleStateType::ENABLED:
560 state->disabled = false;
561 break;
562 case AccessibleStateType::EXPANDABLE:
563 state->expandable = true;
564 break;
565 case AccessibleStateType::FOCUSABLE:
566 state->focusable = true;
567 break;
568 case AccessibleStateType::FOCUSED:
569 state->focused = true;
570 break;
571 case AccessibleStateType::HORIZONTAL:
572 // No match
573 break;
574 case AccessibleStateType::ICONIFIED:
575 // No match
576 break;
577 case AccessibleStateType::INDETERMINATE:
578 // No match
579 break;
580 case AccessibleStateType::MANAGES_DESCENDANTS:
581 // No match
582 break;
583 case AccessibleStateType::MODAL:
584 state->modal = true;
585 break;
586 case AccessibleStateType::OPAQUE:
587 // No match
588 break;
589 case AccessibleStateType::PRESSED:
590 state->pressed = true;
591 break;
592 case AccessibleStateType::RESIZABLE:
593 state->sizeable = true;
594 break;
595 case AccessibleStateType::SELECTABLE:
596 state->selectable = true;
597 break;
598 case AccessibleStateType::SELECTED:
599 state->selected = true;
600 break;
601 case AccessibleStateType::SENSITIVE:
602 // No match
603 break;
604 case AccessibleStateType::SHOWING:
605 // No match
606 break;
607 case AccessibleStateType::SINGLE_LINE:
608 // No match
609 break;
610 case AccessibleStateType::STALE:
611 // No match
612 break;
613 case AccessibleStateType::TRANSIENT:
614 // No match
615 break;
616 case AccessibleStateType::VERTICAL:
617 // No match
618 break;
619 case AccessibleStateType::VISIBLE:
620 state->invisible = false;
621 break;
622 case AccessibleStateType::DEFAULT:
623 // No match
624 break;
625 case AccessibleStateType::DEFUNC:
626 state->invalid = true;
627 break;
628 case AccessibleStateType::MULTI_SELECTABLE:
629 state->multiSelectable = true;
630 break;
631 default:
632 SAL_WARN("vcl.qt5", "Unmapped state: " << nState);
633 break;
634 }
635 }
636 }
637
state() const638 QAccessible::State Qt5AccessibleWidget::state() const
639 {
640 QAccessible::State state;
641
642 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
643 if (!xAc.is())
644 return state;
645
646 Reference<XAccessibleStateSet> xStateSet(xAc->getAccessibleStateSet());
647
648 if (!xStateSet.is())
649 return state;
650
651 Sequence<sal_Int16> aStates = xStateSet->getStates();
652
653 for (sal_Int32 n = 0; n < aStates.getLength(); n++)
654 {
655 lcl_addState(&state, n);
656 }
657
658 return state;
659 }
660
foregroundColor() const661 QColor Qt5AccessibleWidget::foregroundColor() const
662 {
663 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
664 if (!xAc.is())
665 return QColor();
666
667 Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY);
668 return toQColor(xAccessibleComponent->getForeground());
669 }
670
backgroundColor() const671 QColor Qt5AccessibleWidget::backgroundColor() const
672 {
673 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
674 if (!xAc.is())
675 return QColor();
676
677 Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY);
678 return toQColor(xAccessibleComponent->getBackground());
679 }
680
interface_cast(QAccessible::InterfaceType t)681 void* Qt5AccessibleWidget::interface_cast(QAccessible::InterfaceType t)
682 {
683 if (t == QAccessible::ActionInterface)
684 return static_cast<QAccessibleActionInterface*>(this);
685 if (t == QAccessible::TextInterface)
686 return static_cast<QAccessibleTextInterface*>(this);
687 if (t == QAccessible::EditableTextInterface)
688 return static_cast<QAccessibleEditableTextInterface*>(this);
689 if (t == QAccessible::ValueInterface)
690 return static_cast<QAccessibleValueInterface*>(this);
691 if (t == QAccessible::TableInterface)
692 return static_cast<QAccessibleTableInterface*>(this);
693 return nullptr;
694 }
695
isValid() const696 bool Qt5AccessibleWidget::isValid() const
697 {
698 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
699 return xAc.is();
700 }
701
object() const702 QObject* Qt5AccessibleWidget::object() const { return m_pObject; }
703
setText(QAccessible::Text,const QString &)704 void Qt5AccessibleWidget::setText(QAccessible::Text /* t */, const QString& /* text */) {}
705
childAt(int x,int y) const706 QAccessibleInterface* Qt5AccessibleWidget::childAt(int x, int y) const
707 {
708 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
709 if (!xAc.is())
710 return nullptr;
711
712 Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY);
713 return QAccessible::queryAccessibleInterface(
714 new Qt5XAccessible(xAccessibleComponent->getAccessibleAtPoint(awt::Point(x, y))));
715 }
716
customFactory(const QString & classname,QObject * object)717 QAccessibleInterface* Qt5AccessibleWidget::customFactory(const QString& classname, QObject* object)
718 {
719 if (classname == QLatin1String("Qt5Widget") && object && object->isWidgetType())
720 {
721 Qt5Widget* pWidget = static_cast<Qt5Widget*>(object);
722 vcl::Window* pWindow = pWidget->frame().GetWindow();
723
724 if (pWindow)
725 return new Qt5AccessibleWidget(pWindow->GetAccessible(), object);
726 }
727 if (classname == QLatin1String("Qt5XAccessible") && object)
728 {
729 Qt5XAccessible* pXAccessible = dynamic_cast<Qt5XAccessible*>(object);
730 if (pXAccessible && pXAccessible->m_xAccessible.is())
731 return new Qt5AccessibleWidget(pXAccessible->m_xAccessible, object);
732 }
733
734 return nullptr;
735 }
736
737 // QAccessibleActionInterface
actionNames() const738 QStringList Qt5AccessibleWidget::actionNames() const
739 {
740 QStringList actionNames;
741 Reference<XAccessibleAction> xAccessibleAction(m_xAccessible, UNO_QUERY);
742 if (!xAccessibleAction.is())
743 return actionNames;
744
745 int count = xAccessibleAction->getAccessibleActionCount();
746 for (int i = 0; i < count; i++)
747 {
748 OUString desc = xAccessibleAction->getAccessibleActionDescription(i);
749 actionNames.append(toQString(desc));
750 }
751 return actionNames;
752 }
753
doAction(const QString & actionName)754 void Qt5AccessibleWidget::doAction(const QString& actionName)
755 {
756 Reference<XAccessibleAction> xAccessibleAction(m_xAccessible, UNO_QUERY);
757 if (!xAccessibleAction.is())
758 return;
759
760 int index = actionNames().indexOf(actionName);
761 if (index == -1)
762 return;
763 xAccessibleAction->doAccessibleAction(index);
764 }
765
keyBindingsForAction(const QString & actionName) const766 QStringList Qt5AccessibleWidget::keyBindingsForAction(const QString& actionName) const
767 {
768 QStringList keyBindings;
769 Reference<XAccessibleAction> xAccessibleAction(m_xAccessible, UNO_QUERY);
770 if (!xAccessibleAction.is())
771 return keyBindings;
772
773 int index = actionNames().indexOf(actionName);
774 if (index == -1)
775 return keyBindings;
776
777 Reference<XAccessibleKeyBinding> xKeyBinding
778 = xAccessibleAction->getAccessibleActionKeyBinding(index);
779
780 if (!xKeyBinding.is())
781 return keyBindings;
782
783 int count = xKeyBinding->getAccessibleKeyBindingCount();
784 for (int i = 0; i < count; i++)
785 {
786 Sequence<awt::KeyStroke> keyStroke = xKeyBinding->getAccessibleKeyBinding(i);
787 keyBindings.append(toQString(comphelper::GetkeyBindingStrByXkeyBinding(keyStroke)));
788 }
789 return keyBindings;
790 }
791
valueInterface()792 QAccessibleValueInterface* Qt5AccessibleWidget::valueInterface() { return nullptr; }
793
textInterface()794 QAccessibleTextInterface* Qt5AccessibleWidget::textInterface() { return nullptr; }
795
796 // QAccessibleTextInterface
addSelection(int,int)797 void Qt5AccessibleWidget::addSelection(int /* startOffset */, int /* endOffset */)
798 {
799 SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::addSelection");
800 }
801
802 namespace
803 {
lcl_convertFontWeight(double fontWeight)804 OUString lcl_convertFontWeight(double fontWeight)
805 {
806 if (fontWeight == awt::FontWeight::THIN || fontWeight == awt::FontWeight::ULTRALIGHT)
807 return "100";
808 if (fontWeight == awt::FontWeight::LIGHT)
809 return "200";
810 if (fontWeight == awt::FontWeight::SEMILIGHT)
811 return "300";
812 if (fontWeight == awt::FontWeight::NORMAL)
813 return "normal";
814 if (fontWeight == awt::FontWeight::SEMIBOLD)
815 return "500";
816 if (fontWeight == awt::FontWeight::BOLD)
817 return "bold";
818 if (fontWeight == awt::FontWeight::ULTRABOLD)
819 return "800";
820 if (fontWeight == awt::FontWeight::BLACK)
821 return "900";
822
823 // awt::FontWeight::DONTKNOW || fontWeight == awt::FontWeight::NORMAL
824 return "normal";
825 }
826 }
827
attributes(int offset,int * startOffset,int * endOffset) const828 QString Qt5AccessibleWidget::attributes(int offset, int* startOffset, int* endOffset) const
829 {
830 Reference<XAccessibleText> xText(m_xAccessible, UNO_QUERY);
831 if (!xText.is())
832 return QString();
833
834 // handle special values for offset the same way base class's QAccessibleTextWidget::attributes does
835 // (as defined in IAccessible 2: -1 -> length, -2 -> cursor position)
836 if (offset == -2)
837 offset = cursorPosition(); // currently always returns 0
838
839 const int nTextLength = characterCount();
840 if (offset == -1 || offset == nTextLength)
841 offset = nTextLength - 1;
842
843 if (offset < 0 || offset > nTextLength)
844 {
845 *startOffset = -1;
846 *endOffset = -1;
847 return QString();
848 }
849
850 Sequence<PropertyValue> attribs = xText->getCharacterAttributes(offset, Sequence<OUString>());
851 const PropertyValue* pValues = attribs.getConstArray();
852 OUString aRet;
853 for (sal_Int32 i = 0; i < attribs.getLength(); i++)
854 {
855 if (pValues[i].Name == "CharFontName")
856 {
857 OUString aStr;
858 pValues[i].Value >>= aStr;
859 aRet += "font-family:" + aStr + ";";
860 continue;
861 }
862 if (pValues[i].Name == "CharHeight")
863 {
864 double fHeight;
865 pValues[i].Value >>= fHeight;
866 aRet += "font-size:" + OUString::number(fHeight) + "pt;";
867 continue;
868 }
869 if (pValues[i].Name == "CharWeight")
870 {
871 double fWeight;
872 pValues[i].Value >>= fWeight;
873 aRet += "font-weight:" + lcl_convertFontWeight(fWeight) + ";";
874 continue;
875 }
876 }
877 *startOffset = offset;
878 *endOffset = offset + 1;
879 return toQString(aRet);
880 }
characterCount() const881 int Qt5AccessibleWidget::characterCount() const
882 {
883 Reference<XAccessibleText> xText(m_xAccessible, UNO_QUERY);
884 if (xText.is())
885 return xText->getCharacterCount();
886 return 0;
887 }
characterRect(int) const888 QRect Qt5AccessibleWidget::characterRect(int /* offset */) const
889 {
890 SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::characterRect");
891 return QRect();
892 }
cursorPosition() const893 int Qt5AccessibleWidget::cursorPosition() const
894 {
895 SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::cursorPosition");
896 return 0;
897 }
offsetAtPoint(const QPoint &) const898 int Qt5AccessibleWidget::offsetAtPoint(const QPoint& /* point */) const
899 {
900 SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::offsetAtPoint");
901 return 0;
902 }
removeSelection(int)903 void Qt5AccessibleWidget::removeSelection(int /* selectionIndex */)
904 {
905 SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::removeSelection");
906 }
scrollToSubstring(int,int)907 void Qt5AccessibleWidget::scrollToSubstring(int /* startIndex */, int /* endIndex */)
908 {
909 SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::scrollToSubstring");
910 }
911
selection(int selectionIndex,int * startOffset,int * endOffset) const912 void Qt5AccessibleWidget::selection(int selectionIndex, int* startOffset, int* endOffset) const
913 {
914 if (!startOffset && !endOffset)
915 return;
916
917 Reference<XAccessibleText> xText;
918 if (selectionIndex == 0)
919 xText = Reference<XAccessibleText>(m_xAccessible, UNO_QUERY);
920
921 if (startOffset)
922 *startOffset = xText.is() ? xText->getSelectionStart() : 0;
923 if (endOffset)
924 *endOffset = xText.is() ? xText->getSelectionEnd() : 0;
925 }
926
selectionCount() const927 int Qt5AccessibleWidget::selectionCount() const
928 {
929 Reference<XAccessibleText> xText(m_xAccessible, UNO_QUERY);
930 if (xText.is() && !xText->getSelectedText().isEmpty())
931 return 1; // Only 1 selection supported atm
932 return 0;
933 }
setCursorPosition(int position)934 void Qt5AccessibleWidget::setCursorPosition(int position)
935 {
936 Reference<XAccessibleText> xText(m_xAccessible, UNO_QUERY);
937 if (xText.is())
938 xText->setCaretPosition(position);
939 }
setSelection(int,int startOffset,int endOffset)940 void Qt5AccessibleWidget::setSelection(int /* selectionIndex */, int startOffset, int endOffset)
941 {
942 Reference<XAccessibleText> xText(m_xAccessible, UNO_QUERY);
943 if (xText.is())
944 xText->setSelection(startOffset, endOffset);
945 }
text(int startOffset,int endOffset) const946 QString Qt5AccessibleWidget::text(int startOffset, int endOffset) const
947 {
948 Reference<XAccessibleText> xText(m_xAccessible, UNO_QUERY);
949 if (xText.is())
950 return toQString(xText->getTextRange(startOffset, endOffset));
951 return QString();
952 }
textAfterOffset(int,QAccessible::TextBoundaryType,int *,int *) const953 QString Qt5AccessibleWidget::textAfterOffset(int /* offset */,
954 QAccessible::TextBoundaryType /* boundaryType */,
955 int* /* startOffset */, int* /* endOffset */) const
956 {
957 SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::textAfterOffset");
958 return QString();
959 }
textAtOffset(int,QAccessible::TextBoundaryType,int *,int *) const960 QString Qt5AccessibleWidget::textAtOffset(int /* offset */,
961 QAccessible::TextBoundaryType /* boundaryType */,
962 int* /* startOffset */, int* /* endOffset */) const
963 {
964 SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::textAtOffset");
965 return QString();
966 }
textBeforeOffset(int,QAccessible::TextBoundaryType,int *,int *) const967 QString Qt5AccessibleWidget::textBeforeOffset(int /* offset */,
968 QAccessible::TextBoundaryType /* boundaryType */,
969 int* /* startOffset */, int* /* endOffset */) const
970 {
971 SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::textBeforeOffset");
972 return QString();
973 }
974
975 // QAccessibleEditableTextInterface
976
deleteText(int startOffset,int endOffset)977 void Qt5AccessibleWidget::deleteText(int startOffset, int endOffset)
978 {
979 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
980 if (!xAc.is())
981 return;
982
983 Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY);
984 if (!xEditableText.is())
985 return;
986 xEditableText->deleteText(startOffset, endOffset);
987 }
988
insertText(int offset,const QString & text)989 void Qt5AccessibleWidget::insertText(int offset, const QString& text)
990 {
991 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
992 if (!xAc.is())
993 return;
994
995 Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY);
996 if (!xEditableText.is())
997 return;
998 xEditableText->insertText(toOUString(text), offset);
999 }
1000
replaceText(int startOffset,int endOffset,const QString & text)1001 void Qt5AccessibleWidget::replaceText(int startOffset, int endOffset, const QString& text)
1002 {
1003 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1004 if (!xAc.is())
1005 return;
1006
1007 Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY);
1008 if (!xEditableText.is())
1009 return;
1010 xEditableText->replaceText(startOffset, endOffset, toOUString(text));
1011 }
1012
1013 // QAccessibleValueInterface
currentValue() const1014 QVariant Qt5AccessibleWidget::currentValue() const
1015 {
1016 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1017 if (!xAc.is())
1018 return QVariant();
1019
1020 Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
1021 if (!xValue.is())
1022 return QVariant();
1023 double aDouble = 0;
1024 xValue->getCurrentValue() >>= aDouble;
1025 return QVariant(aDouble);
1026 }
maximumValue() const1027 QVariant Qt5AccessibleWidget::maximumValue() const
1028 {
1029 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1030 if (!xAc.is())
1031 return QVariant();
1032
1033 Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
1034 if (!xValue.is())
1035 return QVariant();
1036 double aDouble = 0;
1037 xValue->getMaximumValue() >>= aDouble;
1038 return QVariant(aDouble);
1039 }
minimumStepSize() const1040 QVariant Qt5AccessibleWidget::minimumStepSize() const { return QVariant(); }
minimumValue() const1041 QVariant Qt5AccessibleWidget::minimumValue() const
1042 {
1043 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1044 if (!xAc.is())
1045 return QVariant();
1046
1047 Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
1048 if (!xValue.is())
1049 return QVariant();
1050 double aDouble = 0;
1051 xValue->getMinimumValue() >>= aDouble;
1052 return QVariant(aDouble);
1053 }
setCurrentValue(const QVariant & value)1054 void Qt5AccessibleWidget::setCurrentValue(const QVariant& value)
1055 {
1056 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1057 if (!xAc.is())
1058 return;
1059
1060 Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
1061 if (!xValue.is())
1062 return;
1063 xValue->setCurrentValue(Any(value.toDouble()));
1064 }
1065
1066 // QAccessibleTable
caption() const1067 QAccessibleInterface* Qt5AccessibleWidget::caption() const
1068 {
1069 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1070 if (!xAc.is())
1071 return nullptr;
1072
1073 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1074 if (!xTable.is())
1075 return nullptr;
1076 return QAccessible::queryAccessibleInterface(
1077 new Qt5XAccessible(xTable->getAccessibleCaption()));
1078 }
1079
cellAt(int row,int column) const1080 QAccessibleInterface* Qt5AccessibleWidget::cellAt(int row, int column) const
1081 {
1082 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1083 if (!xAc.is())
1084 return nullptr;
1085
1086 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1087 if (!xTable.is())
1088 return nullptr;
1089 return QAccessible::queryAccessibleInterface(
1090 new Qt5XAccessible(xTable->getAccessibleCellAt(row, column)));
1091 }
1092
columnCount() const1093 int Qt5AccessibleWidget::columnCount() const
1094 {
1095 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1096 if (!xAc.is())
1097 return 0;
1098
1099 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1100 if (!xTable.is())
1101 return 0;
1102 return xTable->getAccessibleColumnCount();
1103 }
1104
columnDescription(int column) const1105 QString Qt5AccessibleWidget::columnDescription(int column) const
1106 {
1107 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1108 if (!xAc.is())
1109 return QString();
1110
1111 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1112 if (!xTable.is())
1113 return QString();
1114 return toQString(xTable->getAccessibleColumnDescription(column));
1115 }
1116
isColumnSelected(int) const1117 bool Qt5AccessibleWidget::isColumnSelected(int /* column */) const { return true; }
1118
isRowSelected(int) const1119 bool Qt5AccessibleWidget::isRowSelected(int /* row */) const { return true; }
1120
modelChange(QAccessibleTableModelChangeEvent *)1121 void Qt5AccessibleWidget::modelChange(QAccessibleTableModelChangeEvent*) {}
1122
rowCount() const1123 int Qt5AccessibleWidget::rowCount() const
1124 {
1125 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1126 if (!xAc.is())
1127 return 0;
1128
1129 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1130 if (!xTable.is())
1131 return 0;
1132 return xTable->getAccessibleRowCount();
1133 }
1134
rowDescription(int row) const1135 QString Qt5AccessibleWidget::rowDescription(int row) const
1136 {
1137 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1138 if (!xAc.is())
1139 return QString();
1140
1141 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1142 if (!xTable.is())
1143 return QString();
1144 return toQString(xTable->getAccessibleRowDescription(row));
1145 }
1146
selectColumn(int column)1147 bool Qt5AccessibleWidget::selectColumn(int column)
1148 {
1149 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1150 if (!xAc.is())
1151 return false;
1152
1153 Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY);
1154 if (!xTableSelection.is())
1155 return false;
1156 return xTableSelection->selectColumn(column);
1157 }
1158
selectRow(int row)1159 bool Qt5AccessibleWidget::selectRow(int row)
1160 {
1161 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1162 if (!xAc.is())
1163 return false;
1164
1165 Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY);
1166 if (!xTableSelection.is())
1167 return false;
1168 return xTableSelection->selectRow(row);
1169 }
1170
selectedCellCount() const1171 int Qt5AccessibleWidget::selectedCellCount() const
1172 {
1173 SAL_INFO("vcl.qt5", "Unsupported QAccessibleTableInterface::selectedCellCount");
1174 return 0;
1175 }
1176
selectedCells() const1177 QList<QAccessibleInterface*> Qt5AccessibleWidget::selectedCells() const
1178 {
1179 SAL_INFO("vcl.qt5", "Unsupported QAccessibleTableInterface::selectedCells");
1180 return QList<QAccessibleInterface*>();
1181 }
1182
selectedColumnCount() const1183 int Qt5AccessibleWidget::selectedColumnCount() const
1184 {
1185 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1186 if (!xAc.is())
1187 return 0;
1188
1189 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1190 if (!xTable.is())
1191 return 0;
1192 return xTable->getSelectedAccessibleColumns().getLength();
1193 }
1194
selectedColumns() const1195 QList<int> Qt5AccessibleWidget::selectedColumns() const
1196 {
1197 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1198 if (!xAc.is())
1199 return QList<int>();
1200
1201 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1202 if (!xTable.is())
1203 return QList<int>();
1204 return toQList(xTable->getSelectedAccessibleColumns());
1205 }
1206
selectedRowCount() const1207 int Qt5AccessibleWidget::selectedRowCount() const
1208 {
1209 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1210 if (!xAc.is())
1211 return 0;
1212
1213 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1214 if (!xTable.is())
1215 return 0;
1216 return xTable->getSelectedAccessibleRows().getLength();
1217 }
1218
selectedRows() const1219 QList<int> Qt5AccessibleWidget::selectedRows() const
1220 {
1221 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1222 if (!xAc.is())
1223 return QList<int>();
1224
1225 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1226 if (!xTable.is())
1227 return QList<int>();
1228 return toQList(xTable->getSelectedAccessibleRows());
1229 }
1230
summary() const1231 QAccessibleInterface* Qt5AccessibleWidget::summary() const
1232 {
1233 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1234 if (!xAc.is())
1235 return nullptr;
1236
1237 Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
1238 if (!xTable.is())
1239 return nullptr;
1240 return QAccessible::queryAccessibleInterface(
1241 new Qt5XAccessible(xTable->getAccessibleSummary()));
1242 }
1243
unselectColumn(int column)1244 bool Qt5AccessibleWidget::unselectColumn(int column)
1245 {
1246 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1247 if (!xAc.is())
1248 return false;
1249
1250 Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY);
1251 if (!xTableSelection.is())
1252 return false;
1253 return xTableSelection->unselectColumn(column);
1254 }
1255
unselectRow(int row)1256 bool Qt5AccessibleWidget::unselectRow(int row)
1257 {
1258 Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
1259 if (!xAc.is())
1260 return false;
1261
1262 Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY);
1263 if (!xTableSelection.is())
1264 return false;
1265 return xTableSelection->unselectRow(row);
1266 }
1267
1268 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1269