193207c5ab
I think I managed to disable this when I converted it to use the shared plugin infrastructure. So fix that, and then make it much smarter to avoid various false positives. Change-Id: I0a4657cff3b40a00434924bf764d024dbfd7d5b3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176646 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
1950 lines
64 KiB
C++
1950 lines
64 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <QtAccessibleWidget.hxx>
|
|
|
|
#include <QtGui/QAccessibleInterface>
|
|
|
|
#include <QtAccessibleEventListener.hxx>
|
|
#include <QtAccessibleRegistry.hxx>
|
|
#include <QtFrame.hxx>
|
|
#include <QtTools.hxx>
|
|
#include <QtWidget.hxx>
|
|
#include <QtXAccessible.hxx>
|
|
|
|
#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
|
|
#include <com/sun/star/accessibility/AccessibleRole.hpp>
|
|
#include <com/sun/star/accessibility/AccessibleScrollType.hpp>
|
|
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
|
|
#include <com/sun/star/accessibility/AccessibleTextType.hpp>
|
|
#include <com/sun/star/accessibility/XAccessible.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleAction.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleContext.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleContext2.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleExtendedAttributes.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleKeyBinding.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleTable.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleTableSelection.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleText.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleValue.hpp>
|
|
#include <com/sun/star/beans/PropertyValue.hpp>
|
|
#include <com/sun/star/lang/DisposedException.hpp>
|
|
#include <com/sun/star/uno/Sequence.hxx>
|
|
|
|
#include <comphelper/AccessibleImplementationHelper.hxx>
|
|
#include <o3tl/any.hxx>
|
|
#include <sal/log.hxx>
|
|
#include <vcl/accessibility/AccessibleTextAttributeHelper.hxx>
|
|
#include <vcl/qt/QtUtils.hxx>
|
|
|
|
using namespace css;
|
|
using namespace css::accessibility;
|
|
using namespace css::uno;
|
|
|
|
QtAccessibleWidget::QtAccessibleWidget(const Reference<XAccessible>& xAccessible, QObject* pObject)
|
|
: m_xAccessible(xAccessible)
|
|
, m_pObject(pObject)
|
|
{
|
|
Reference<XAccessibleContext> xContext = xAccessible->getAccessibleContext();
|
|
Reference<XAccessibleEventBroadcaster> xBroadcaster(xContext, UNO_QUERY);
|
|
if (xBroadcaster.is())
|
|
{
|
|
Reference<XAccessibleEventListener> xListener(new QtAccessibleEventListener(this));
|
|
xBroadcaster->addAccessibleEventListener(xListener);
|
|
}
|
|
}
|
|
|
|
void QtAccessibleWidget::invalidate()
|
|
{
|
|
QtAccessibleRegistry::remove(m_xAccessible);
|
|
m_xAccessible.clear();
|
|
}
|
|
|
|
Reference<XAccessibleContext> QtAccessibleWidget::getAccessibleContextImpl() const
|
|
{
|
|
Reference<XAccessibleContext> xAc;
|
|
|
|
if (m_xAccessible.is())
|
|
{
|
|
try
|
|
{
|
|
xAc = m_xAccessible->getAccessibleContext();
|
|
}
|
|
catch (css::lang::DisposedException /*ex*/)
|
|
{
|
|
SAL_WARN("vcl.qt", "Accessible context disposed already");
|
|
}
|
|
// sometimes getAccessibleContext throws also RuntimeException if context is no longer alive
|
|
catch (css::uno::RuntimeException /*ex*/)
|
|
{
|
|
// so let's catch it here, cuz otherwise soffice falls flat on its face
|
|
// with FatalError and nothing else
|
|
SAL_WARN("vcl.qt", "Accessible context no longer alive");
|
|
}
|
|
}
|
|
|
|
return xAc;
|
|
}
|
|
|
|
css::uno::Reference<css::accessibility::XAccessibleTable>
|
|
QtAccessibleWidget::getAccessibleTableForParent() const
|
|
{
|
|
Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
|
|
if (!xAcc.is())
|
|
return nullptr;
|
|
|
|
Reference<XAccessible> xParent = xAcc->getAccessibleParent();
|
|
if (!xParent.is())
|
|
return nullptr;
|
|
|
|
Reference<XAccessibleContext> xParentContext = xParent->getAccessibleContext();
|
|
if (!xParentContext.is())
|
|
return nullptr;
|
|
|
|
return Reference<XAccessibleTable>(xParentContext, UNO_QUERY);
|
|
}
|
|
|
|
QWindow* QtAccessibleWidget::window() const
|
|
{
|
|
assert(m_pObject);
|
|
if (m_pObject->isWidgetType())
|
|
{
|
|
QWidget* pWidget = static_cast<QWidget*>(m_pObject);
|
|
QWidget* pWindow = pWidget->window();
|
|
if (pWindow)
|
|
return pWindow->windowHandle();
|
|
}
|
|
|
|
QAccessibleInterface* pParent = parent();
|
|
if (pParent)
|
|
return pParent->window();
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
int QtAccessibleWidget::childCount() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return 0;
|
|
|
|
sal_Int64 nChildCount = xAc->getAccessibleChildCount();
|
|
if (nChildCount > std::numeric_limits<int>::max())
|
|
{
|
|
SAL_WARN("vcl.qt", "QtAccessibleWidget::childCount: Child count exceeds maximum int value, "
|
|
"returning max int.");
|
|
nChildCount = std::numeric_limits<int>::max();
|
|
}
|
|
|
|
return nChildCount;
|
|
}
|
|
|
|
int QtAccessibleWidget::indexOfChild(const QAccessibleInterface* pChild) const
|
|
{
|
|
const QtAccessibleWidget* pAccessibleWidget = dynamic_cast<const QtAccessibleWidget*>(pChild);
|
|
if (!pAccessibleWidget)
|
|
{
|
|
SAL_WARN(
|
|
"vcl.qt",
|
|
"QtAccessibleWidget::indexOfChild called with child that is no QtAccessibleWidget");
|
|
return -1;
|
|
}
|
|
|
|
Reference<XAccessibleContext> xContext = pAccessibleWidget->getAccessibleContextImpl();
|
|
if (!xContext.is())
|
|
return -1;
|
|
|
|
sal_Int64 nChildIndex = xContext->getAccessibleIndexInParent();
|
|
if (nChildIndex > std::numeric_limits<int>::max())
|
|
{
|
|
// use -2 when the child index is too large to fit into 32 bit to neither use the
|
|
// valid index of another child nor -1, which would e.g. make the Orca screen reader
|
|
// interpret the object as being a zombie
|
|
SAL_WARN("vcl.qt",
|
|
"QtAccessibleWidget::indexOfChild: Child index exceeds maximum int value, "
|
|
"returning -2.");
|
|
nChildIndex = -2;
|
|
}
|
|
return nChildIndex;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
sal_Int16 lcl_matchQtTextBoundaryType(QAccessible::TextBoundaryType boundaryType)
|
|
{
|
|
switch (boundaryType)
|
|
{
|
|
case QAccessible::CharBoundary:
|
|
return css::accessibility::AccessibleTextType::CHARACTER;
|
|
case QAccessible::WordBoundary:
|
|
return css::accessibility::AccessibleTextType::WORD;
|
|
case QAccessible::SentenceBoundary:
|
|
return css::accessibility::AccessibleTextType::SENTENCE;
|
|
case QAccessible::ParagraphBoundary:
|
|
return css::accessibility::AccessibleTextType::PARAGRAPH;
|
|
case QAccessible::LineBoundary:
|
|
return css::accessibility::AccessibleTextType::LINE;
|
|
case QAccessible::NoBoundary:
|
|
// assert here, better handle it directly at call site
|
|
assert(false
|
|
&& "No match for QAccessible::NoBoundary, handle it separately at call site.");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
SAL_WARN("vcl.qt", "Unmatched text boundary type: " << boundaryType);
|
|
return -1;
|
|
}
|
|
|
|
QAccessible::Relation lcl_matchUnoRelation(AccessibleRelationType eRelationType)
|
|
{
|
|
// Qt semantics is the other way around
|
|
switch (eRelationType)
|
|
{
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
|
|
case AccessibleRelationType_CONTENT_FLOWS_FROM:
|
|
return QAccessible::FlowsTo;
|
|
case AccessibleRelationType_CONTENT_FLOWS_TO:
|
|
return QAccessible::FlowsFrom;
|
|
#endif
|
|
case AccessibleRelationType_CONTROLLED_BY:
|
|
return QAccessible::Controller;
|
|
case AccessibleRelationType_CONTROLLER_FOR:
|
|
return QAccessible::Controlled;
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
|
|
case AccessibleRelationType_DESCRIBED_BY:
|
|
return QAccessible::DescriptionFor;
|
|
#endif
|
|
case AccessibleRelationType_LABELED_BY:
|
|
return QAccessible::Label;
|
|
case AccessibleRelationType_LABEL_FOR:
|
|
return QAccessible::Labelled;
|
|
case AccessibleRelationType_INVALID:
|
|
case AccessibleRelationType_MEMBER_OF:
|
|
case AccessibleRelationType_SUB_WINDOW_OF:
|
|
case AccessibleRelationType_NODE_CHILD_OF:
|
|
default:
|
|
SAL_WARN("vcl.qt", "Unmatched relation: " << static_cast<int>(eRelationType));
|
|
return {};
|
|
}
|
|
}
|
|
|
|
void lcl_appendRelation(QVector<QPair<QAccessibleInterface*, QAccessible::Relation>>* relations,
|
|
AccessibleRelation aRelation, QAccessible::Relation match)
|
|
{
|
|
QAccessible::Relation aQRelation = lcl_matchUnoRelation(aRelation.RelationType);
|
|
// skip in case there's no Qt relation matching the filter
|
|
if (!(aQRelation & match))
|
|
return;
|
|
|
|
sal_uInt32 nTargetCount = aRelation.TargetSet.getLength();
|
|
|
|
for (sal_uInt32 i = 0; i < nTargetCount; i++)
|
|
{
|
|
Reference<XAccessible> xAccessible = aRelation.TargetSet[i];
|
|
relations->append(
|
|
{ QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xAccessible)),
|
|
aQRelation });
|
|
}
|
|
}
|
|
}
|
|
|
|
QVector<QPair<QAccessibleInterface*, QAccessible::Relation>>
|
|
QtAccessibleWidget::relations(QAccessible::Relation match) const
|
|
{
|
|
QVector<QPair<QAccessibleInterface*, QAccessible::Relation>> relations;
|
|
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return relations;
|
|
|
|
Reference<XAccessibleRelationSet> xRelationSet = xAc->getAccessibleRelationSet();
|
|
if (xRelationSet.is())
|
|
{
|
|
int count = xRelationSet->getRelationCount();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
AccessibleRelation aRelation = xRelationSet->getRelation(i);
|
|
lcl_appendRelation(&relations, aRelation, match);
|
|
}
|
|
}
|
|
|
|
return relations;
|
|
}
|
|
|
|
QAccessibleInterface* QtAccessibleWidget::focusChild() const
|
|
{
|
|
/* if (m_pWindow->HasChildPathFocus())
|
|
return QAccessible::queryAccessibleInterface(
|
|
new QtXAccessible(m_xAccessible->getAccessibleContext()->getAccessibleChild(index))); */
|
|
return QAccessible::queryAccessibleInterface(object());
|
|
}
|
|
|
|
QRect QtAccessibleWidget::rect() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return QRect();
|
|
|
|
Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY);
|
|
awt::Point aPoint = xAccessibleComponent->getLocationOnScreen();
|
|
awt::Size aSize = xAccessibleComponent->getSize();
|
|
|
|
return QRect(aPoint.X, aPoint.Y, aSize.Width, aSize.Height);
|
|
}
|
|
|
|
QAccessibleInterface* QtAccessibleWidget::parent() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return nullptr;
|
|
|
|
if (xAc->getAccessibleParent().is())
|
|
return QAccessible::queryAccessibleInterface(
|
|
QtAccessibleRegistry::getQObject(xAc->getAccessibleParent()));
|
|
|
|
// go via the QObject hierarchy; some a11y objects like the application
|
|
// (at the root of the a11y hierarchy) are handled solely by Qt and have
|
|
// no LO-internal a11y objects associated with them
|
|
QObject* pObj = object();
|
|
if (pObj && pObj->parent())
|
|
return QAccessible::queryAccessibleInterface(pObj->parent());
|
|
|
|
// return app as parent for top-level objects
|
|
return QAccessible::queryAccessibleInterface(qApp);
|
|
}
|
|
|
|
QAccessibleInterface* QtAccessibleWidget::child(int index) const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return nullptr;
|
|
|
|
if (index < 0 || index >= xAc->getAccessibleChildCount())
|
|
{
|
|
SAL_WARN("vcl.qt", "QtAccessibleWidget::child called with invalid index: " << index);
|
|
return nullptr;
|
|
}
|
|
|
|
return QAccessible::queryAccessibleInterface(
|
|
QtAccessibleRegistry::getQObject(xAc->getAccessibleChild(index)));
|
|
}
|
|
|
|
QString QtAccessibleWidget::text(QAccessible::Text text) const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return QString();
|
|
|
|
switch (text)
|
|
{
|
|
case QAccessible::Name:
|
|
return toQString(xAc->getAccessibleName());
|
|
case QAccessible::Description:
|
|
case QAccessible::DebugDescription:
|
|
return toQString(xAc->getAccessibleDescription());
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
|
|
case QAccessible::Identifier:
|
|
{
|
|
Reference<XAccessibleContext2> xContext(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (!xContext.is())
|
|
return QString();
|
|
return toQString(xContext->getAccessibleId());
|
|
}
|
|
#endif
|
|
case QAccessible::Value:
|
|
case QAccessible::Help:
|
|
case QAccessible::Accelerator:
|
|
case QAccessible::UserText:
|
|
default:
|
|
return QString();
|
|
}
|
|
}
|
|
QAccessible::Role QtAccessibleWidget::role() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return QAccessible::NoRole;
|
|
|
|
switch (xAc->getAccessibleRole())
|
|
{
|
|
case AccessibleRole::UNKNOWN:
|
|
return QAccessible::NoRole;
|
|
case AccessibleRole::ALERT:
|
|
return QAccessible::AlertMessage;
|
|
case AccessibleRole::BLOCK_QUOTE:
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
|
|
return QAccessible::BlockQuote;
|
|
#else
|
|
return QAccessible::Paragraph;
|
|
#endif
|
|
case AccessibleRole::COLUMN_HEADER:
|
|
return QAccessible::ColumnHeader;
|
|
case AccessibleRole::CANVAS:
|
|
return QAccessible::Canvas;
|
|
case AccessibleRole::CHECK_BOX:
|
|
return QAccessible::CheckBox;
|
|
case AccessibleRole::CHECK_MENU_ITEM:
|
|
return QAccessible::MenuItem;
|
|
case AccessibleRole::COLOR_CHOOSER:
|
|
return QAccessible::ColorChooser;
|
|
case AccessibleRole::COMBO_BOX:
|
|
return QAccessible::ComboBox;
|
|
case AccessibleRole::DATE_EDITOR:
|
|
return QAccessible::EditableText;
|
|
case AccessibleRole::DESKTOP_ICON:
|
|
return QAccessible::Graphic;
|
|
case AccessibleRole::DESKTOP_PANE:
|
|
case AccessibleRole::DIRECTORY_PANE:
|
|
return QAccessible::Pane;
|
|
case AccessibleRole::DIALOG:
|
|
return QAccessible::Dialog;
|
|
case AccessibleRole::DOCUMENT:
|
|
return QAccessible::Document;
|
|
case AccessibleRole::EMBEDDED_OBJECT:
|
|
return QAccessible::UserRole;
|
|
case AccessibleRole::END_NOTE:
|
|
return QAccessible::Note;
|
|
case AccessibleRole::FILE_CHOOSER:
|
|
return QAccessible::Dialog;
|
|
case AccessibleRole::FILLER:
|
|
return QAccessible::Whitespace;
|
|
case AccessibleRole::FONT_CHOOSER:
|
|
return QAccessible::UserRole;
|
|
case AccessibleRole::FOOTER:
|
|
return QAccessible::Footer;
|
|
case AccessibleRole::FOOTNOTE:
|
|
return QAccessible::Note;
|
|
case AccessibleRole::FRAME:
|
|
// report Pane instead of Window role for a frame that's not actually
|
|
// an accessible frame (top-level window with title bar) itself,
|
|
// but a child of the real top-level
|
|
if (QAccessibleInterface* pParent = parent())
|
|
{
|
|
const QAccessible::Role eParentRole = pParent->role();
|
|
if (eParentRole == QAccessible::Window || eParentRole == QAccessible::Dialog)
|
|
return QAccessible::Pane;
|
|
}
|
|
return QAccessible::Window;
|
|
case AccessibleRole::GLASS_PANE:
|
|
return QAccessible::UserRole;
|
|
case AccessibleRole::GRAPHIC:
|
|
return QAccessible::Graphic;
|
|
case AccessibleRole::GROUP_BOX:
|
|
return QAccessible::Grouping;
|
|
case AccessibleRole::HEADER:
|
|
return QAccessible::UserRole;
|
|
case AccessibleRole::HEADING:
|
|
return QAccessible::Heading;
|
|
case AccessibleRole::HYPER_LINK:
|
|
return QAccessible::Link;
|
|
case AccessibleRole::ICON:
|
|
return QAccessible::Graphic;
|
|
case AccessibleRole::INTERNAL_FRAME:
|
|
return QAccessible::UserRole;
|
|
case AccessibleRole::LABEL:
|
|
return QAccessible::StaticText;
|
|
case AccessibleRole::LAYERED_PANE:
|
|
return QAccessible::Pane;
|
|
case AccessibleRole::LIST:
|
|
return QAccessible::List;
|
|
case AccessibleRole::LIST_ITEM:
|
|
return QAccessible::ListItem;
|
|
case AccessibleRole::MENU:
|
|
case AccessibleRole::MENU_BAR:
|
|
return QAccessible::MenuBar;
|
|
case AccessibleRole::MENU_ITEM:
|
|
return QAccessible::MenuItem;
|
|
case AccessibleRole::NOTIFICATION:
|
|
return QAccessible::Notification;
|
|
case AccessibleRole::OPTION_PANE:
|
|
return QAccessible::Pane;
|
|
case AccessibleRole::PAGE_TAB:
|
|
return QAccessible::PageTab;
|
|
case AccessibleRole::PAGE_TAB_LIST:
|
|
return QAccessible::PageTabList;
|
|
case AccessibleRole::PANEL:
|
|
return QAccessible::Pane;
|
|
case AccessibleRole::PARAGRAPH:
|
|
return QAccessible::Paragraph;
|
|
case AccessibleRole::PASSWORD_TEXT:
|
|
// Qt API doesn't have a separate role to distinguish password edits,
|
|
// but a 'passwordEdit' state
|
|
return QAccessible::EditableText;
|
|
case AccessibleRole::POPUP_MENU:
|
|
return QAccessible::PopupMenu;
|
|
case AccessibleRole::PUSH_BUTTON:
|
|
return QAccessible::Button;
|
|
case AccessibleRole::PROGRESS_BAR:
|
|
return QAccessible::ProgressBar;
|
|
case AccessibleRole::RADIO_BUTTON:
|
|
return QAccessible::RadioButton;
|
|
case AccessibleRole::RADIO_MENU_ITEM:
|
|
return QAccessible::MenuItem;
|
|
case AccessibleRole::ROW_HEADER:
|
|
return QAccessible::RowHeader;
|
|
case AccessibleRole::ROOT_PANE:
|
|
return QAccessible::Pane;
|
|
case AccessibleRole::SCROLL_BAR:
|
|
return QAccessible::ScrollBar;
|
|
case AccessibleRole::SCROLL_PANE:
|
|
return QAccessible::Pane;
|
|
case AccessibleRole::SHAPE:
|
|
return QAccessible::Graphic;
|
|
case AccessibleRole::SEPARATOR:
|
|
return QAccessible::Separator;
|
|
case AccessibleRole::SLIDER:
|
|
return QAccessible::Slider;
|
|
case AccessibleRole::SPIN_BOX:
|
|
return QAccessible::SpinBox;
|
|
case AccessibleRole::SPLIT_PANE:
|
|
return QAccessible::Pane;
|
|
case AccessibleRole::STATUS_BAR:
|
|
return QAccessible::StatusBar;
|
|
case AccessibleRole::TABLE:
|
|
return QAccessible::Table;
|
|
case AccessibleRole::TABLE_CELL:
|
|
return QAccessible::Cell;
|
|
case AccessibleRole::TEXT:
|
|
return QAccessible::EditableText;
|
|
case AccessibleRole::TEXT_FRAME:
|
|
return QAccessible::Pane;
|
|
case AccessibleRole::TOGGLE_BUTTON:
|
|
return QAccessible::Button;
|
|
case AccessibleRole::TOOL_BAR:
|
|
return QAccessible::ToolBar;
|
|
case AccessibleRole::TOOL_TIP:
|
|
return QAccessible::ToolTip;
|
|
case AccessibleRole::TREE:
|
|
return QAccessible::Tree;
|
|
case AccessibleRole::VIEW_PORT:
|
|
return QAccessible::UserRole;
|
|
case AccessibleRole::BUTTON_DROPDOWN:
|
|
return QAccessible::ButtonDropDown;
|
|
case AccessibleRole::BUTTON_MENU:
|
|
return QAccessible::ButtonMenu;
|
|
case AccessibleRole::CAPTION:
|
|
return QAccessible::StaticText;
|
|
case AccessibleRole::CHART:
|
|
return QAccessible::Chart;
|
|
case AccessibleRole::EDIT_BAR:
|
|
return QAccessible::Equation;
|
|
case AccessibleRole::FORM:
|
|
return QAccessible::Form;
|
|
case AccessibleRole::IMAGE_MAP:
|
|
return QAccessible::Graphic;
|
|
case AccessibleRole::NOTE:
|
|
return QAccessible::Note;
|
|
case AccessibleRole::RULER:
|
|
return QAccessible::UserRole;
|
|
case AccessibleRole::SECTION:
|
|
return QAccessible::Section;
|
|
case AccessibleRole::TREE_ITEM:
|
|
return QAccessible::TreeItem;
|
|
case AccessibleRole::TREE_TABLE:
|
|
return QAccessible::Tree;
|
|
case AccessibleRole::COMMENT:
|
|
return QAccessible::Note;
|
|
case AccessibleRole::COMMENT_END:
|
|
return QAccessible::UserRole;
|
|
case AccessibleRole::DOCUMENT_PRESENTATION:
|
|
return QAccessible::Document;
|
|
case AccessibleRole::DOCUMENT_SPREADSHEET:
|
|
return QAccessible::Document;
|
|
case AccessibleRole::DOCUMENT_TEXT:
|
|
return QAccessible::Document;
|
|
case AccessibleRole::STATIC:
|
|
return QAccessible::StaticText;
|
|
case AccessibleRole::WINDOW: // top-level window without title bar
|
|
return QAccessible::Window;
|
|
}
|
|
|
|
SAL_WARN("vcl.qt", "Unmapped role: " << getAccessibleContextImpl()->getAccessibleRole());
|
|
return QAccessible::NoRole;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
void lcl_addState(QAccessible::State* state, sal_Int64 nState)
|
|
{
|
|
switch (nState)
|
|
{
|
|
case AccessibleStateType::INVALID:
|
|
state->invalid = true;
|
|
break;
|
|
case AccessibleStateType::ACTIVE:
|
|
state->active = true;
|
|
break;
|
|
case AccessibleStateType::ARMED:
|
|
// No match
|
|
break;
|
|
case AccessibleStateType::BUSY:
|
|
state->busy = true;
|
|
break;
|
|
case AccessibleStateType::CHECKABLE:
|
|
state->checkable = true;
|
|
break;
|
|
case AccessibleStateType::CHECKED:
|
|
state->checked = true;
|
|
break;
|
|
case AccessibleStateType::EDITABLE:
|
|
state->editable = true;
|
|
break;
|
|
case AccessibleStateType::ENABLED:
|
|
state->disabled = false;
|
|
break;
|
|
case AccessibleStateType::EXPANDABLE:
|
|
state->expandable = true;
|
|
break;
|
|
case AccessibleStateType::EXPANDED:
|
|
state->expanded = true;
|
|
break;
|
|
case AccessibleStateType::FOCUSABLE:
|
|
state->focusable = true;
|
|
break;
|
|
case AccessibleStateType::FOCUSED:
|
|
state->focused = true;
|
|
break;
|
|
case AccessibleStateType::HORIZONTAL:
|
|
// No match
|
|
break;
|
|
case AccessibleStateType::ICONIFIED:
|
|
// No match
|
|
break;
|
|
case AccessibleStateType::INDETERMINATE:
|
|
state->checkStateMixed = true;
|
|
break;
|
|
case AccessibleStateType::MANAGES_DESCENDANTS:
|
|
// No match
|
|
break;
|
|
case AccessibleStateType::MODAL:
|
|
state->modal = true;
|
|
break;
|
|
case AccessibleStateType::MOVEABLE:
|
|
state->movable = true;
|
|
break;
|
|
case AccessibleStateType::MULTI_LINE:
|
|
state->multiLine = true;
|
|
break;
|
|
case AccessibleStateType::OPAQUE:
|
|
// No match
|
|
break;
|
|
case AccessibleStateType::PRESSED:
|
|
state->pressed = true;
|
|
break;
|
|
case AccessibleStateType::RESIZABLE:
|
|
state->sizeable = true;
|
|
break;
|
|
case AccessibleStateType::SELECTABLE:
|
|
state->selectable = true;
|
|
break;
|
|
case AccessibleStateType::SELECTED:
|
|
state->selected = true;
|
|
break;
|
|
case AccessibleStateType::SENSITIVE:
|
|
// No match
|
|
break;
|
|
case AccessibleStateType::SHOWING:
|
|
// No match
|
|
break;
|
|
case AccessibleStateType::SINGLE_LINE:
|
|
// No match
|
|
break;
|
|
case AccessibleStateType::STALE:
|
|
// No match
|
|
break;
|
|
case AccessibleStateType::TRANSIENT:
|
|
// No match
|
|
break;
|
|
case AccessibleStateType::VERTICAL:
|
|
// No match
|
|
break;
|
|
case AccessibleStateType::VISIBLE:
|
|
state->invisible = false;
|
|
break;
|
|
case AccessibleStateType::DEFAULT:
|
|
// No match
|
|
break;
|
|
case AccessibleStateType::DEFUNC:
|
|
state->invalid = true;
|
|
break;
|
|
case AccessibleStateType::MULTI_SELECTABLE:
|
|
state->multiSelectable = true;
|
|
break;
|
|
default:
|
|
SAL_WARN("vcl.qt", "Unmapped state: " << nState);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
QAccessible::State QtAccessibleWidget::state() const
|
|
{
|
|
QAccessible::State state;
|
|
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return state;
|
|
|
|
sal_Int64 nStateSet(xAc->getAccessibleStateSet());
|
|
|
|
for (int i = 0; i < 63; ++i)
|
|
{
|
|
sal_Int64 nState = sal_Int64(1) << i;
|
|
if (nStateSet & nState)
|
|
lcl_addState(&state, nState);
|
|
}
|
|
|
|
if (xAc->getAccessibleRole() == AccessibleRole::PASSWORD_TEXT)
|
|
state.passwordEdit = true;
|
|
|
|
return state;
|
|
}
|
|
|
|
QColor QtAccessibleWidget::foregroundColor() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return QColor();
|
|
|
|
Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY);
|
|
return toQColor(Color(ColorTransparency, xAccessibleComponent->getForeground()));
|
|
}
|
|
|
|
QColor QtAccessibleWidget::backgroundColor() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return QColor();
|
|
|
|
Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY);
|
|
return toQColor(Color(ColorTransparency, xAccessibleComponent->getBackground()));
|
|
}
|
|
|
|
void* QtAccessibleWidget::interface_cast(QAccessible::InterfaceType t)
|
|
{
|
|
if (t == QAccessible::ActionInterface && accessibleProvidesInterface<XAccessibleAction>())
|
|
return static_cast<QAccessibleActionInterface*>(this);
|
|
if (t == QAccessible::TextInterface && accessibleProvidesInterface<XAccessibleText>())
|
|
return static_cast<QAccessibleTextInterface*>(this);
|
|
if (t == QAccessible::EditableTextInterface
|
|
&& accessibleProvidesInterface<XAccessibleEditableText>())
|
|
return static_cast<QAccessibleEditableTextInterface*>(this);
|
|
if (t == QAccessible::ValueInterface && accessibleProvidesInterface<XAccessibleValue>())
|
|
return static_cast<QAccessibleValueInterface*>(this);
|
|
if (t == QAccessible::TableCellInterface)
|
|
{
|
|
// parent must be a table
|
|
Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
|
|
if (xTable.is())
|
|
return static_cast<QAccessibleTableCellInterface*>(this);
|
|
}
|
|
if (t == QAccessible::TableInterface && accessibleProvidesInterface<XAccessibleTable>())
|
|
return static_cast<QAccessibleTableInterface*>(this);
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
|
if (t == QAccessible::SelectionInterface && accessibleProvidesInterface<XAccessibleSelection>())
|
|
return static_cast<QAccessibleSelectionInterface*>(this);
|
|
#endif
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
|
|
if (t == QAccessible::AttributesInterface)
|
|
return static_cast<QAccessibleAttributesInterface*>(this);
|
|
#endif
|
|
return nullptr;
|
|
}
|
|
|
|
bool QtAccessibleWidget::isValid() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
return xAc.is();
|
|
}
|
|
|
|
QObject* QtAccessibleWidget::object() const { return m_pObject; }
|
|
|
|
void QtAccessibleWidget::setText(QAccessible::Text /* t */, const QString& /* text */) {}
|
|
|
|
QAccessibleInterface* QtAccessibleWidget::childAt(int x, int y) const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return nullptr;
|
|
|
|
Reference<XAccessibleComponent> xAccessibleComponent(xAc, UNO_QUERY);
|
|
// convert from screen to local coordinates
|
|
QPoint aLocalCoords = QPoint(x, y) - rect().topLeft();
|
|
return QAccessible::queryAccessibleInterface(
|
|
QtAccessibleRegistry::getQObject(xAccessibleComponent->getAccessibleAtPoint(
|
|
awt::Point(aLocalCoords.x(), aLocalCoords.y()))));
|
|
}
|
|
|
|
QAccessibleInterface* QtAccessibleWidget::customFactory(const QString& classname, QObject* object)
|
|
{
|
|
if (classname == QLatin1String("QtWidget") && object && object->isWidgetType())
|
|
{
|
|
QtWidget* pWidget = static_cast<QtWidget*>(object);
|
|
vcl::Window* pWindow = pWidget->frame().GetWindow();
|
|
|
|
if (pWindow)
|
|
{
|
|
css::uno::Reference<XAccessible> xAcc = pWindow->GetAccessible();
|
|
// insert into registry so the association between the XAccessible and the QtWidget
|
|
// is remembered rather than creating a different QtXAccessible when a QObject is needed later
|
|
QtAccessibleRegistry::insert(xAcc, object);
|
|
return new QtAccessibleWidget(xAcc, object);
|
|
}
|
|
}
|
|
if (classname == QLatin1String("QtXAccessible") && object)
|
|
{
|
|
QtXAccessible* pXAccessible = static_cast<QtXAccessible*>(object);
|
|
if (pXAccessible->m_xAccessible.is())
|
|
{
|
|
QtAccessibleWidget* pRet = new QtAccessibleWidget(pXAccessible->m_xAccessible, object);
|
|
// clear the reference in the QtXAccessible, no longer needed now that the QtAccessibleWidget holds one
|
|
pXAccessible->m_xAccessible.clear();
|
|
return pRet;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
// QAccessibleActionInterface
|
|
QStringList QtAccessibleWidget::actionNames() const
|
|
{
|
|
QStringList actionNames;
|
|
Reference<XAccessibleAction> xAccessibleAction(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (!xAccessibleAction.is())
|
|
return actionNames;
|
|
|
|
int count = xAccessibleAction->getAccessibleActionCount();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
OUString desc = xAccessibleAction->getAccessibleActionDescription(i);
|
|
actionNames.append(toQString(desc));
|
|
}
|
|
return actionNames;
|
|
}
|
|
|
|
void QtAccessibleWidget::doAction(const QString& actionName)
|
|
{
|
|
Reference<XAccessibleAction> xAccessibleAction(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (!xAccessibleAction.is())
|
|
return;
|
|
|
|
int index = actionNames().indexOf(actionName);
|
|
if (index == -1)
|
|
return;
|
|
xAccessibleAction->doAccessibleAction(index);
|
|
}
|
|
|
|
QStringList QtAccessibleWidget::keyBindingsForAction(const QString& actionName) const
|
|
{
|
|
QStringList keyBindings;
|
|
Reference<XAccessibleAction> xAccessibleAction(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (!xAccessibleAction.is())
|
|
return keyBindings;
|
|
|
|
int index = actionNames().indexOf(actionName);
|
|
if (index == -1)
|
|
return keyBindings;
|
|
|
|
Reference<XAccessibleKeyBinding> xKeyBinding
|
|
= xAccessibleAction->getAccessibleActionKeyBinding(index);
|
|
|
|
if (!xKeyBinding.is())
|
|
return keyBindings;
|
|
|
|
int count = xKeyBinding->getAccessibleKeyBindingCount();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
Sequence<awt::KeyStroke> keyStroke = xKeyBinding->getAccessibleKeyBinding(i);
|
|
keyBindings.append(toQString(comphelper::GetkeyBindingStrByXkeyBinding(keyStroke)));
|
|
}
|
|
return keyBindings;
|
|
}
|
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
|
|
|
|
// QAccessibleAttributesInterface helpers
|
|
namespace
|
|
{
|
|
void lcl_insertAttribute(QHash<QAccessible::Attribute, QVariant>& rQtAttrs, const OUString& rName,
|
|
const OUString& rValue)
|
|
{
|
|
if (rName == u"level"_ustr)
|
|
{
|
|
rQtAttrs.insert(QAccessible::Attribute::Level,
|
|
QVariant::fromValue(static_cast<int>(rValue.toInt32())));
|
|
}
|
|
else
|
|
{
|
|
// for now, leave not explicitly handled attributes as they are and report
|
|
// via QAccessible::Attribute::Custom, but should consider suggesting to
|
|
// add more specific attributes on Qt side and use those instead
|
|
const QVariant aVariant = rQtAttrs.value(QAccessible::Attribute::Custom,
|
|
QVariant::fromValue(QHash<QString, QString>()));
|
|
assert((aVariant.canConvert<QHash<QString, QString>>()));
|
|
QHash<QString, QString> aAttrs = aVariant.value<QHash<QString, QString>>();
|
|
aAttrs.insert(toQString(rName), toQString(rValue));
|
|
rQtAttrs.insert(QAccessible::Attribute::Custom, QVariant::fromValue(aAttrs));
|
|
}
|
|
}
|
|
}
|
|
|
|
QHash<QAccessible::Attribute, QVariant> QtAccessibleWidget::attributes() const
|
|
{
|
|
Reference<XAccessibleContext> xContext = getAccessibleContextImpl();
|
|
if (!xContext.is())
|
|
return {};
|
|
|
|
Reference<XAccessibleExtendedAttributes> xAttributes(xContext, UNO_QUERY);
|
|
if (!xAttributes.is())
|
|
return {};
|
|
|
|
OUString sAttrs;
|
|
xAttributes->getExtendedAttributes() >>= sAttrs;
|
|
|
|
QHash<QAccessible::Attribute, QVariant> aQtAttrs;
|
|
sal_Int32 nIndex = 0;
|
|
do
|
|
{
|
|
const OUString sAttribute = sAttrs.getToken(0, ';', nIndex);
|
|
sal_Int32 nColonPos = 0;
|
|
const OUString sName = sAttribute.getToken(0, ':', nColonPos);
|
|
const OUString sValue = sAttribute.getToken(0, ':', nColonPos);
|
|
assert(nColonPos == -1
|
|
&& "Too many colons in attribute that should have \"name:value\" syntax");
|
|
if (!sName.isEmpty())
|
|
lcl_insertAttribute(aQtAttrs, sName, sValue);
|
|
} while (nIndex >= 0);
|
|
|
|
return aQtAttrs;
|
|
}
|
|
|
|
// QAccessibleAttributesInterface
|
|
QList<QAccessible::Attribute> QtAccessibleWidget::attributeKeys() const
|
|
{
|
|
const QHash<QAccessible::Attribute, QVariant> aAttributes = attributes();
|
|
return aAttributes.keys();
|
|
}
|
|
|
|
QVariant QtAccessibleWidget::attributeValue(QAccessible::Attribute eAttribute) const
|
|
{
|
|
const QHash<QAccessible::Attribute, QVariant> aAllAttributes = attributes();
|
|
return aAllAttributes.value(eAttribute);
|
|
}
|
|
#endif
|
|
|
|
// QAccessibleTextInterface
|
|
void QtAccessibleWidget::addSelection(int /* startOffset */, int /* endOffset */)
|
|
{
|
|
SAL_INFO("vcl.qt", "Unsupported QAccessibleTextInterface::addSelection");
|
|
}
|
|
|
|
// Text attributes are returned in format specified in IAccessible2 spec, since that
|
|
// is what Qt handles:
|
|
// https://wiki.linuxfoundation.org/accessibility/iaccessible2/textattributes
|
|
QString QtAccessibleWidget::attributes(int offset, int* startOffset, int* endOffset) const
|
|
{
|
|
if (startOffset == nullptr || endOffset == nullptr)
|
|
return QString();
|
|
|
|
*startOffset = -1;
|
|
*endOffset = -1;
|
|
|
|
Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (!xText.is())
|
|
return QString();
|
|
|
|
// handle special values for offset the same way base class's QAccessibleTextWidget::attributes does
|
|
// (as defined in IAccessible 2: -1 -> length, -2 -> cursor position)
|
|
if (offset == -2)
|
|
offset = cursorPosition();
|
|
|
|
const int nTextLength = characterCount();
|
|
if (offset == -1 || offset == nTextLength)
|
|
offset = nTextLength - 1;
|
|
|
|
if (offset < 0 || offset > nTextLength)
|
|
{
|
|
SAL_WARN("vcl.qt", "QtAccessibleWidget::attributes called with invalid offset: " << offset);
|
|
return QString();
|
|
}
|
|
|
|
// Qt doesn't have the strict separation into text and object attributes, but also
|
|
// supports text-specific attributes that are object attributes according to the
|
|
// IAccessible2 spec.
|
|
sal_Int32 nStart = 0;
|
|
sal_Int32 nEnd = 0;
|
|
const OUString aRet = AccessibleTextAttributeHelper::GetIAccessible2TextAttributes(
|
|
xText, IA2AttributeType::TextAttributes | IA2AttributeType::ObjectAttributes,
|
|
static_cast<sal_Int32>(offset), nStart, nEnd);
|
|
*startOffset = static_cast<int>(nStart);
|
|
*endOffset = static_cast<int>(nEnd);
|
|
return toQString(aRet);
|
|
}
|
|
|
|
int QtAccessibleWidget::characterCount() const
|
|
{
|
|
Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (xText.is())
|
|
return xText->getCharacterCount();
|
|
return 0;
|
|
}
|
|
|
|
QRect QtAccessibleWidget::characterRect(int nOffset) const
|
|
{
|
|
Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (!xText.is())
|
|
return QRect();
|
|
|
|
if (nOffset < 0 || nOffset > xText->getCharacterCount())
|
|
{
|
|
SAL_WARN("vcl.qt",
|
|
"QtAccessibleWidget::characterRect called with invalid offset: " << nOffset);
|
|
return QRect();
|
|
}
|
|
|
|
const awt::Rectangle aBounds = xText->getCharacterBounds(nOffset);
|
|
const QRect aRect(aBounds.X, aBounds.Y, aBounds.Width, aBounds.Height);
|
|
// convert to screen coordinates
|
|
const QRect aScreenPos = rect();
|
|
return aRect.translated(aScreenPos.x(), aScreenPos.y());
|
|
}
|
|
|
|
int QtAccessibleWidget::cursorPosition() const
|
|
{
|
|
Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (xText.is())
|
|
return xText->getCaretPosition();
|
|
return 0;
|
|
}
|
|
|
|
int QtAccessibleWidget::offsetAtPoint(const QPoint& rPoint) const
|
|
{
|
|
Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (!xText.is())
|
|
return -1;
|
|
|
|
// convert from screen to local coordinates
|
|
QPoint aLocalCoords = rPoint - rect().topLeft();
|
|
awt::Point aPoint(aLocalCoords.x(), aLocalCoords.y());
|
|
return xText->getIndexAtPoint(aPoint);
|
|
}
|
|
|
|
void QtAccessibleWidget::removeSelection(int /* selectionIndex */)
|
|
{
|
|
SAL_INFO("vcl.qt", "Unsupported QAccessibleTextInterface::removeSelection");
|
|
}
|
|
|
|
void QtAccessibleWidget::scrollToSubstring(int startIndex, int endIndex)
|
|
{
|
|
Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (!xText.is())
|
|
return;
|
|
|
|
sal_Int32 nTextLength = xText->getCharacterCount();
|
|
if (startIndex < 0 || startIndex > nTextLength || endIndex < 0 || endIndex > nTextLength)
|
|
{
|
|
SAL_WARN("vcl.qt", "QtAccessibleWidget::scrollToSubstring called with invalid offset.");
|
|
return;
|
|
}
|
|
|
|
xText->scrollSubstringTo(startIndex, endIndex, AccessibleScrollType_SCROLL_ANYWHERE);
|
|
}
|
|
|
|
void QtAccessibleWidget::selection(int selectionIndex, int* startOffset, int* endOffset) const
|
|
{
|
|
if (!startOffset && !endOffset)
|
|
return;
|
|
|
|
Reference<XAccessibleText> xText;
|
|
if (selectionIndex == 0)
|
|
xText = Reference<XAccessibleText>(getAccessibleContextImpl(), UNO_QUERY);
|
|
|
|
if (startOffset)
|
|
*startOffset = xText.is() ? xText->getSelectionStart() : 0;
|
|
if (endOffset)
|
|
*endOffset = xText.is() ? xText->getSelectionEnd() : 0;
|
|
}
|
|
|
|
int QtAccessibleWidget::selectionCount() const
|
|
{
|
|
Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (xText.is() && !xText->getSelectedText().isEmpty())
|
|
return 1; // Only 1 selection supported atm
|
|
return 0;
|
|
}
|
|
|
|
void QtAccessibleWidget::setCursorPosition(int position)
|
|
{
|
|
Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (!xText.is())
|
|
return;
|
|
|
|
if (position < 0 || position > xText->getCharacterCount())
|
|
{
|
|
SAL_WARN("vcl.qt",
|
|
"QtAccessibleWidget::setCursorPosition called with invalid offset: " << position);
|
|
return;
|
|
}
|
|
|
|
xText->setCaretPosition(position);
|
|
}
|
|
|
|
void QtAccessibleWidget::setSelection(int /* selectionIndex */, int startOffset, int endOffset)
|
|
{
|
|
Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (!xText.is())
|
|
return;
|
|
|
|
sal_Int32 nTextLength = xText->getCharacterCount();
|
|
if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength)
|
|
{
|
|
SAL_WARN("vcl.qt", "QtAccessibleWidget::setSelection called with invalid offset.");
|
|
return;
|
|
}
|
|
|
|
xText->setSelection(startOffset, endOffset);
|
|
}
|
|
|
|
QString QtAccessibleWidget::text(int startOffset, int endOffset) const
|
|
{
|
|
Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (!xText.is())
|
|
return QString();
|
|
|
|
sal_Int32 nTextLength = xText->getCharacterCount();
|
|
if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength)
|
|
{
|
|
SAL_WARN("vcl.qt", "QtAccessibleWidget::text called with invalid offset.");
|
|
return QString();
|
|
}
|
|
|
|
return toQString(xText->getTextRange(startOffset, endOffset));
|
|
}
|
|
|
|
QString QtAccessibleWidget::textAfterOffset(int nOffset,
|
|
QAccessible::TextBoundaryType eBoundaryType,
|
|
int* pStartOffset, int* pEndOffset) const
|
|
{
|
|
if (pStartOffset == nullptr || pEndOffset == nullptr)
|
|
return QString();
|
|
|
|
*pStartOffset = -1;
|
|
*pEndOffset = -1;
|
|
|
|
Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (!xText.is())
|
|
return QString();
|
|
|
|
const int nCharCount = characterCount();
|
|
// -1 is special value for text length
|
|
if (nOffset == -1)
|
|
nOffset = nCharCount;
|
|
else if (nOffset < -1 || nOffset > nCharCount)
|
|
{
|
|
SAL_WARN("vcl.qt",
|
|
"QtAccessibleWidget::textAfterOffset called with invalid offset: " << nOffset);
|
|
return QString();
|
|
}
|
|
|
|
if (eBoundaryType == QAccessible::NoBoundary)
|
|
{
|
|
if (nOffset == nCharCount)
|
|
return QString();
|
|
*pStartOffset = nOffset + 1;
|
|
*pEndOffset = nCharCount;
|
|
return text(nOffset + 1, nCharCount);
|
|
}
|
|
|
|
sal_Int16 nUnoBoundaryType = lcl_matchQtTextBoundaryType(eBoundaryType);
|
|
assert(nUnoBoundaryType > 0);
|
|
const TextSegment aSegment = xText->getTextBehindIndex(nOffset, nUnoBoundaryType);
|
|
*pStartOffset = aSegment.SegmentStart;
|
|
*pEndOffset = aSegment.SegmentEnd;
|
|
return toQString(aSegment.SegmentText);
|
|
}
|
|
|
|
QString QtAccessibleWidget::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType,
|
|
int* startOffset, int* endOffset) const
|
|
{
|
|
if (startOffset == nullptr || endOffset == nullptr)
|
|
return QString();
|
|
|
|
const int nCharCount = characterCount();
|
|
if (boundaryType == QAccessible::NoBoundary)
|
|
{
|
|
*startOffset = 0;
|
|
*endOffset = nCharCount;
|
|
return text(0, nCharCount);
|
|
}
|
|
|
|
Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (!xText.is())
|
|
return QString();
|
|
|
|
sal_Int16 nUnoBoundaryType = lcl_matchQtTextBoundaryType(boundaryType);
|
|
assert(nUnoBoundaryType > 0);
|
|
|
|
// special value of -1 for offset means text length
|
|
if (offset == -1)
|
|
offset = nCharCount;
|
|
|
|
if (offset < 0 || offset > nCharCount)
|
|
{
|
|
SAL_WARN("vcl.qt",
|
|
"QtAccessibleWidget::textAtOffset called with invalid offset: " << offset);
|
|
return QString();
|
|
}
|
|
|
|
const TextSegment segment = xText->getTextAtIndex(offset, nUnoBoundaryType);
|
|
*startOffset = segment.SegmentStart;
|
|
*endOffset = segment.SegmentEnd;
|
|
return toQString(segment.SegmentText);
|
|
}
|
|
|
|
QString QtAccessibleWidget::textBeforeOffset(int nOffset,
|
|
QAccessible::TextBoundaryType eBoundaryType,
|
|
int* pStartOffset, int* pEndOffset) const
|
|
{
|
|
if (pStartOffset == nullptr || pEndOffset == nullptr)
|
|
return QString();
|
|
|
|
*pStartOffset = -1;
|
|
*pEndOffset = -1;
|
|
|
|
Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
|
|
if (!xText.is())
|
|
return QString();
|
|
|
|
const int nCharCount = characterCount();
|
|
// -1 is special value for text length
|
|
if (nOffset == -1)
|
|
nOffset = nCharCount;
|
|
else if (nOffset < -1 || nOffset > nCharCount)
|
|
{
|
|
SAL_WARN("vcl.qt",
|
|
"QtAccessibleWidget::textBeforeOffset called with invalid offset: " << nOffset);
|
|
return QString();
|
|
}
|
|
|
|
if (eBoundaryType == QAccessible::NoBoundary)
|
|
{
|
|
*pStartOffset = 0;
|
|
*pEndOffset = nOffset;
|
|
return text(0, nOffset);
|
|
}
|
|
|
|
sal_Int16 nUnoBoundaryType = lcl_matchQtTextBoundaryType(eBoundaryType);
|
|
assert(nUnoBoundaryType > 0);
|
|
const TextSegment aSegment = xText->getTextBeforeIndex(nOffset, nUnoBoundaryType);
|
|
*pStartOffset = aSegment.SegmentStart;
|
|
*pEndOffset = aSegment.SegmentEnd;
|
|
return toQString(aSegment.SegmentText);
|
|
}
|
|
|
|
// QAccessibleEditableTextInterface
|
|
|
|
void QtAccessibleWidget::deleteText(int startOffset, int endOffset)
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return;
|
|
|
|
Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY);
|
|
if (!xEditableText.is())
|
|
return;
|
|
|
|
sal_Int32 nTextLength = xEditableText->getCharacterCount();
|
|
if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength)
|
|
{
|
|
SAL_WARN("vcl.qt", "QtAccessibleWidget::deleteText called with invalid offset.");
|
|
return;
|
|
}
|
|
|
|
xEditableText->deleteText(startOffset, endOffset);
|
|
}
|
|
|
|
void QtAccessibleWidget::insertText(int offset, const QString& text)
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return;
|
|
|
|
Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY);
|
|
if (!xEditableText.is())
|
|
return;
|
|
|
|
if (offset < 0 || offset > xEditableText->getCharacterCount())
|
|
{
|
|
SAL_WARN("vcl.qt", "QtAccessibleWidget::insertText called with invalid offset: " << offset);
|
|
return;
|
|
}
|
|
|
|
xEditableText->insertText(toOUString(text), offset);
|
|
}
|
|
|
|
void QtAccessibleWidget::replaceText(int startOffset, int endOffset, const QString& text)
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return;
|
|
|
|
Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY);
|
|
if (!xEditableText.is())
|
|
return;
|
|
|
|
sal_Int32 nTextLength = xEditableText->getCharacterCount();
|
|
if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength)
|
|
{
|
|
SAL_WARN("vcl.qt", "QtAccessibleWidget::replaceText called with invalid offset.");
|
|
return;
|
|
}
|
|
|
|
xEditableText->replaceText(startOffset, endOffset, toOUString(text));
|
|
}
|
|
|
|
// QAccessibleValueInterface
|
|
QVariant QtAccessibleWidget::currentValue() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return QVariant();
|
|
|
|
Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
|
|
if (!xValue.is())
|
|
return QVariant();
|
|
double aDouble = 0;
|
|
xValue->getCurrentValue() >>= aDouble;
|
|
return QVariant(aDouble);
|
|
}
|
|
|
|
QVariant QtAccessibleWidget::maximumValue() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return QVariant();
|
|
|
|
Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
|
|
if (!xValue.is())
|
|
return QVariant();
|
|
double aDouble = 0;
|
|
xValue->getMaximumValue() >>= aDouble;
|
|
return QVariant(aDouble);
|
|
}
|
|
|
|
QVariant QtAccessibleWidget::minimumStepSize() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return QVariant();
|
|
|
|
Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
|
|
if (!xValue.is())
|
|
return QVariant();
|
|
double dMinStep = 0;
|
|
xValue->getMinimumIncrement() >>= dMinStep;
|
|
return QVariant(dMinStep);
|
|
}
|
|
|
|
QVariant QtAccessibleWidget::minimumValue() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return QVariant();
|
|
|
|
Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
|
|
if (!xValue.is())
|
|
return QVariant();
|
|
double aDouble = 0;
|
|
xValue->getMinimumValue() >>= aDouble;
|
|
return QVariant(aDouble);
|
|
}
|
|
|
|
void QtAccessibleWidget::setCurrentValue(const QVariant& value)
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return;
|
|
|
|
Reference<XAccessibleValue> xValue(xAc, UNO_QUERY);
|
|
if (!xValue.is())
|
|
return;
|
|
|
|
// Different types of numerical values for XAccessibleValue are possible.
|
|
// If current value has an integer type, also use that for the new value, to make
|
|
// sure underlying implementations expecting that can handle the value properly.
|
|
const Any aCurrentValue = xValue->getCurrentValue();
|
|
if (aCurrentValue.getValueTypeClass() == css::uno::TypeClass::TypeClass_LONG)
|
|
xValue->setCurrentValue(Any(static_cast<sal_Int32>(value.toInt())));
|
|
else if (aCurrentValue.getValueTypeClass() == css::uno::TypeClass::TypeClass_HYPER)
|
|
xValue->setCurrentValue(Any(static_cast<sal_Int64>(value.toLongLong())));
|
|
else
|
|
xValue->setCurrentValue(Any(value.toDouble()));
|
|
}
|
|
|
|
// QAccessibleTableInterface
|
|
QAccessibleInterface* QtAccessibleWidget::caption() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return nullptr;
|
|
|
|
Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
|
|
if (!xTable.is())
|
|
return nullptr;
|
|
return QAccessible::queryAccessibleInterface(
|
|
QtAccessibleRegistry::getQObject(xTable->getAccessibleCaption()));
|
|
}
|
|
|
|
QAccessibleInterface* QtAccessibleWidget::cellAt(int row, int column) const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return nullptr;
|
|
|
|
Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
|
|
if (!xTable.is())
|
|
return nullptr;
|
|
|
|
if (row < 0 || row >= xTable->getAccessibleRowCount() || column < 0
|
|
|| column >= xTable->getAccessibleColumnCount())
|
|
{
|
|
SAL_WARN("vcl.qt", "QtAccessibleWidget::cellAt called with invalid row/column index ("
|
|
<< row << ", " << column << ")");
|
|
return nullptr;
|
|
}
|
|
|
|
return QAccessible::queryAccessibleInterface(
|
|
QtAccessibleRegistry::getQObject(xTable->getAccessibleCellAt(row, column)));
|
|
}
|
|
|
|
int QtAccessibleWidget::columnCount() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return 0;
|
|
|
|
Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
|
|
if (!xTable.is())
|
|
return 0;
|
|
return xTable->getAccessibleColumnCount();
|
|
}
|
|
|
|
QString QtAccessibleWidget::columnDescription(int column) const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return QString();
|
|
|
|
Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
|
|
if (!xTable.is())
|
|
return QString();
|
|
return toQString(xTable->getAccessibleColumnDescription(column));
|
|
}
|
|
|
|
bool QtAccessibleWidget::isColumnSelected(int nColumn) const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return false;
|
|
|
|
Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
|
|
if (!xTable.is())
|
|
return false;
|
|
|
|
if (nColumn < 0 || nColumn >= xTable->getAccessibleColumnCount())
|
|
{
|
|
SAL_WARN("vcl.qt", "QtAccessibleWidget::isColumnSelected called with invalid column index "
|
|
<< nColumn);
|
|
return false;
|
|
}
|
|
|
|
return xTable->isAccessibleColumnSelected(nColumn);
|
|
}
|
|
|
|
bool QtAccessibleWidget::isRowSelected(int nRow) const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return false;
|
|
|
|
Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
|
|
if (!xTable.is())
|
|
return false;
|
|
|
|
if (nRow < 0 || nRow >= xTable->getAccessibleRowCount())
|
|
{
|
|
SAL_WARN("vcl.qt",
|
|
"QtAccessibleWidget::isRowSelected called with invalid row index " << nRow);
|
|
return false;
|
|
}
|
|
|
|
return xTable->isAccessibleRowSelected(nRow);
|
|
}
|
|
|
|
void QtAccessibleWidget::modelChange(QAccessibleTableModelChangeEvent*) {}
|
|
|
|
int QtAccessibleWidget::rowCount() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return 0;
|
|
|
|
Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
|
|
if (!xTable.is())
|
|
return 0;
|
|
return xTable->getAccessibleRowCount();
|
|
}
|
|
|
|
QString QtAccessibleWidget::rowDescription(int row) const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return QString();
|
|
|
|
Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
|
|
if (!xTable.is())
|
|
return QString();
|
|
return toQString(xTable->getAccessibleRowDescription(row));
|
|
}
|
|
|
|
bool QtAccessibleWidget::selectColumn(int column)
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return false;
|
|
|
|
if (column < 0 || column >= columnCount())
|
|
{
|
|
SAL_WARN("vcl.qt",
|
|
"QtAccessibleWidget::selectColumn called with invalid column index " << column);
|
|
return false;
|
|
}
|
|
|
|
Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY);
|
|
if (!xTableSelection.is())
|
|
return false;
|
|
return xTableSelection->selectColumn(column);
|
|
}
|
|
|
|
bool QtAccessibleWidget::selectRow(int row)
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return false;
|
|
|
|
if (row < 0 || row >= rowCount())
|
|
{
|
|
SAL_WARN("vcl.qt", "QtAccessibleWidget::selectRow called with invalid row index " << row);
|
|
return false;
|
|
}
|
|
|
|
Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY);
|
|
if (!xTableSelection.is())
|
|
return false;
|
|
return xTableSelection->selectRow(row);
|
|
}
|
|
|
|
int QtAccessibleWidget::selectedCellCount() const { return selectedItemCount(); }
|
|
|
|
QList<QAccessibleInterface*> QtAccessibleWidget::selectedCells() const { return selectedItems(); }
|
|
|
|
int QtAccessibleWidget::selectedColumnCount() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return 0;
|
|
|
|
Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
|
|
if (!xTable.is())
|
|
return 0;
|
|
return xTable->getSelectedAccessibleColumns().getLength();
|
|
}
|
|
|
|
QList<int> QtAccessibleWidget::selectedColumns() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return QList<int>();
|
|
|
|
Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
|
|
if (!xTable.is())
|
|
return QList<int>();
|
|
return toQList(xTable->getSelectedAccessibleColumns());
|
|
}
|
|
|
|
int QtAccessibleWidget::selectedRowCount() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return 0;
|
|
|
|
Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
|
|
if (!xTable.is())
|
|
return 0;
|
|
return xTable->getSelectedAccessibleRows().getLength();
|
|
}
|
|
|
|
QList<int> QtAccessibleWidget::selectedRows() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return QList<int>();
|
|
|
|
Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
|
|
if (!xTable.is())
|
|
return QList<int>();
|
|
return toQList(xTable->getSelectedAccessibleRows());
|
|
}
|
|
|
|
QAccessibleInterface* QtAccessibleWidget::summary() const
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return nullptr;
|
|
|
|
Reference<XAccessibleTable> xTable(xAc, UNO_QUERY);
|
|
if (!xTable.is())
|
|
return nullptr;
|
|
return QAccessible::queryAccessibleInterface(
|
|
QtAccessibleRegistry::getQObject(xTable->getAccessibleSummary()));
|
|
}
|
|
|
|
bool QtAccessibleWidget::unselectColumn(int column)
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return false;
|
|
|
|
Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY);
|
|
if (!xTableSelection.is())
|
|
return false;
|
|
return xTableSelection->unselectColumn(column);
|
|
}
|
|
|
|
bool QtAccessibleWidget::unselectRow(int row)
|
|
{
|
|
Reference<XAccessibleContext> xAc = getAccessibleContextImpl();
|
|
if (!xAc.is())
|
|
return false;
|
|
|
|
Reference<XAccessibleTableSelection> xTableSelection(xAc, UNO_QUERY);
|
|
if (!xTableSelection.is())
|
|
return false;
|
|
return xTableSelection->unselectRow(row);
|
|
}
|
|
|
|
// QAccessibleTableCellInterface
|
|
QList<QAccessibleInterface*> QtAccessibleWidget::columnHeaderCells() const
|
|
{
|
|
Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
|
|
if (!xTable.is())
|
|
return QList<QAccessibleInterface*>();
|
|
|
|
Reference<XAccessibleTable> xHeaders = xTable->getAccessibleColumnHeaders();
|
|
if (!xHeaders.is())
|
|
return QList<QAccessibleInterface*>();
|
|
|
|
const sal_Int32 nCol = columnIndex();
|
|
QList<QAccessibleInterface*> aHeaderCells;
|
|
for (sal_Int32 nRow = 0; nRow < xHeaders->getAccessibleRowCount(); nRow++)
|
|
{
|
|
Reference<XAccessible> xCell = xHeaders->getAccessibleCellAt(nRow, nCol);
|
|
QAccessibleInterface* pInterface
|
|
= QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xCell));
|
|
aHeaderCells.push_back(pInterface);
|
|
}
|
|
return aHeaderCells;
|
|
}
|
|
|
|
int QtAccessibleWidget::columnIndex() const
|
|
{
|
|
Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
|
|
if (!xAcc.is())
|
|
return -1;
|
|
|
|
Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
|
|
if (!xTable.is())
|
|
return -1;
|
|
|
|
const sal_Int64 nIndexInParent = xAcc->getAccessibleIndexInParent();
|
|
return xTable->getAccessibleColumn(nIndexInParent);
|
|
}
|
|
|
|
bool QtAccessibleWidget::isSelected() const
|
|
{
|
|
Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
|
|
if (!xAcc.is())
|
|
return false;
|
|
|
|
Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
|
|
if (!xTable.is())
|
|
return false;
|
|
|
|
const sal_Int32 nColumn = columnIndex();
|
|
const sal_Int32 nRow = rowIndex();
|
|
return xTable->isAccessibleSelected(nRow, nColumn);
|
|
}
|
|
|
|
int QtAccessibleWidget::columnExtent() const
|
|
{
|
|
Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
|
|
if (!xAcc.is())
|
|
return -1;
|
|
|
|
Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
|
|
if (!xTable.is())
|
|
return -1;
|
|
|
|
const sal_Int32 nColumn = columnIndex();
|
|
const sal_Int32 nRow = rowIndex();
|
|
return xTable->getAccessibleColumnExtentAt(nRow, nColumn);
|
|
}
|
|
|
|
QList<QAccessibleInterface*> QtAccessibleWidget::rowHeaderCells() const
|
|
{
|
|
Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
|
|
if (!xTable.is())
|
|
return QList<QAccessibleInterface*>();
|
|
|
|
Reference<XAccessibleTable> xHeaders = xTable->getAccessibleRowHeaders();
|
|
if (!xHeaders.is())
|
|
return QList<QAccessibleInterface*>();
|
|
|
|
const sal_Int32 nRow = rowIndex();
|
|
QList<QAccessibleInterface*> aHeaderCells;
|
|
for (sal_Int32 nCol = 0; nCol < xHeaders->getAccessibleColumnCount(); nCol++)
|
|
{
|
|
Reference<XAccessible> xCell = xHeaders->getAccessibleCellAt(nRow, nCol);
|
|
QAccessibleInterface* pInterface
|
|
= QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xCell));
|
|
aHeaderCells.push_back(pInterface);
|
|
}
|
|
return aHeaderCells;
|
|
}
|
|
|
|
int QtAccessibleWidget::rowExtent() const
|
|
{
|
|
Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
|
|
if (!xAcc.is())
|
|
return -1;
|
|
|
|
Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
|
|
if (!xTable.is())
|
|
return -1;
|
|
|
|
const sal_Int32 nColumn = columnIndex();
|
|
const sal_Int32 nRow = rowIndex();
|
|
return xTable->getAccessibleRowExtentAt(nRow, nColumn);
|
|
}
|
|
|
|
int QtAccessibleWidget::rowIndex() const
|
|
{
|
|
Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
|
|
if (!xAcc.is())
|
|
return -1;
|
|
|
|
Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
|
|
if (!xTable.is())
|
|
return -1;
|
|
|
|
const sal_Int64 nIndexInParent = xAcc->getAccessibleIndexInParent();
|
|
return xTable->getAccessibleRow(nIndexInParent);
|
|
}
|
|
|
|
QAccessibleInterface* QtAccessibleWidget::table() const
|
|
{
|
|
Reference<XAccessibleTable> xTable = getAccessibleTableForParent();
|
|
if (!xTable.is())
|
|
return nullptr;
|
|
|
|
Reference<XAccessible> xTableAcc(xTable, UNO_QUERY);
|
|
if (!xTableAcc.is())
|
|
return nullptr;
|
|
|
|
return QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xTableAcc));
|
|
}
|
|
|
|
// QAccessibleSelectionInterface
|
|
int QtAccessibleWidget::selectedItemCount() const
|
|
{
|
|
Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
|
|
if (!xAcc.is())
|
|
return 0;
|
|
|
|
Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
|
|
if (!xSelection.is())
|
|
return 0;
|
|
|
|
sal_Int64 nSelected = xSelection->getSelectedAccessibleChildCount();
|
|
if (nSelected > std::numeric_limits<int>::max())
|
|
{
|
|
SAL_WARN("vcl.qt",
|
|
"QtAccessibleWidget::selectedItemCount: Cell count exceeds maximum int value, "
|
|
"using max int.");
|
|
nSelected = std::numeric_limits<int>::max();
|
|
}
|
|
return nSelected;
|
|
}
|
|
|
|
QList<QAccessibleInterface*> QtAccessibleWidget::selectedItems() const
|
|
{
|
|
Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
|
|
if (!xAcc.is())
|
|
return QList<QAccessibleInterface*>();
|
|
|
|
Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
|
|
if (!xSelection.is())
|
|
return QList<QAccessibleInterface*>();
|
|
|
|
QList<QAccessibleInterface*> aSelectedItems;
|
|
sal_Int64 nSelected = xSelection->getSelectedAccessibleChildCount();
|
|
if (nSelected > std::numeric_limits<int>::max())
|
|
{
|
|
SAL_WARN("vcl.qt",
|
|
"QtAccessibleWidget::selectedItems: Cell count exceeds maximum int value, "
|
|
"using max int.");
|
|
nSelected = std::numeric_limits<int>::max();
|
|
}
|
|
for (sal_Int64 i = 0; i < nSelected; i++)
|
|
{
|
|
Reference<XAccessible> xChild = xSelection->getSelectedAccessibleChild(i);
|
|
QAccessibleInterface* pInterface
|
|
= QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xChild));
|
|
aSelectedItems.push_back(pInterface);
|
|
}
|
|
return aSelectedItems;
|
|
}
|
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
|
QAccessibleInterface* QtAccessibleWidget::selectedItem(int nSelectionIndex) const
|
|
{
|
|
Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
|
|
if (!xAcc.is())
|
|
return nullptr;
|
|
|
|
Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
|
|
if (!xSelection.is())
|
|
return nullptr;
|
|
|
|
if (nSelectionIndex < 0 || nSelectionIndex >= xSelection->getSelectedAccessibleChildCount())
|
|
{
|
|
SAL_WARN("vcl.qt",
|
|
"QtAccessibleWidget::selectedItem called with invalid index: " << nSelectionIndex);
|
|
return nullptr;
|
|
}
|
|
|
|
Reference<XAccessible> xChild = xSelection->getSelectedAccessibleChild(nSelectionIndex);
|
|
if (!xChild)
|
|
return nullptr;
|
|
|
|
return QAccessible::queryAccessibleInterface(QtAccessibleRegistry::getQObject(xChild));
|
|
}
|
|
|
|
bool QtAccessibleWidget::isSelected(QAccessibleInterface* pItem) const
|
|
{
|
|
Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
|
|
if (!xAcc.is())
|
|
return false;
|
|
|
|
Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
|
|
if (!xSelection.is())
|
|
return false;
|
|
|
|
int nChildIndex = indexOfChild(pItem);
|
|
if (nChildIndex < 0)
|
|
return false;
|
|
|
|
return xSelection->isAccessibleChildSelected(nChildIndex);
|
|
}
|
|
|
|
bool QtAccessibleWidget::select(QAccessibleInterface* pItem)
|
|
{
|
|
Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
|
|
if (!xAcc.is())
|
|
return false;
|
|
|
|
Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
|
|
if (!xSelection.is())
|
|
return false;
|
|
|
|
int nChildIndex = indexOfChild(pItem);
|
|
if (nChildIndex < 0)
|
|
return false;
|
|
|
|
xSelection->selectAccessibleChild(nChildIndex);
|
|
return true;
|
|
}
|
|
|
|
bool QtAccessibleWidget::unselect(QAccessibleInterface* pItem)
|
|
{
|
|
Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
|
|
if (!xAcc.is())
|
|
return false;
|
|
|
|
Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
|
|
if (!xSelection.is())
|
|
return false;
|
|
|
|
int nChildIndex = indexOfChild(pItem);
|
|
if (nChildIndex < 0)
|
|
return false;
|
|
|
|
xSelection->deselectAccessibleChild(nChildIndex);
|
|
return true;
|
|
}
|
|
|
|
bool QtAccessibleWidget::selectAll()
|
|
{
|
|
Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
|
|
if (!xAcc.is())
|
|
return false;
|
|
|
|
Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
|
|
if (!xSelection.is())
|
|
return false;
|
|
|
|
xSelection->selectAllAccessibleChildren();
|
|
return true;
|
|
}
|
|
|
|
bool QtAccessibleWidget::clear()
|
|
{
|
|
Reference<XAccessibleContext> xAcc = getAccessibleContextImpl();
|
|
if (!xAcc.is())
|
|
return false;
|
|
|
|
Reference<XAccessibleSelection> xSelection(xAcc, UNO_QUERY);
|
|
if (!xSelection.is())
|
|
return false;
|
|
|
|
xSelection->clearAccessibleSelection();
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|