diff options
Diffstat (limited to 'starmath/source')
-rw-r--r-- | starmath/source/AccessibleSmElement.cxx | 290 | ||||
-rw-r--r-- | starmath/source/AccessibleSmElementsControl.cxx | 457 | ||||
-rw-r--r-- | starmath/source/ElementsDockingWindow.cxx | 155 |
3 files changed, 891 insertions, 11 deletions
diff --git a/starmath/source/AccessibleSmElement.cxx b/starmath/source/AccessibleSmElement.cxx new file mode 100644 index 000000000000..e4cebe9712f6 --- /dev/null +++ b/starmath/source/AccessibleSmElement.cxx @@ -0,0 +1,290 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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 <AccessibleSmElement.hxx> +#include <ElementsDockingWindow.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> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <toolkit/helper/convert.hxx> +#include <unotools/accessiblerelationsethelper.hxx> +#include <unotools/accessiblestatesethelper.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> + +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star; +using OContextEntryGuard = ::comphelper::OContextEntryGuard; +using OExternalLockGuard = ::comphelper::OExternalLockGuard; + +AccessibleSmElement::AccessibleSmElement(SmElementsControl* pSmElementsControl, sal_uInt16 nItemId, + sal_Int32 nIndexInParent) + : m_pSmElementsControl(pSmElementsControl) + , m_nIndexInParent(nIndexInParent) + , m_nItemId(nItemId) + , m_bHasFocus(false) +{ + assert(m_pSmElementsControl); + m_nRole = m_pSmElementsControl->itemIsSeparator(m_nItemId) ? AccessibleRole::SEPARATOR + : AccessibleRole::PUSH_BUTTON; +} + +AccessibleSmElement::~AccessibleSmElement() {} + +void AccessibleSmElement::SetFocus(bool bFocus) +{ + if (m_bHasFocus == bFocus) + return; + + uno::Any aOldValue; + uno::Any aNewValue; + if (m_bHasFocus) + aOldValue <<= AccessibleStateType::FOCUSED; + else + aNewValue <<= AccessibleStateType::FOCUSED; + m_bHasFocus = bFocus; + NotifyAccessibleEvent(AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue); +} + +awt::Rectangle AccessibleSmElement::implGetBounds() +{ + awt::Rectangle aRect; + if (m_pSmElementsControl) + aRect = AWTRectangle(m_pSmElementsControl->itemPosRect(m_nItemId)); + return aRect; +} + +// XInterface + +IMPLEMENT_FORWARD_REFCOUNT(AccessibleSmElement, comphelper::OAccessibleComponentHelper) + +uno::Any AccessibleSmElement::queryInterface(const uno::Type& _rType) +{ + if (_rType == cppu::UnoType<XAccessibleAction>::get() + && (!m_pSmElementsControl || m_pSmElementsControl->itemIsSeparator(m_nItemId))) + return uno::Any(); + + uno::Any aReturn = comphelper::OAccessibleComponentHelper::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = AccessibleSmElement_BASE::queryInterface(_rType); + return aReturn; +} + +// XTypeProvider + +IMPLEMENT_FORWARD_XTYPEPROVIDER2(AccessibleSmElement, comphelper::OAccessibleComponentHelper, + AccessibleSmElement_BASE) + +// XComponent + +void AccessibleSmElement::disposing() +{ + comphelper::OAccessibleComponentHelper::disposing(); + m_pSmElementsControl = nullptr; +} + +// XServiceInfo + +OUString AccessibleSmElement::getImplementationName() +{ + return OUString("com.sun.star.comp.toolkit.AccessibleSmElement"); +} + +sal_Bool AccessibleSmElement::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence<OUString> AccessibleSmElement::getSupportedServiceNames() +{ + return { "com.sun.star.accessibility.AccessibleContext", + "com.sun.star.accessibility.AccessibleComponent", + "com.sun.star.accessibility.AccessibleSmElement" }; +} + +// XAccessible + +uno::Reference<XAccessibleContext> AccessibleSmElement::getAccessibleContext() { return this; } + +// XAccessibleContext + +sal_Int32 AccessibleSmElement::getAccessibleChildCount() { return 0; } + +uno::Reference<accessibility::XAccessible> AccessibleSmElement::getAccessibleChild(sal_Int32) +{ + return uno::Reference<XAccessible>(); +} + +uno::Reference<XAccessible> AccessibleSmElement::getAccessibleParent() +{ + OContextEntryGuard aGuard(this); + uno::Reference<XAccessible> xParent; + if (m_pSmElementsControl) + xParent = m_pSmElementsControl->GetAccessible(); + return xParent; +} + +sal_Int32 AccessibleSmElement::getAccessibleIndexInParent() +{ + OContextEntryGuard aGuard(this); + return m_nIndexInParent; +} + +sal_Int16 AccessibleSmElement::getAccessibleRole() +{ + OContextEntryGuard aGuard(this); + return m_nRole; +} + +OUString AccessibleSmElement::getAccessibleDescription() { return getAccessibleName(); } + +OUString AccessibleSmElement::getAccessibleName() +{ + OExternalLockGuard aGuard(this); + OUString aName; + if (m_pSmElementsControl) + aName = m_pSmElementsControl->itemName(m_nItemId); + return aName; +} + +uno::Reference<XAccessibleRelationSet> AccessibleSmElement::getAccessibleRelationSet() +{ + OContextEntryGuard aGuard(this); + + utl::AccessibleRelationSetHelper* pRelationSetHelper = new utl::AccessibleRelationSetHelper; + uno::Reference<XAccessibleRelationSet> xSet = pRelationSetHelper; + return xSet; +} + +uno::Reference<XAccessibleStateSet> AccessibleSmElement::getAccessibleStateSet() +{ + OExternalLockGuard aGuard(this); + + utl::AccessibleStateSetHelper* pStateSetHelper = new utl::AccessibleStateSetHelper; + uno::Reference<XAccessibleStateSet> xStateSet = pStateSetHelper; + + if (m_pSmElementsControl && !rBHelper.bDisposed && !rBHelper.bInDispose) + { + if (m_pSmElementsControl->itemIsVisible(m_nItemId)) + pStateSetHelper->AddState(AccessibleStateType::VISIBLE); + if (!m_pSmElementsControl->itemIsSeparator(m_nItemId)) + { + if (m_pSmElementsControl->IsEnabled()) + { + pStateSetHelper->AddState(AccessibleStateType::ENABLED); + pStateSetHelper->AddState(AccessibleStateType::SENSITIVE); + } + pStateSetHelper->AddState(AccessibleStateType::FOCUSABLE); + if (m_bHasFocus) + pStateSetHelper->AddState(AccessibleStateType::FOCUSED); + } + } + else + pStateSetHelper->AddState(AccessibleStateType::DEFUNC); + + return xStateSet; +} + +// XAccessibleComponent + +uno::Reference<XAccessible> AccessibleSmElement::getAccessibleAtPoint(const awt::Point&) +{ + return uno::Reference<XAccessible>(); +} + +void AccessibleSmElement::grabFocus() +{ + uno::Reference<XAccessible> xParent(getAccessibleParent()); + + if (xParent.is()) + { + uno::Reference<XAccessibleSelection> rxAccessibleSelection(xParent->getAccessibleContext(), + uno::UNO_QUERY); + if (rxAccessibleSelection.is()) + rxAccessibleSelection->selectAccessibleChild(getAccessibleIndexInParent()); + } +} + +sal_Int32 AccessibleSmElement::getForeground() +{ + OExternalLockGuard aGuard(this); + + Color nColor; + if (m_pSmElementsControl) + nColor = m_pSmElementsControl->GetControlForeground(); + return sal_Int32(nColor); +} + +sal_Int32 AccessibleSmElement::getBackground() +{ + OExternalLockGuard aGuard(this); + + Color nColor; + if (m_pSmElementsControl) + nColor = m_pSmElementsControl->GetControlBackground(); + return sal_Int32(nColor); +} + +// XAccessibleAction + +sal_Int32 AccessibleSmElement::getAccessibleActionCount() +{ + // only one action -> "Press" + return m_pSmElementsControl->itemIsSeparator(m_nItemId) ? 0 : 1; +} + +void AccessibleSmElement::testAction(sal_Int32 nIndex) const +{ + if (!m_pSmElementsControl || m_pSmElementsControl->itemIsSeparator(m_nItemId) || (nIndex != 0)) + throw lang::IndexOutOfBoundsException(); +} + +sal_Bool AccessibleSmElement::doAccessibleAction(sal_Int32 nIndex) +{ + OExternalLockGuard aGuard(this); + + testAction(nIndex); + + return m_pSmElementsControl->itemTrigger(m_nItemId); +} + +OUString AccessibleSmElement::getAccessibleActionDescription(sal_Int32 nIndex) +{ + OExternalLockGuard aGuard(this); + + testAction(nIndex); + + return OUString("press"); +} + +uno::Reference<XAccessibleKeyBinding> +AccessibleSmElement::getAccessibleActionKeyBinding(sal_Int32 nIndex) +{ + OContextEntryGuard aGuard(this); + + testAction(nIndex); + + return uno::Reference<XAccessibleKeyBinding>(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/starmath/source/AccessibleSmElementsControl.cxx b/starmath/source/AccessibleSmElementsControl.cxx new file mode 100644 index 000000000000..d0f95a0ecef7 --- /dev/null +++ b/starmath/source/AccessibleSmElementsControl.cxx @@ -0,0 +1,457 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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 <AccessibleSmElementsControl.hxx> +#include <AccessibleSmElement.hxx> +#include <ElementsDockingWindow.hxx> +#include <smmod.hxx> + +#include <comphelper/accessiblewrapper.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/types.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> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <toolkit/helper/convert.hxx> +#include <unotools/accessiblerelationsethelper.hxx> +#include <unotools/accessiblestatesethelper.hxx> +#include <vcl/svapp.hxx> +#include <vcl/vclevent.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using OContextEntryGuard = ::comphelper::OContextEntryGuard; +using OExternalLockGuard = ::comphelper::OExternalLockGuard; + +// AccessibleSmElementsControl + +AccessibleSmElementsControl::AccessibleSmElementsControl(SmElementsControl& rControl) + : m_pControl(&rControl) +{ +} + +AccessibleSmElementsControl::~AccessibleSmElementsControl() {} + +void AccessibleSmElementsControl::UpdateFocus(sal_uInt16 nPos) +{ + const bool bSetFocus = (nPos == SAL_MAX_UINT16); + + // submit events only if the widget has the focus to avoid sending events due to mouse move + if (!m_pControl || (bSetFocus && !m_pControl->HasFocus())) + return; + + if (bSetFocus) + nPos = m_pControl->itemHighlighted() - m_pControl->itemOffset(); + + if (nPos < m_aAccessibleChildren.size()) + { + const auto& rxChild = m_aAccessibleChildren[nPos]; + if (rxChild.is()) + rxChild->SetFocus(bSetFocus); + } +} + +void AccessibleSmElementsControl::ReleaseAllItems(bool bNotifyRemoval) +{ + if (m_aAccessibleChildren.empty()) + return; + + m_aAccessibleChildren.clear(); + if (!bNotifyRemoval) + return; + + // The original toolbox accessibility code uses individual NAME_CHANGED + // events in a loop. We can't do this, because on each remove event the + // list of known children is rebuild. But since we rely on the child + // count of the SmElementsControl, we'll always have no or all items. + // In the latter case this would automatically recreate all items! + assert(m_pControl && m_pControl->itemCount() == 0); + NotifyAccessibleEvent(AccessibleEventId::INVALIDATE_ALL_CHILDREN, uno::Any(), uno::Any()); +} + +void AccessibleSmElementsControl::AddAllItems() +{ + assert(m_pControl); + if (!m_pControl) + return; + + uno::Any aNewName(getAccessibleName()); + NotifyAccessibleEvent(AccessibleEventId::NAME_CHANGED, uno::Any(), aNewName); + + // register the new items + sal_uInt16 nCount = getAccessibleChildCount(); + for (sal_uInt16 i = 0; i < nCount; ++i) + { + uno::Any aNewValue; + aNewValue <<= getAccessibleChild(static_cast<sal_Int32>(i)); + NotifyAccessibleEvent(AccessibleEventId::CHILD, uno::Any(), aNewValue); + } +} + +IMPLEMENT_FORWARD_XINTERFACE2(AccessibleSmElementsControl, comphelper::OAccessibleComponentHelper, + AccessibleSmElementsControl_BASE) + +IMPLEMENT_FORWARD_XTYPEPROVIDER2(AccessibleSmElementsControl, + comphelper::OAccessibleComponentHelper, + AccessibleSmElementsControl_BASE) + +// XAccessible +uno::Reference<XAccessibleContext> AccessibleSmElementsControl::getAccessibleContext() +{ + return this; +} + +// XComponent +void AccessibleSmElementsControl::disposing() +{ + comphelper::OAccessibleComponentHelper::disposing(); + m_aAccessibleChildren.clear(); +} + +void AccessibleSmElementsControl::grabFocus() +{ + SolarMutexGuard aGuard; + if (!m_pControl) + throw uno::RuntimeException(); + + m_pControl->GrabFocus(); +} + +sal_Int32 AccessibleSmElementsControl::getForeground() +{ + SolarMutexGuard aGuard; + + if (!m_pControl) + throw uno::RuntimeException(); + return static_cast<sal_Int32>(m_pControl->GetTextColor()); +} + +sal_Int32 AccessibleSmElementsControl::getBackground() +{ + SolarMutexGuard aGuard; + + if (!m_pControl) + throw uno::RuntimeException(); + Color nCol = m_pControl->GetControlBackground(); + return static_cast<sal_Int32>(nCol); +} + +// XServiceInfo +OUString AccessibleSmElementsControl::getImplementationName() +{ + return OUString("com.sun.star.comp.toolkit.AccessibleSmElementsControl"); +} + +sal_Bool AccessibleSmElementsControl::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence<OUString> AccessibleSmElementsControl::getSupportedServiceNames() +{ + return { "com.sun.star.accessibility.AccessibleContext", + "com.sun.star.accessibility.AccessibleComponent", + "com.sun.star.accessibility.AccessibleSelection", + "com.sun.star.accessibility.AccessibleSmElementsControl" }; +} + +// XAccessibleContext +sal_Int32 AccessibleSmElementsControl::getAccessibleChildCount() +{ + comphelper::OExternalLockGuard aGuard(this); + sal_Int32 nCount = 0; + if (m_pControl) + { + nCount = m_pControl->itemCount(); + if (m_aAccessibleChildren.size() != sal_uInt16(nCount)) + m_aAccessibleChildren.resize(nCount); + if (m_pControl->scrollbarAccessible().is()) + nCount++; + } + return nCount; +} + +uno::Reference<XAccessible> AccessibleSmElementsControl::getAccessibleChild(sal_Int32 i) +{ + comphelper::OExternalLockGuard aGuard(this); + + if (i < 0 || i >= getAccessibleChildCount()) + throw lang::IndexOutOfBoundsException(); + + // first child may be the scrollbar + sal_uInt16 c(i); + uno::Reference<XAccessible> xScrollbar = m_pControl->scrollbarAccessible(); + if (xScrollbar.is()) + { + if (c == 0) + return xScrollbar; + c--; + } + + assert(c < m_aAccessibleChildren.size()); + rtl::Reference<AccessibleSmElement> xChild = m_aAccessibleChildren[c]; + const sal_uInt16 nItemId = m_pControl->itemOffset() + c; + if (xChild.is() && xChild->itemId() != nItemId) + xChild.clear(); + if (!xChild.is()) + { + sal_uInt16 nHighlightItemId = m_pControl->itemHighlighted(); + AccessibleSmElement* pChild = new AccessibleSmElement(m_pControl, nItemId, i); + if (pChild->itemId() == nHighlightItemId) + pChild->SetFocus(true); + m_aAccessibleChildren[c] = pChild; + xChild = pChild; + } + return xChild.get(); +} + +uno::Reference<XAccessible> AccessibleSmElementsControl::getAccessibleParent() +{ + SolarMutexGuard aGuard; + if (!m_pControl) + throw uno::RuntimeException(); + + vcl::Window* pAccParent = m_pControl->GetAccessibleParentWindow(); + assert(pAccParent); + return pAccParent ? pAccParent->GetAccessible() : uno::Reference<XAccessible>(); +} + +uno::Reference<XAccessible> +AccessibleSmElementsControl::getAccessibleAtPoint(const awt::Point& rPoint) +{ + comphelper::OExternalLockGuard aGuard(this); + + uno::Reference<XAccessible> xAccessible; + if (m_pControl) + { + sal_uInt16 nPos = m_pControl->itemAtPos(VCLPoint(rPoint)); + nPos -= m_pControl->itemOffset(); + if (nPos <= m_aAccessibleChildren.size()) + xAccessible = getAccessibleChild(nPos); + } + return xAccessible; +} + +sal_Int16 AccessibleSmElementsControl::getAccessibleRole() { return AccessibleRole::SCROLL_PANE; } + +OUString AccessibleSmElementsControl::getAccessibleDescription() { return OUString(); } + +OUString AccessibleSmElementsControl::getAccessibleName() +{ + SolarMutexGuard aGuard; + OUString aName; + if (m_pControl) + aName = SmResId(m_pControl->elementSetId().getStr()); + return aName; +} + +// XAccessibleSelection +void AccessibleSmElementsControl::selectAccessibleChild(sal_Int32 nChildIndex) +{ + OExternalLockGuard aGuard(this); + + if ((!m_pControl) || nChildIndex < 0 + || static_cast<size_t>(nChildIndex) >= m_aAccessibleChildren.size()) + throw lang::IndexOutOfBoundsException(); + + m_pControl->setItemHighlighted(nChildIndex); +} + +sal_Bool AccessibleSmElementsControl::isAccessibleChildSelected(sal_Int32 nChildIndex) +{ + OExternalLockGuard aGuard(this); + if ((!m_pControl) || nChildIndex < 0 + || static_cast<size_t>(nChildIndex) >= m_aAccessibleChildren.size()) + throw lang::IndexOutOfBoundsException(); + + return (m_pControl->itemHighlighted() == nChildIndex); +} + +void AccessibleSmElementsControl::clearAccessibleSelection() +{ + OExternalLockGuard aGuard(this); + if (m_pControl) + m_pControl->setItemHighlighted(SAL_MAX_UINT16); +} + +void AccessibleSmElementsControl::selectAllAccessibleChildren() +{ + // intentionally empty +} + +sal_Int32 AccessibleSmElementsControl::getSelectedAccessibleChildCount() +{ + OExternalLockGuard aGuard(this); + + sal_Int32 nRet = 0; + if (m_pControl + && (m_pControl->itemHighlighted() - m_pControl->itemOffset()) < getAccessibleChildCount()) + nRet = 1; + return nRet; +} + +uno::Reference<XAccessible> +AccessibleSmElementsControl::getSelectedAccessibleChild(sal_Int32 nSelectedChildIndex) +{ + OExternalLockGuard aGuard(this); + if (nSelectedChildIndex != 0 || !m_pControl) + throw lang::IndexOutOfBoundsException(); + return getAccessibleChild(m_pControl->itemHighlighted() - m_pControl->itemOffset()); +} + +void AccessibleSmElementsControl::deselectAccessibleChild(sal_Int32 nChildIndex) +{ + OExternalLockGuard aGuard(this); + if (nChildIndex != 0 || nChildIndex >= getAccessibleChildCount()) + throw lang::IndexOutOfBoundsException(); + clearAccessibleSelection(); // there can be just one selected child +} + +// XAccessibleComponent +static awt::Point lcl_GetLocationOnScreen(vcl::Window const* m_pControl) +{ + awt::Point aPos; + if (m_pControl) + { + tools::Rectangle aRect = m_pControl->GetWindowExtentsRelative(nullptr); + aPos.X = aRect.Left(); + aPos.Y = aRect.Top(); + } + return aPos; +} + +static awt::Rectangle lcl_GetBounds(vcl::Window const* m_pControl) +{ + // !! see VCLXAccessibleComponent::implGetBounds() + + //! the coordinates returned are relative to the parent window ! + //! Thus the top-left point may be different from (0, 0) ! + + awt::Rectangle aBounds; + if (m_pControl) + { + tools::Rectangle aRect = m_pControl->GetWindowExtentsRelative(nullptr); + aBounds.X = aRect.Left(); + aBounds.Y = aRect.Top(); + aBounds.Width = aRect.GetWidth(); + aBounds.Height = aRect.GetHeight(); + + vcl::Window* pParent = m_pControl->GetAccessibleParentWindow(); + if (pParent) + { + tools::Rectangle aParentRect = pParent->GetWindowExtentsRelative(nullptr); + awt::Point aParentScreenLoc(aParentRect.Left(), aParentRect.Top()); + aBounds.X -= aParentScreenLoc.X; + aBounds.Y -= aParentScreenLoc.Y; + } + } + return aBounds; +} + +void AccessibleSmElementsControl::TestControl() +{ + if (!m_pControl) + throw uno::RuntimeException(); + assert(m_pControl->GetParent()->GetAccessible() == getAccessibleParent()); +} + +awt::Rectangle AccessibleSmElementsControl::implGetBounds() +{ + SolarMutexGuard aGuard; + TestControl(); + return lcl_GetBounds(m_pControl); +} + +awt::Rectangle AccessibleSmElementsControl::getBounds() { return implGetBounds(); } + +sal_Bool AccessibleSmElementsControl::containsPoint(const awt::Point& aPoint) +{ + SolarMutexGuard aGuard; + TestControl(); + Size aSz(m_pControl->GetSizePixel()); + return aPoint.X >= 0 && aPoint.Y >= 0 && aPoint.X < aSz.Width() && aPoint.Y < aSz.Height(); +} + +awt::Point AccessibleSmElementsControl::getLocation() +{ + SolarMutexGuard aGuard; + TestControl(); + awt::Rectangle aRect(lcl_GetBounds(m_pControl)); + return awt::Point(aRect.X, aRect.Y); +} + +awt::Point AccessibleSmElementsControl::getLocationOnScreen() +{ + SolarMutexGuard aGuard; + TestControl(); + return lcl_GetLocationOnScreen(m_pControl); +} + +awt::Size AccessibleSmElementsControl::getSize() +{ + SolarMutexGuard aGuard; + TestControl(); + + Size aSz(m_pControl->GetSizePixel()); +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + awt::Rectangle aRect(lcl_GetBounds(m_pControl)); + Size aSz2(aRect.Width, aRect.Height); + assert(aSz == aSz2 && "mismatch in width"); +#endif + return awt::Size(aSz.Width(), aSz.Height()); +} + +uno::Reference<XAccessibleRelationSet> AccessibleSmElementsControl::getAccessibleRelationSet() +{ + uno::Reference<XAccessibleRelationSet> xRelSet = new utl::AccessibleRelationSetHelper(); + return xRelSet; // empty relation set +} + +uno::Reference<XAccessibleStateSet> AccessibleSmElementsControl::getAccessibleStateSet() +{ + SolarMutexGuard aGuard; + ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper; + + uno::Reference<XAccessibleStateSet> xStateSet(pStateSet); + + if (!m_pControl) + pStateSet->AddState(AccessibleStateType::DEFUNC); + else + { + pStateSet->AddState(AccessibleStateType::ENABLED); + pStateSet->AddState(AccessibleStateType::FOCUSABLE); + if (m_pControl->HasFocus()) + pStateSet->AddState(AccessibleStateType::FOCUSED); + if (m_pControl->IsActive()) + pStateSet->AddState(AccessibleStateType::ACTIVE); + if (m_pControl->IsVisible()) + pStateSet->AddState(AccessibleStateType::SHOWING); + if (m_pControl->IsReallyVisible()) + pStateSet->AddState(AccessibleStateType::VISIBLE); + if (COL_TRANSPARENT != m_pControl->GetBackground().GetColor()) + pStateSet->AddState(AccessibleStateType::OPAQUE); + } + + return xStateSet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/starmath/source/ElementsDockingWindow.cxx b/starmath/source/ElementsDockingWindow.cxx index d34062ddb158..45bfb7541099 100644 --- a/starmath/source/ElementsDockingWindow.cxx +++ b/starmath/source/ElementsDockingWindow.cxx @@ -261,8 +261,9 @@ const size_t SmElementsControl::m_aCategoriesSize = SAL_N_ELEMENTS(m_aCategories SmElementsControl::SmElementsControl(vcl::Window *pParent) : Control(pParent, WB_TABSTOP) , mpDocShell(new SmDocShell(SfxModelFlags::EMBEDDED_OBJECT)) - , m_nCurrentElement(0) + , m_nCurrentElement(SAL_MAX_UINT16) , m_nCurrentRolloverElement(SAL_MAX_UINT16) + , m_nCurrentOffset(1) // Default offset of 1 due to the ScrollBar child , mbVerticalMode(true) , mxScroll(VclPtr<ScrollBar>::Create(this, WB_VERT)) , m_bFirstPaintAfterLayout(false) @@ -311,6 +312,19 @@ SmElement* SmElementsControl::current() const return (nCur < maElementList.size()) ? maElementList[nCur].get() : nullptr; } +void SmElementsControl::setCurrentElement(sal_uInt16 nPos) +{ + if (m_nCurrentElement == nPos) + return; + if (nPos != SAL_MAX_UINT16 && nPos >= maElementList.size()) + return; + if (m_xAccessible.is() && m_nCurrentElement != SAL_MAX_UINT16) + m_xAccessible->ReleaseFocus(m_nCurrentElement); + m_nCurrentElement = nPos; + if (m_xAccessible.is() && m_nCurrentElement != SAL_MAX_UINT16) + m_xAccessible->AcquireFocus(); +} + /** * !pContext => layout only * @@ -357,6 +371,9 @@ void SmElementsControl::LayoutOrPaintContents(vcl::RenderContext *pContext) x += boxX; y = 0; + element->mBoxLocation = Point(x, y); + element->mBoxSize = Size(10, nControlHeight); + tools::Rectangle aSelectionRectangle(x + 5 - 1, y + 5, x + 5 + 1, nControlHeight - 5); @@ -369,6 +386,9 @@ void SmElementsControl::LayoutOrPaintContents(vcl::RenderContext *pContext) x = 0; y += boxY; + element->mBoxLocation = Point(x, y); + element->mBoxSize = Size(nControlWidth, 10); + tools::Rectangle aSelectionRectangle(x + 5, y + 5 - 1, nControlWidth - 5, y + 5 + 1); @@ -603,7 +623,7 @@ void SmElementsControl::MouseButtonDown(const MouseEvent& rMouseEvent) tools::Rectangle rect(pPrevElement->mBoxLocation, pPrevElement->mBoxSize); if (rect.IsInside(rMouseEvent.GetPosPixel())) { - m_nCurrentElement = m_nCurrentRolloverElement; + setCurrentElement(m_nCurrentRolloverElement); maSelectHdlLink.Call(*const_cast<SmElement*>(pPrevElement)); collectUIInformation(OUString::number(m_nCurrentRolloverElement)); return; @@ -617,7 +637,7 @@ void SmElementsControl::MouseButtonDown(const MouseEvent& rMouseEvent) tools::Rectangle rect(element->mBoxLocation, element->mBoxSize); if (rect.IsInside(rMouseEvent.GetPosPixel())) { - m_nCurrentElement = n; + setCurrentElement(n); maSelectHdlLink.Call(*element); collectUIInformation(OUString::number(n)); return; @@ -697,8 +717,8 @@ void SmElementsControl::stepFocus(const bool bBackward) sal_uInt16 nPos = nextElement(bBackward, nStartPos, nLastElement); if (nStartPos != nPos) { - m_nCurrentElement = nPos; m_nCurrentRolloverElement = SAL_MAX_UINT16; + setCurrentElement(nPos); const tools::Rectangle outputRect(Point(0,0), GetOutputSizePixel()); const SmElement *pCur = maElementList[nPos].get(); @@ -752,7 +772,7 @@ void SmElementsControl::pageFocus(const bool bBackward) if (nStartPos != nPos) { - m_nCurrentElement = nPos; + setCurrentElement(nPos); if (bMoved) scrollToElement(bBackward, maElementList[nPos].get()); Invalidate(); @@ -793,12 +813,18 @@ void SmElementsControl::KeyInput(const KeyEvent& rKEvt) break; case KEY_HOME: - m_nCurrentElement = 0; - mxScroll->DoScroll(0); + if (!maElementList.empty()) + { + setCurrentElement(0); + mxScroll->DoScroll(0); + } break; case KEY_END: - m_nCurrentElement = (maElementList.size() ? maElementList.size() - 1 : 0); - mxScroll->DoScroll(mxScroll->GetRangeMax()); + if (!maElementList.empty()) + { + setCurrentElement(maElementList.size() - 1); + mxScroll->DoScroll(mxScroll->GetRangeMax()); + } break; case KEY_PAGEUP: @@ -964,8 +990,21 @@ void SmElementsControl::addElements(const SmElementDescr aElementsArray[], sal_u void SmElementsControl::build() { + // The order is important! + // 1. Ensure there are no items left, including the default scrollbar! + // 2. Release all the current accessible items. + // This will check for new items after releasing them! + // 3. Set the cursor element maElementList.clear(); - + mxScroll->SetThumbPos(0); + mxScroll->Hide(); + if (m_xAccessible.is()) + m_xAccessible->ReleaseAllItems(true); + setCurrentElement(SAL_MAX_UINT16); + + // The first element is the scrollbar. We can't change its indexInParent + // value, as this is set by being a child of the SmElementsControl. + m_nCurrentOffset = 1; for (sal_uInt16 n = 0; n < SAL_N_ELEMENTS(m_aCategories); ++n) { if (msCurrentSetId == std::get<0>(m_aCategories[n])) @@ -973,11 +1012,15 @@ void SmElementsControl::build() addElements(std::get<1>(m_aCategories[n]), std::get<2>(m_aCategories[n])); break; } + else + m_nCurrentOffset += std::get<2>(m_aCategories[n]); } - m_nCurrentElement = 0; m_nCurrentRolloverElement = SAL_MAX_UINT16; LayoutOrPaintContents(); + if (m_xAccessible.is()) + m_xAccessible->AddAllItems(); + setCurrentElement(0); Invalidate(); } @@ -991,6 +1034,96 @@ FactoryFunction SmElementsControl::GetUITestFactory() const return ElementSelectorUIObject::create; } +bool SmElementsControl::itemIsSeparator(sal_uInt16 nPos) const +{ + if (nPos < m_nCurrentOffset || (nPos -= m_nCurrentOffset) >= maElementList.size()) + return true; + return maElementList[nPos].get()->isSeparator(); +} + +css::uno::Reference<css::accessibility::XAccessible> SmElementsControl::CreateAccessible() +{ + if (!m_xAccessible.is()) + { + m_xAccessible = new AccessibleSmElementsControl(*this); + m_xAccessible->AddAllItems(); + } + return m_xAccessible.get(); +} + +bool SmElementsControl::itemTrigger(sal_uInt16 nPos) +{ + if (nPos < m_nCurrentOffset || (nPos -= m_nCurrentOffset) >= maElementList.size()) + return false; + + maSelectHdlLink.Call(*maElementList[nPos].get()); + collectUIInformation(OUString::number(nPos)); + return true; +} + +tools::Rectangle SmElementsControl::itemPosRect(sal_uInt16 nPos) const +{ + if (nPos < m_nCurrentOffset || (nPos -= m_nCurrentOffset) >= maElementList.size()) + return tools::Rectangle(); + + SmElement* pItem = maElementList[nPos].get(); + return tools::Rectangle(pItem->mBoxLocation, pItem->mBoxSize); +} + +bool SmElementsControl::itemIsVisible(sal_uInt16 nPos) const +{ + tools::Rectangle elementRect = itemPosRect(nPos); + if (elementRect.IsEmpty()) + return false; + + tools::Rectangle outputRect(Point(0, 0), GetOutputSizePixel()); + return outputRect.IsInside(elementRect); +} + +sal_uInt16 SmElementsControl::itemCount() const { return maElementList.size(); } + +sal_uInt16 SmElementsControl::itemHighlighted() const { return m_nCurrentElement; } + +void SmElementsControl::setItemHighlighted(sal_uInt16 nPos) +{ + if (m_nCurrentRolloverElement == nPos) + return; + if (nPos != SAL_MAX_UINT16 && nPos >= maElementList.size()) + return; + + if (maElementList[nPos]->isSeparator()) + m_nCurrentRolloverElement = SAL_MAX_UINT16; + else + m_nCurrentRolloverElement = nPos; + Invalidate(); +} + +OUString SmElementsControl::itemName(sal_uInt16 nPos) const +{ + if (nPos < m_nCurrentOffset || (nPos -= m_nCurrentOffset) >= maElementList.size()) + return OUString(); + + return maElementList[nPos]->getHelpText(); +} + +sal_uInt16 SmElementsControl::itemAtPos(const Point& rPoint) const +{ + sal_uInt16 nElementCount = maElementList.size(); + for (sal_uInt16 n = 0; n < nElementCount; n++) + { + const SmElement* pItem = maElementList[n].get(); + tools::Rectangle elementRect(pItem->mBoxLocation, pItem->mBoxSize); + if (elementRect.IsInside(rPoint)) + return n; + } + return SAL_MAX_UINT16; +} + +css::uno::Reference<css::accessibility::XAccessible> SmElementsControl::scrollbarAccessible() const +{ + return mxScroll && mxScroll->IsVisible() ? mxScroll->GetAccessible() : css::uno::Reference<css::accessibility::XAccessible>(); +} + SmElementsDockingWindow::SmElementsDockingWindow(SfxBindings* pInputBindings, SfxChildWindow* pChildWindow, vcl::Window* pParent) : SfxDockingWindow(pInputBindings, pChildWindow, pParent, "DockingElements", "modules/smath/ui/dockingelements.ui") |