diff options
author | Michael Weghorn <m.weghorn@posteo.de> | 2025-02-27 13:54:53 +0100 |
---|---|---|
committer | Michael Weghorn <m.weghorn@posteo.de> | 2025-02-27 23:01:02 +0100 |
commit | bc35ec327f1ade9075232ebc77a466130aa3aa95 (patch) | |
tree | 62711030e03b255d32a431fff826083c292ef8b6 /sd/source/console/AccessibleObject.cxx | |
parent | da3c954c95b2cc8e9316a36f76ec5f7bfadce868 (diff) |
sd presenter a11y: Move 2 classes to own .hxx/.cxx
Move the AccessibleFocusManager and
AccessibleObject classes to their own
header and source files, which makes it a little
easier to keep the overview.
AccessibleObject is now also no longer an inner
class of the PresenterAccessible class.
Change-Id: Ifdd2101fff7bee32567d737227dff514678d8f1c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182322
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
Tested-by: Jenkins
Diffstat (limited to 'sd/source/console/AccessibleObject.cxx')
-rw-r--r-- | sd/source/console/AccessibleObject.cxx | 528 |
1 files changed, 528 insertions, 0 deletions
diff --git a/sd/source/console/AccessibleObject.cxx b/sd/source/console/AccessibleObject.cxx new file mode 100644 index 000000000000..a77712f63596 --- /dev/null +++ b/sd/source/console/AccessibleObject.cxx @@ -0,0 +1,528 @@ +/* -*- 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 "AccessibleObject.hxx" +#include "AccessibleFocusManager.hxx" + +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> + + +AccessibleObject::AccessibleObject( + const sal_Int16 nRole, + OUString sName) + : AccessibleObjectInterfaceBase(m_aMutex), + msName(std::move(sName)), + mnRole(nRole), + mnStateSet(0), + mbIsFocused(false) +{ +} + +void AccessibleObject::LateInitialization() +{ + AccessibleFocusManager::Instance()->AddFocusableObject(this); +} + +void AccessibleObject::SetWindow ( + const Reference<awt::XWindow>& rxContentWindow, + const Reference<awt::XWindow>& rxBorderWindow) +{ + Reference<awt::XWindow2> xContentWindow (rxContentWindow, UNO_QUERY); + + if (mxContentWindow.get() == xContentWindow.get()) + return; + + if (mxContentWindow.is()) + { + mxContentWindow->removeWindowListener(this); + } + + mxContentWindow = std::move(xContentWindow); + mxBorderWindow.set(rxBorderWindow, UNO_QUERY); + + if (mxContentWindow.is()) + { + mxContentWindow->addWindowListener(this); + } + + UpdateStateSet(); +} + +void AccessibleObject::SetAccessibleParent ( + const Reference<XAccessible>& rxAccessibleParent) +{ + mxParentAccessible = rxAccessibleParent; +} + +void SAL_CALL AccessibleObject::disposing() +{ + AccessibleFocusManager::Instance()->RemoveFocusableObject(this); + SetWindow(nullptr, nullptr); +} + +//----- XAccessible ------------------------------------------------------- + +Reference<XAccessibleContext> SAL_CALL + AccessibleObject::getAccessibleContext() +{ + ThrowIfDisposed(); + + return this; +} + +//----- XAccessibleContext ---------------------------------------------- + +sal_Int64 SAL_CALL AccessibleObject::getAccessibleChildCount() +{ + ThrowIfDisposed(); + + return maChildren.size(); +} + +Reference<XAccessible> SAL_CALL + AccessibleObject::getAccessibleChild (sal_Int64 nIndex) +{ + ThrowIfDisposed(); + + if (nIndex<0 || o3tl::make_unsigned(nIndex)>=maChildren.size()) + throw lang::IndexOutOfBoundsException(u"invalid child index"_ustr, static_cast<uno::XWeak*>(this)); + + return maChildren[nIndex]; +} + +Reference<XAccessible> SAL_CALL + AccessibleObject::getAccessibleParent() +{ + ThrowIfDisposed(); + + return mxParentAccessible; +} + +sal_Int64 SAL_CALL + AccessibleObject::getAccessibleIndexInParent() +{ + ThrowIfDisposed(); + + const Reference<XAccessible> xThis (this); + if (mxParentAccessible.is()) + { + const Reference<XAccessibleContext> xContext (mxParentAccessible->getAccessibleContext()); + for (sal_Int64 nIndex = 0, nCount=xContext->getAccessibleChildCount(); + nIndex<nCount; + ++nIndex) + { + if (xContext->getAccessibleChild(nIndex) == xThis) + return nIndex; + } + } + + return 0; +} + +sal_Int16 SAL_CALL + AccessibleObject::getAccessibleRole() +{ + ThrowIfDisposed(); + + return mnRole; +} + +OUString SAL_CALL + AccessibleObject::getAccessibleDescription() +{ + ThrowIfDisposed(); + + return msName; +} + +OUString SAL_CALL + AccessibleObject::getAccessibleName() +{ + ThrowIfDisposed(); + + return msName; +} + +Reference<XAccessibleRelationSet> SAL_CALL + AccessibleObject::getAccessibleRelationSet() +{ + ThrowIfDisposed(); + + return nullptr; +} + +sal_Int64 SAL_CALL + AccessibleObject::getAccessibleStateSet() +{ + ThrowIfDisposed(); + + return mnStateSet; +} + +lang::Locale SAL_CALL + AccessibleObject::getLocale() +{ + ThrowIfDisposed(); + + if (mxParentAccessible.is()) + { + Reference<XAccessibleContext> xParentContext (mxParentAccessible->getAccessibleContext()); + if (xParentContext.is()) + return xParentContext->getLocale(); + } + return css::lang::Locale(); +} + +//----- XAccessibleComponent ------------------------------------------------ + +sal_Bool SAL_CALL AccessibleObject::containsPoint ( + const awt::Point& rPoint) +{ + ThrowIfDisposed(); + + if (mxContentWindow.is()) + { + const awt::Rectangle aBox (getBounds()); + return rPoint.X>=aBox.X + && rPoint.Y>=aBox.Y + && rPoint.X<aBox.X+aBox.Width + && rPoint.Y<aBox.Y+aBox.Height; + } + else + return false; +} + +Reference<XAccessible> SAL_CALL + AccessibleObject::getAccessibleAtPoint (const awt::Point&) +{ + ThrowIfDisposed(); + + return Reference<XAccessible>(); +} + +awt::Rectangle SAL_CALL AccessibleObject::getBounds() +{ + ThrowIfDisposed(); + + const awt::Point aLocation (GetRelativeLocation()); + const awt::Size aSize (GetSize()); + + return awt::Rectangle (aLocation.X, aLocation.Y, aSize.Width, aSize.Height); +} + +awt::Point SAL_CALL AccessibleObject::getLocation() +{ + ThrowIfDisposed(); + + const awt::Point aLocation (GetRelativeLocation()); + + return aLocation; +} + +awt::Point SAL_CALL AccessibleObject::getLocationOnScreen() +{ + ThrowIfDisposed(); + + awt::Point aRelativeLocation (GetRelativeLocation()); + awt::Point aParentLocationOnScreen (GetAbsoluteParentLocation()); + + return awt::Point( + aRelativeLocation.X + aParentLocationOnScreen.X, + aRelativeLocation.Y + aParentLocationOnScreen.Y); +} + +awt::Size SAL_CALL AccessibleObject::getSize() +{ + ThrowIfDisposed(); + + const awt::Size aSize (GetSize()); + + return aSize; +} + +void SAL_CALL AccessibleObject::grabFocus() +{ + ThrowIfDisposed(); + if (mxBorderWindow.is()) + mxBorderWindow->setFocus(); + else if (mxContentWindow.is()) + mxContentWindow->setFocus(); +} + +sal_Int32 SAL_CALL AccessibleObject::getForeground() +{ + ThrowIfDisposed(); + + return 0x00ffffff; +} + +sal_Int32 SAL_CALL AccessibleObject::getBackground() +{ + ThrowIfDisposed(); + + return 0x00000000; +} + +//----- XAccessibleEventBroadcaster ------------------------------------------- + +void SAL_CALL AccessibleObject::addAccessibleEventListener ( + const Reference<XAccessibleEventListener>& rxListener) +{ + if (!rxListener.is()) + return; + + const osl::MutexGuard aGuard(m_aMutex); + + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + uno::Reference<uno::XInterface> xThis (static_cast<XWeak*>(this), UNO_QUERY); + rxListener->disposing (lang::EventObject(xThis)); + } + else + { + maListeners.push_back(rxListener); + } +} + +void SAL_CALL AccessibleObject::removeAccessibleEventListener ( + const Reference<XAccessibleEventListener>& rxListener) +{ + ThrowIfDisposed(); + if (rxListener.is()) + { + const osl::MutexGuard aGuard(m_aMutex); + + std::erase(maListeners, rxListener); + } +} + +//----- XWindowListener --------------------------------------------------- + +void SAL_CALL AccessibleObject::windowResized ( + const css::awt::WindowEvent&) +{ + FireAccessibleEvent(AccessibleEventId::BOUNDRECT_CHANGED, Any(), Any()); +} + +void SAL_CALL AccessibleObject::windowMoved ( + const css::awt::WindowEvent&) +{ + FireAccessibleEvent(AccessibleEventId::BOUNDRECT_CHANGED, Any(), Any()); +} + +void SAL_CALL AccessibleObject::windowShown ( + const css::lang::EventObject&) +{ + UpdateStateSet(); +} + +void SAL_CALL AccessibleObject::windowHidden ( + const css::lang::EventObject&) +{ + UpdateStateSet(); +} + +//----- XEventListener -------------------------------------------------------- + +void SAL_CALL AccessibleObject::disposing (const css::lang::EventObject& rEvent) +{ + if (rEvent.Source == mxContentWindow) + { + mxContentWindow = nullptr; + mxBorderWindow = nullptr; + } + else + { + SetWindow(nullptr, nullptr); + } +} + +//----- private --------------------------------------------------------------- + +bool AccessibleObject::GetWindowState (const sal_Int64 nType) const +{ + switch (nType) + { + case AccessibleStateType::ENABLED: + return mxContentWindow.is() && mxContentWindow->isEnabled(); + + case AccessibleStateType::FOCUSABLE: + return true; + + case AccessibleStateType::FOCUSED: + return mbIsFocused; + + case AccessibleStateType::SHOWING: + return mxContentWindow.is() && mxContentWindow->isVisible(); + + default: + return false; + } +} + +void AccessibleObject::UpdateStateSet() +{ + UpdateState(AccessibleStateType::FOCUSABLE, true); + UpdateState(AccessibleStateType::VISIBLE, true); + UpdateState(AccessibleStateType::ENABLED, true); + UpdateState(AccessibleStateType::MULTI_LINE, true); + UpdateState(AccessibleStateType::SENSITIVE, true); + + UpdateState(AccessibleStateType::ENABLED, GetWindowState(AccessibleStateType::ENABLED)); + UpdateState(AccessibleStateType::FOCUSED, GetWindowState(AccessibleStateType::FOCUSED)); + UpdateState(AccessibleStateType::SHOWING, GetWindowState(AccessibleStateType::SHOWING)); + // UpdateState(AccessibleStateType::ACTIVE, GetWindowState(AccessibleStateType::ACTIVE)); +} + +void AccessibleObject::UpdateState( + const sal_Int64 nState, + const bool bValue) +{ + if (((mnStateSet & nState) != 0) == bValue) + return; + if (bValue) + { + mnStateSet |= nState; + FireAccessibleEvent(AccessibleEventId::STATE_CHANGED, Any(), Any(nState)); + } + else + { + mnStateSet &= ~nState; + FireAccessibleEvent(AccessibleEventId::STATE_CHANGED, Any(nState), Any()); + } +} + +void AccessibleObject::AddChild ( + const ::rtl::Reference<AccessibleObject>& rpChild) +{ + maChildren.push_back(rpChild); + rpChild->SetAccessibleParent(this); + FireAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN, Any(), Any()); +} + +void AccessibleObject::RemoveChild ( + const ::rtl::Reference<AccessibleObject>& rpChild) +{ + rpChild->SetAccessibleParent(Reference<XAccessible>()); + maChildren.erase(::std::find(maChildren.begin(), maChildren.end(), rpChild)); + FireAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN, Any(), Any()); +} + +void AccessibleObject::SetIsFocused (const bool bIsFocused) +{ + if (mbIsFocused != bIsFocused) + { + mbIsFocused = bIsFocused; + UpdateStateSet(); + } +} + +void AccessibleObject::SetAccessibleName (const OUString& rsName) +{ + if (msName != rsName) + { + const OUString sOldName(msName); + msName = rsName; + FireAccessibleEvent(AccessibleEventId::NAME_CHANGED, Any(sOldName), Any(msName)); + } +} + +void AccessibleObject::FireAccessibleEvent ( + const sal_Int16 nEventId, + const uno::Any& rOldValue, + const uno::Any& rNewValue ) +{ + AccessibleEventObject aEventObject; + + aEventObject.Source = Reference<XWeak>(this); + aEventObject.EventId = nEventId; + aEventObject.NewValue = rNewValue; + aEventObject.OldValue = rOldValue; + + ::std::vector<Reference<XAccessibleEventListener> > aListenerCopy(maListeners); + for (const auto& rxListener : aListenerCopy) + { + try + { + rxListener->notifyEvent(aEventObject); + } + catch (const lang::DisposedException&) + { + // Listener has been disposed and should have been removed + // already. + removeAccessibleEventListener(rxListener); + } + catch (const Exception&) + { + // Ignore all other exceptions and assume that they are + // caused by a temporary problem. + } + } +} + +awt::Point AccessibleObject::GetRelativeLocation() +{ + awt::Point aLocation; + if (mxContentWindow.is()) + { + const awt::Rectangle aContentBox (mxContentWindow->getPosSize()); + aLocation.X = aContentBox.X; + aLocation.Y = aContentBox.Y; + if (mxBorderWindow.is()) + { + const awt::Rectangle aBorderBox (mxBorderWindow->getPosSize()); + aLocation.X += aBorderBox.X; + aLocation.Y += aBorderBox.Y; + } + } + return aLocation; +} + +awt::Size AccessibleObject::GetSize() +{ + if (mxContentWindow.is()) + { + const awt::Rectangle aBox (mxContentWindow->getPosSize()); + return awt::Size(aBox.Width, aBox.Height); + } + else + return awt::Size(); +} + +awt::Point AccessibleObject::GetAbsoluteParentLocation() +{ + Reference<XAccessibleComponent> xParentComponent; + if (mxParentAccessible.is()) + xParentComponent.set( mxParentAccessible->getAccessibleContext(), UNO_QUERY); + if (xParentComponent.is()) + return xParentComponent->getLocationOnScreen(); + else + return awt::Point(); +} + +void AccessibleObject::ThrowIfDisposed() const +{ + if (rBHelper.bDisposed || rBHelper.bInDispose) + throw lang::DisposedException(u"object has already been disposed"_ustr, uno::Reference<uno::XInterface>(const_cast<uno::XWeak*>(static_cast<uno::XWeak const *>(this)))); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ |