summaryrefslogtreecommitdiff
path: root/starmath
diff options
context:
space:
mode:
authorJan-Marek Glogowski <glogow@fbihome.de>2019-05-26 14:53:33 +0000
committerJan-Marek Glogowski <glogow@fbihome.de>2019-05-29 20:14:38 +0200
commita7e52282e36987f4ca6bed968e87ada6849b10e8 (patch)
tree891e7dd4e986528d55e6866801221273a87a3e17 /starmath
parent3eba9602197da972b66f2b7cc72b61cbdffe5a52 (diff)
tdf#65587 SM implement ElementControl accessibility
This took me ages to implement. I'm still not 100% sure, it works correct. One main problem was the loop where the ATK listener will rebuild the list of children based on the current child count. Then there is the "broken" SPI bridge behaviour. I could actually test this with the gtk3 backend just fine, if I started LO *after* the accerciser. Otherwise the displayed tree will be really broken and the add and remove child events won't be correctly processed, because some Windows in the hierarchy will return a negative parent index. And generally the accerciser has various problems, with most result in Python backtraces an inconsistent app state, but even SIGSEGV happened a few time. Already have some patches for the easy reproducible ones. No idea what will happen on any other setup then Linux with ATK. Change-Id: I3280fd8622966be74e3833621952d95a2671d214 Reviewed-on: https://gerrit.libreoffice.org/73077 Tested-by: Jenkins Reviewed-by: Jan-Marek Glogowski <glogow@fbihome.de>
Diffstat (limited to 'starmath')
-rw-r--r--starmath/Library_sm.mk2
-rw-r--r--starmath/inc/AccessibleSmElement.hxx107
-rw-r--r--starmath/inc/AccessibleSmElementsControl.hxx116
-rw-r--r--starmath/inc/ElementsDockingWindow.hxx20
-rw-r--r--starmath/source/AccessibleSmElement.cxx290
-rw-r--r--starmath/source/AccessibleSmElementsControl.cxx457
-rw-r--r--starmath/source/ElementsDockingWindow.cxx155
7 files changed, 1136 insertions, 11 deletions
diff --git a/starmath/Library_sm.mk b/starmath/Library_sm.mk
index d87039dc8567..9848e103ac23 100644
--- a/starmath/Library_sm.mk
+++ b/starmath/Library_sm.mk
@@ -62,6 +62,8 @@ $(eval $(call gb_Library_use_libraries,sm,\
))
$(eval $(call gb_Library_add_exception_objects,sm,\
+ starmath/source/AccessibleSmElement \
+ starmath/source/AccessibleSmElementsControl \
starmath/source/ElementsDockingWindow \
starmath/source/accessibility \
starmath/source/action \
diff --git a/starmath/inc/AccessibleSmElement.hxx b/starmath/inc/AccessibleSmElement.hxx
new file mode 100644
index 000000000000..9b168bbee4cb
--- /dev/null
+++ b/starmath/inc/AccessibleSmElement.hxx
@@ -0,0 +1,107 @@
+/* -*- 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 .
+ */
+#ifndef INCLUDED_STARMATH_INC_ACCESSIBLESMELEMENT_HXX
+#define INCLUDED_STARMATH_INC_ACCESSIBLESMELEMENT_HXX
+
+#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/XAccessibleStateSet.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/implbase3.hxx>
+#include <comphelper/accessiblecomponenthelper.hxx>
+#include <sal/types.h>
+#include <vcl/vclptr.hxx>
+
+class SmElementsControl;
+
+typedef ::cppu::ImplHelper3<css::lang::XServiceInfo, css::accessibility::XAccessible,
+ css::accessibility::XAccessibleAction>
+ AccessibleSmElement_BASE;
+
+class AccessibleSmElement final : public comphelper::OAccessibleComponentHelper,
+ public AccessibleSmElement_BASE
+{
+ VclPtr<SmElementsControl> m_pSmElementsControl;
+ const sal_Int32 m_nIndexInParent; ///< index in the parent XAccessible
+ const sal_uInt16 m_nItemId; ///< index in the SmElementsControl
+ bool m_bHasFocus;
+ sal_Int16 m_nRole;
+
+ ~AccessibleSmElement() override;
+ void SAL_CALL disposing() override;
+ css::awt::Rectangle implGetBounds() override;
+
+ void testAction(sal_Int32) const;
+
+public:
+ explicit AccessibleSmElement(SmElementsControl* pSmElementsControl, sal_uInt16 nItemId,
+ sal_Int32 nIndexInParent);
+
+ void SetFocus(bool _bFocus);
+ bool HasFocus() const { return m_bHasFocus; }
+ void ReleaseSmElementsControl() { m_pSmElementsControl = nullptr; }
+ sal_uInt16 itemId() const { return m_nItemId; }
+
+ DECLARE_XINTERFACE()
+ DECLARE_XTYPEPROVIDER()
+
+ // XAccessible
+ css::uno::Reference<css::accessibility::XAccessibleContext>
+ SAL_CALL getAccessibleContext() override;
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override;
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XAccessibleContext
+ sal_Int32 SAL_CALL getAccessibleChildCount() override;
+ css::uno::Reference<css::accessibility::XAccessible>
+ SAL_CALL getAccessibleChild(sal_Int32 i) override;
+ css::uno::Reference<css::accessibility::XAccessible> SAL_CALL getAccessibleParent() override;
+ sal_Int32 SAL_CALL getAccessibleIndexInParent() override;
+ sal_Int16 SAL_CALL getAccessibleRole() override;
+ OUString SAL_CALL getAccessibleDescription() override;
+ OUString SAL_CALL getAccessibleName() override;
+ css::uno::Reference<css::accessibility::XAccessibleRelationSet>
+ SAL_CALL getAccessibleRelationSet() override;
+ css::uno::Reference<css::accessibility::XAccessibleStateSet>
+ SAL_CALL getAccessibleStateSet() override;
+
+ // XAccessibleComponent
+ css::uno::Reference<css::accessibility::XAccessible>
+ SAL_CALL getAccessibleAtPoint(const css::awt::Point& aPoint) override;
+ void SAL_CALL grabFocus() override;
+ sal_Int32 SAL_CALL getForeground() override;
+ sal_Int32 SAL_CALL getBackground() override;
+
+ // XAccessibleAction
+ sal_Int32 SAL_CALL getAccessibleActionCount() override;
+ sal_Bool SAL_CALL doAccessibleAction(sal_Int32 nIndex) override;
+ OUString SAL_CALL getAccessibleActionDescription(sal_Int32 nIndex) override;
+ css::uno::Reference<css::accessibility::XAccessibleKeyBinding>
+ SAL_CALL getAccessibleActionKeyBinding(sal_Int32 nIndex) override;
+};
+
+#endif // INCLUDED_STARMATH_INC_ACCESSIBLESMELEMENT_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/starmath/inc/AccessibleSmElementsControl.hxx b/starmath/inc/AccessibleSmElementsControl.hxx
new file mode 100644
index 000000000000..d38d57dc92c2
--- /dev/null
+++ b/starmath/inc/AccessibleSmElementsControl.hxx
@@ -0,0 +1,116 @@
+/* -*- 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 .
+ */
+#ifndef INCLUDED_STARMATH_INC_ACCESSIBLESMELEMENTSCONTROL_HXX
+#define INCLUDED_STARMATH_INC_ACCESSIBLESMELEMENTSCONTROL_HXX
+
+#include <comphelper/accessiblecomponenthelper.hxx>
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/implbase3.hxx>
+#include <vcl/vclptr.hxx>
+
+#include <vector>
+
+class AccessibleSmElement;
+class SmElementsControl;
+
+typedef ::cppu::ImplHelper3<css::lang::XServiceInfo, css::accessibility::XAccessible,
+ css::accessibility::XAccessibleSelection>
+ AccessibleSmElementsControl_BASE;
+
+class AccessibleSmElementsControl final : public comphelper::OAccessibleComponentHelper,
+ public AccessibleSmElementsControl_BASE
+{
+ std::vector<rtl::Reference<AccessibleSmElement>> m_aAccessibleChildren;
+ VclPtr<SmElementsControl> m_pControl;
+
+ AccessibleSmElement* GetItem_Impl(sal_uInt16 _nPos);
+ void ReleaseFocus_Impl(sal_uInt16 _nPos);
+ sal_Int32 implGetAccessibleChildCount();
+ void ReleaseItems(bool bNotifyRemoval);
+ void UpdateFocus(sal_uInt16);
+ inline void TestControl();
+
+ ~AccessibleSmElementsControl() override;
+ void SAL_CALL disposing() override;
+ css::awt::Rectangle implGetBounds() override;
+
+public:
+ AccessibleSmElementsControl(SmElementsControl& rControl);
+
+ void ReleaseAllItems(bool bNotify);
+ void AddAllItems();
+ inline void AcquireFocus();
+ inline void ReleaseFocus(sal_uInt16);
+
+ DECLARE_XINTERFACE()
+ DECLARE_XTYPEPROVIDER()
+
+ // XAccessible
+ css::uno::Reference<css::accessibility::XAccessibleContext>
+ SAL_CALL getAccessibleContext() override;
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XAccessibleComponent
+ sal_Bool SAL_CALL containsPoint(const css::awt::Point& aPoint) override;
+ css::uno::Reference<css::accessibility::XAccessible>
+ SAL_CALL getAccessibleAtPoint(const css::awt::Point& aPoint) override;
+ css::awt::Rectangle SAL_CALL getBounds() override;
+ css::awt::Point SAL_CALL getLocation() override;
+ css::awt::Point SAL_CALL getLocationOnScreen() override;
+ css::awt::Size SAL_CALL getSize() override;
+ void SAL_CALL grabFocus() override;
+ sal_Int32 SAL_CALL getForeground() override;
+ sal_Int32 SAL_CALL getBackground() override;
+
+ // XAccessibleContext
+ sal_Int32 SAL_CALL getAccessibleChildCount() override;
+ css::uno::Reference<css::accessibility::XAccessible>
+ SAL_CALL getAccessibleChild(sal_Int32 i) override;
+ css::uno::Reference<css::accessibility::XAccessible> SAL_CALL getAccessibleParent() override;
+ sal_Int16 SAL_CALL getAccessibleRole() override;
+ OUString SAL_CALL getAccessibleDescription() override;
+ OUString SAL_CALL getAccessibleName() override;
+ css::uno::Reference<css::accessibility::XAccessibleRelationSet>
+ SAL_CALL getAccessibleRelationSet() override;
+ css::uno::Reference<css::accessibility::XAccessibleStateSet>
+ SAL_CALL getAccessibleStateSet() override;
+
+ // XAccessibleSelection
+ void SAL_CALL selectAccessibleChild(sal_Int32 nChildIndex) override;
+ sal_Bool SAL_CALL isAccessibleChildSelected(sal_Int32 nChildIndex) override;
+ void SAL_CALL clearAccessibleSelection() override;
+ void SAL_CALL selectAllAccessibleChildren() override;
+ sal_Int32 SAL_CALL getSelectedAccessibleChildCount() override;
+ css::uno::Reference<css::accessibility::XAccessible>
+ SAL_CALL getSelectedAccessibleChild(sal_Int32 nSelectedChildIndex) override;
+ void SAL_CALL deselectAccessibleChild(sal_Int32 nChildIndex) override;
+};
+
+void AccessibleSmElementsControl::AcquireFocus() { UpdateFocus(SAL_MAX_UINT16); }
+
+void AccessibleSmElementsControl::ReleaseFocus(sal_uInt16 nPos) { UpdateFocus(nPos); }
+
+#endif // INCLUDED_STARMATH_INC_ACCESSIBLESMELEMENTSCONTROL_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/starmath/inc/ElementsDockingWindow.hxx b/starmath/inc/ElementsDockingWindow.hxx
index 0fdb3fc72369..aaa992b97f77 100644
--- a/starmath/inc/ElementsDockingWindow.hxx
+++ b/starmath/inc/ElementsDockingWindow.hxx
@@ -27,6 +27,8 @@
#include <memory>
#include <tuple>
+#include "AccessibleSmElementsControl.hxx"
+
class SmDocShell;
class SmNode;
@@ -88,12 +90,14 @@ class SmElementsControl : public Control
virtual void GetFocus() override;
virtual void LoseFocus() override;
virtual void KeyInput(const KeyEvent& rKEvt) override;
+ css::uno::Reference<css::accessibility::XAccessible> CreateAccessible() override;
SmDocShell* mpDocShell;
SmFormat maFormat;
OString msCurrentSetId;
sal_uInt16 m_nCurrentElement;
sal_uInt16 m_nCurrentRolloverElement;
+ sal_uInt16 m_nCurrentOffset;
Link<SmElement&,void> maSelectHdlLink;
std::vector< std::unique_ptr<SmElement> > maElementList;
@@ -101,10 +105,12 @@ class SmElementsControl : public Control
bool mbVerticalMode;
VclPtr< ScrollBar > mxScroll;
bool m_bFirstPaintAfterLayout;
+ rtl::Reference<AccessibleSmElementsControl> m_xAccessible;
void addElement(const OUString& aElementVisual, const OUString& aElementSource, const OUString& aHelpText);
void addElements(const SmElementDescr aElementsArray[], sal_uInt16 size);
SmElement* current() const;
+ void setCurrentElement(sal_uInt16);
bool hasRollover() const { return m_nCurrentRolloverElement != SAL_MAX_UINT16; }
void stepFocus(const bool bBackward);
@@ -126,10 +132,24 @@ public:
static const auto& categories() { return m_aCategories; }
static size_t categoriesSize() { return m_aCategoriesSize; }
+ OString elementSetId() const { return msCurrentSetId; }
void setElementSetId(const char* pSetId);
void setVerticalMode(bool bVertical);
+ sal_uInt16 itemCount() const;
+ sal_uInt16 itemHighlighted() const;
+ sal_uInt16 itemFocused() const;
+ sal_uInt16 itemAtPos(const Point& rPos) const;
+ tools::Rectangle itemPosRect(sal_uInt16) const;
+ bool itemIsSeparator(sal_uInt16) const;
+ bool itemIsVisible(sal_uInt16) const;
+ OUString itemName(sal_uInt16) const;
+ bool itemTrigger(sal_uInt16);
+ void setItemHighlighted(sal_uInt16);
+ sal_uInt16 itemOffset() const { return m_nCurrentOffset; }
+ css::uno::Reference<css::accessibility::XAccessible> scrollbarAccessible() const;
+
Size GetOptimalSize() const override;
DECL_LINK( ScrollHdl, ScrollBar*, void );
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")