desktop/qa/desktop_lib/test_desktop_lib.cxx |    4 
 desktop/source/lib/init.cxx                 |   17 +
 include/LibreOfficeKit/LibreOfficeKit.h     |    3 
 include/sfx2/lokhelper.hxx                  |    2 
 include/sfx2/viewsh.hxx                     |    7 
 sfx2/source/view/lokhelper.cxx              |   14 
 sfx2/source/view/viewsh.cxx                 |  410 ++++++++++++++++++++++++++++
 7 files changed, 454 insertions(+), 3 deletions(-)

New commits:
commit 190f7caa9e5c565168a45fd198585526573d966d
Author:     Marco Cecchetti <[email protected]>
AuthorDate: Thu Mar 23 08:33:16 2023 +0100
Commit:     Marco Cecchetti <[email protected]>
CommitDate: Fri May 5 08:55:06 2023 +0200

    lok: accessibility event listener for focused paragraph
    
    LOKDocumentFocusListener keeps track of the currently focused
    paragraph.
    
    Change-Id: I0fa400694f3129608228ade0b96e0b4e0aee87e2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151363
    Reviewed-by: Michael Meeks <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>

diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx 
b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 3f5ca1f96fb4..55ef248ec932 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -3640,9 +3640,11 @@ void DesktopLOKTest::testABI()
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(67), offsetof(struct 
_LibreOfficeKitDocumentClass, getEditMode));
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(68),
                          offsetof(struct _LibreOfficeKitDocumentClass, 
setViewTimezone));
+    CPPUNIT_ASSERT_EQUAL(documentClassOffset(69),
+                         offsetof(struct _LibreOfficeKitDocumentClass, 
setAccessibilityState));
 
     // As above
-    CPPUNIT_ASSERT_EQUAL(documentClassOffset(69), sizeof(struct 
_LibreOfficeKitDocumentClass));
+    CPPUNIT_ASSERT_EQUAL(documentClassOffset(70), sizeof(struct 
_LibreOfficeKitDocumentClass));
 }
 
 CPPUNIT_TEST_SUITE_REGISTRATION(DesktopLOKTest);
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 949af11504ed..b3350be8e8aa 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -1311,6 +1311,7 @@ static void 
doc_sendContentControlEvent(LibreOfficeKitDocument* pThis, const cha
 
 static void doc_setViewTimezone(LibreOfficeKitDocument* pThis, int nId, const 
char* timezone);
 
+static void doc_setAccessibilityState(LibreOfficeKitDocument* pThis, int nId, 
bool bEnabled);
 } // extern "C"
 
 namespace {
@@ -1460,6 +1461,8 @@ LibLODocument_Impl::LibLODocument_Impl(uno::Reference 
<css::lang::XComponent> xC
 
         m_pDocumentClass->setViewTimezone = doc_setViewTimezone;
 
+        m_pDocumentClass->setAccessibilityState = doc_setAccessibilityState;
+
         gDocumentClass = m_pDocumentClass;
     }
     pClass = m_pDocumentClass.get();
@@ -6398,12 +6401,13 @@ static void doc_setViewLanguage(SAL_UNUSED_PARAMETER 
LibreOfficeKitDocument* /*p
     SolarMutexGuard aGuard;
     SetLastExceptionMsg();
 
+    SAL_DEBUG("doc_setViewLanguage: nId: " << nId);
     OUString sLanguage = OStringToOUString(language, RTL_TEXTENCODING_UTF8);
     SfxLokHelper::setViewLanguage(nId, sLanguage);
     SfxLokHelper::setViewLocale(nId, sLanguage);
-}
-
 
+    SfxLokHelper::setAccessibilityState(nId, true);
+}
 
 unsigned char* doc_renderFont(LibreOfficeKitDocument* pThis,
                               const char* pFontName,
@@ -6946,6 +6950,15 @@ static void doc_setViewTimezone(SAL_UNUSED_PARAMETER 
LibreOfficeKitDocument* /*p
     }
 }
 
+static void doc_setAccessibilityState(SAL_UNUSED_PARAMETER 
LibreOfficeKitDocument* /*pThis*/, int nId, bool nEnabled)
+{
+    SolarMutexGuard aGuard;
+    if (gImpl)
+        gImpl->maLastExceptionMsg.clear();
+
+    SfxLokHelper::setAccessibilityState(nId, nEnabled);
+}
+
 static char* lo_getError (LibreOfficeKit *pThis)
 {
     comphelper::ProfileZone aZone("lo_getError");
diff --git a/include/LibreOfficeKit/LibreOfficeKit.h 
b/include/LibreOfficeKit/LibreOfficeKit.h
index 767469666fef..30089bb11e0d 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/include/LibreOfficeKit/LibreOfficeKit.h
@@ -493,6 +493,9 @@ struct _LibreOfficeKitDocumentClass
     /// @see lok::Document::setViewTimezone().
     void (*setViewTimezone) (LibreOfficeKitDocument* pThis, int nId, const 
char* timezone);
 
+    /// @see lok::Document::setAccessibilityState().
+    void (*setAccessibilityState) (LibreOfficeKitDocument* pThis, int nId, 
bool nEnabled);
+
 #endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY
 };
 
diff --git a/include/sfx2/lokhelper.hxx b/include/sfx2/lokhelper.hxx
index 184f899880f7..d2adacad55e6 100644
--- a/include/sfx2/lokhelper.hxx
+++ b/include/sfx2/lokhelper.hxx
@@ -83,6 +83,8 @@ public:
     static void setViewLanguage(int nId, const OUString& rBcp47LanguageTag);
     /// Set the default language for views.
     static void setDefaultLanguage(const OUString& rBcp47LanguageTag);
+    /// Enable/Disable AT support for the given view.
+    static void setAccessibilityState(int nId, bool nEnabled);
     /// Get the language used by the loading view (used for all save 
operations).
     static const LanguageTag & getLoadLanguage();
     /// Set the language used by the loading view (used for all save 
operations).
diff --git a/include/sfx2/viewsh.hxx b/include/sfx2/viewsh.hxx
index c34e1a69640b..3b0bc9bdcaae 100644
--- a/include/sfx2/viewsh.hxx
+++ b/include/sfx2/viewsh.hxx
@@ -56,6 +56,7 @@ class SfxPrinter;
 class NotifyEvent;
 class SfxInPlaceClient;
 class SfxLokCallbackInterface;
+class LOKDocumentFocusListener;
 class SfxStoringHelper;
 namespace rtl { class OStringBuffer; }
 namespace vcl { class PrinterController; }
@@ -169,6 +170,8 @@ friend class SfxPrinterController;
     LanguageTag                 maLOKLanguageTag;
     LanguageTag                 maLOKLocale;
     LOKDeviceFormFactor         maLOKDeviceFormFactor;
+    bool                        mbLOKAccessibilityEnabled;
+    std::unique_ptr<LOKDocumentFocusListener>   mpLOKDocumentFocusListener;
     std::unordered_set<OUString>    mvLOKBlockedCommandList;
     OUString maLOKTimezone;
     bool maLOKIsTimezoneSet;
@@ -208,6 +211,8 @@ private:
     /// SfxInterface initializer.
     static void InitInterface_Impl();
 
+    LOKDocumentFocusListener& GetLOKDocumentFocusListener();
+
 public:
 
                                 SfxViewShell( SfxViewFrame *pFrame, 
SfxViewShellFlags nFlags );
@@ -405,6 +410,8 @@ public:
     void SetLOKLanguageTag(const OUString& rBcp47LanguageTag);
     /// Get the LibreOfficeKit language of this view.
     const LanguageTag& GetLOKLanguageTag() const { return maLOKLanguageTag; }
+    /// Enable/Disable LibreOfficeKit AT support for this view.
+    void SetLOKAccessibilityState(bool bEnabled);
 
     /// Get the LibreOfficeKit timezone of this view. See @SetLOKTimezone.
     std::pair<bool, OUString> GetLOKTimezone() const
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index b66ad6d05b83..91c2e3830c99 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -314,6 +314,20 @@ void SfxLokHelper::setViewLanguage(int nId, const 
OUString& rBcp47LanguageTag)
     }
 }
 
+void SfxLokHelper::setAccessibilityState(int nId, bool nEnabled)
+{
+    std::vector<SfxViewShell*>& rViewArr = SfxGetpApp()->GetViewShells_Impl();
+
+    for (SfxViewShell* pViewShell : rViewArr)
+    {
+        if (pViewShell->GetViewShellId() == ViewShellId(nId))
+        {
+            pViewShell->SetLOKAccessibilityState(nEnabled);
+            return;
+        }
+    }
+}
+
 void SfxLokHelper::setViewLocale(int nId, const OUString& rBcp47LanguageTag)
 {
     std::vector<SfxViewShell*>& rViewArr = SfxGetpApp()->GetViewShells_Impl();
diff --git a/sfx2/source/view/viewsh.cxx b/sfx2/source/view/viewsh.cxx
index 9ae31f66e43e..221e41080562 100644
--- a/sfx2/source/view/viewsh.cxx
+++ b/sfx2/source/view/viewsh.cxx
@@ -46,9 +46,22 @@
 #include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
 #include <com/sun/star/view/XRenderable.hpp>
 #include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/XAccessibleText.hpp>
 #include <cppuhelper/implbase.hxx>
 #include <com/sun/star/ui/XAcceleratorConfiguration.hpp>
 
+#include <cppuhelper/weakref.hxx>
+
+#include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp>
+#include <com/sun/star/accessibility/AccessibleTextType.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+
 #include <comphelper/diagnose_ex.hxx>
 #include <tools/urlobj.hxx>
 #include <unotools/tempfile.hxx>
@@ -220,6 +233,350 @@ void SAL_CALL 
SfxClipboardChangeListener::changedContents( const datatransfer::c
         delete pInfo;
 }
 
+class LOKDocumentFocusListener :
+    public ::cppu::WeakImplHelper< accessibility::XAccessibleEventListener >
+{
+
+    std::set< uno::Reference< uno::XInterface > > m_aRefList;
+
+public:
+    /// @throws lang::IndexOutOfBoundsException
+    /// @throws uno::RuntimeException
+    void attachRecursive(
+        const uno::Reference< accessibility::XAccessible >& xAccessible
+    );
+
+    /// @throws lang::IndexOutOfBoundsException
+    /// @throws uno::RuntimeException
+    void attachRecursive(
+        const uno::Reference< accessibility::XAccessible >& xAccessible,
+        const uno::Reference< accessibility::XAccessibleContext >& xContext
+    );
+
+    /// @throws lang::IndexOutOfBoundsException
+    /// @throws uno::RuntimeException
+    void attachRecursive(
+        const uno::Reference< accessibility::XAccessible >& xAccessible,
+        const uno::Reference< accessibility::XAccessibleContext >& xContext,
+        const sal_Int64 nStateSet
+    );
+
+    /// @throws lang::IndexOutOfBoundsException
+    /// @throws uno::RuntimeException
+    void detachRecursive(
+        const uno::Reference< accessibility::XAccessible >& xAccessible
+    );
+
+    /// @throws lang::IndexOutOfBoundsException
+    /// @throws uno::RuntimeException
+    void detachRecursive(
+        const uno::Reference< accessibility::XAccessibleContext >& xContext
+    );
+
+    /// @throws lang::IndexOutOfBoundsException
+    /// @throws uno::RuntimeException
+    void detachRecursive(
+        const uno::Reference< accessibility::XAccessibleContext >& xContext,
+        const sal_Int64 nStateSet
+    );
+
+    /// @throws lang::IndexOutOfBoundsException
+    /// @throws uno::RuntimeException
+    static uno::Reference< accessibility::XAccessible > getAccessible(const 
lang::EventObject& aEvent );
+
+    // XEventListener
+    virtual void SAL_CALL disposing( const lang::EventObject& Source ) 
override;
+
+    // XAccessibleEventListener
+    virtual void SAL_CALL notifyEvent( const 
accessibility::AccessibleEventObject& aEvent ) override;
+
+};
+
+void LOKDocumentFocusListener::disposing( const lang::EventObject& aEvent )
+{
+
+    // Unref the object here, but do not remove as listener since the object
+    // might no longer be in a state that safely allows this.
+    if( aEvent.Source.is() )
+        m_aRefList.erase(aEvent.Source);
+
+}
+
+void LOKDocumentFocusListener::notifyEvent( const 
accessibility::AccessibleEventObject& aEvent )
+{
+    SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent:event id: " << 
aEvent.EventId);
+    try {
+        switch( aEvent.EventId )
+        {
+            case accessibility::AccessibleEventId::STATE_CHANGED:
+            {
+                sal_Int16 nState = accessibility::AccessibleStateType::INVALID;
+                aEvent.NewValue >>= nState;
+                SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: 
STATE_CHANGED: XAccessible: " << getAccessible(aEvent).get());
+
+                if( accessibility::AccessibleStateType::FOCUSED == nState )
+                {
+                    SAL_INFO("lok.a11y", 
"LOKDocumentFocusListener::notifyEvent: FOCUSED");
+
+                    uno::Reference<css::accessibility::XAccessibleText> 
xAccText(getAccessible(aEvent), uno::UNO_QUERY);
+                    if( xAccText.is() )
+                    {
+                        OUString sText = xAccText->getText();
+                        sal_Int32 nLength = sText.getLength();
+                        SAL_INFO("lok.a11y", 
"LOKDocumentFocusListener::notifyEvent: xAccText: " << xAccText.get() << ", 
text: " << sText);
+
+                        if (nLength)
+                        {
+                            
css::uno::Reference<css::accessibility::XAccessibleTextAttributes> 
xAccTextAttr(xAccText, uno::UNO_QUERY);
+                            css::uno::Sequence< OUString > 
aRequestedAttributes;
+
+                            sal_Int32 nPos = 0;
+                            while (nPos < nLength)
+                            {
+                                css::accessibility::TextSegment aTextSegment =
+                                        xAccText->getTextAtIndex(nPos, 
css::accessibility::AccessibleTextType::ATTRIBUTE_RUN);
+                                SAL_INFO("lok.a11y", 
"LOKDocumentFocusListener::notifyEvent: text segment: '" << 
aTextSegment.SegmentText
+                                        << "', start: " << 
aTextSegment.SegmentStart << ", end: " << aTextSegment.SegmentEnd);
+
+                                css::uno::Sequence< css::beans::PropertyValue 
> aRunAttributeList;
+                                if (xAccTextAttr.is())
+                                {
+                                    aRunAttributeList = 
xAccTextAttr->getRunAttributes(nPos, aRequestedAttributes);
+                                }
+                                else
+                                {
+                                    aRunAttributeList = 
xAccText->getCharacterAttributes(nPos, aRequestedAttributes);
+                                }
+
+                                sal_Int32 nSize = 
aRunAttributeList.getLength();
+                                SAL_INFO("lok.a11y", 
"LOKDocumentFocusListener::notifyEvent: attribute list size: " << nSize);
+                                if (nSize)
+                                {
+                                    OUString sValue;
+                                    OUString sAttributes = "{ ";
+                                    for (const auto& attribute: 
aRunAttributeList)
+                                    {
+                                        if (attribute.Name.isEmpty())
+                                            continue;
+
+                                        if (attribute.Name == "CharHeight" || 
attribute.Name == "CharWeight")
+                                        {
+                                            float fValue;
+                                            attribute.Value >>= fValue;
+                                            sValue = OUString::number(fValue);
+                                        }
+                                        else if (attribute.Name == 
"CharPosture")
+                                        {
+                                            awt::FontSlant nValue;
+                                            attribute.Value >>= nValue;
+                                            sValue = 
OUString::number((unsigned int)(nValue));
+                                        }
+                                        else if (attribute.Name == 
"CharUnderline")
+                                        {
+                                            sal_Int16 nValue;
+                                            attribute.Value >>= nValue;
+                                            sValue = OUString::number(nValue);
+                                        }
+                                        else if (attribute.Name == 
"CharFontName")
+                                        {
+                                            attribute.Value >>= sValue;
+                                        }
+                                        else if (attribute.Name == "Rsid")
+                                        {
+                                            sal_uInt32 nValue;
+                                            attribute.Value >>= nValue;
+                                            sValue = OUString::number(nValue);
+                                        }
+
+                                        if (!sValue.isEmpty())
+                                        {
+                                            if (sAttributes != "{ ")
+                                                sAttributes += ", ";
+                                            sAttributes += attribute.Name + ": 
";
+                                            sAttributes += sValue;
+                                            sValue = "";
+                                        }
+                                    }
+                                    sAttributes += " }";
+                                    SAL_INFO("lok.a11y", 
"LOKDocumentFocusListener::notifyEvent: attributes: " << sAttributes);
+                                    }
+                                nPos = aTextSegment.SegmentEnd + 1;
+                            }
+                        }
+
+                    }
+                }
+
+                break;
+            }
+
+            case accessibility::AccessibleEventId::CHILD:
+            {
+                uno::Reference< accessibility::XAccessible > xChild;
+                if( (aEvent.OldValue >>= xChild) && xChild.is() )
+                    detachRecursive(xChild);
+
+                if( (aEvent.NewValue >>= xChild) && xChild.is() )
+                    attachRecursive(xChild);
+
+                break;
+            }
+
+            case accessibility::AccessibleEventId::INVALIDATE_ALL_CHILDREN:
+                SAL_INFO("lok.a11y", "Invalidate all children called");
+                break;
+
+            default:
+                break;
+        }
+    }
+    catch( const lang::IndexOutOfBoundsException& e )
+    {
+        SAL_WARN("lok.a11y", "Focused object has invalid index in parent");
+    }
+}
+
+uno::Reference< accessibility::XAccessible > 
LOKDocumentFocusListener::getAccessible(const lang::EventObject& aEvent )
+{
+    uno::Reference< accessibility::XAccessible > xAccessible(aEvent.Source, 
uno::UNO_QUERY);
+
+    if( xAccessible.is() )
+        return xAccessible;
+
+    uno::Reference< accessibility::XAccessibleContext > 
xContext(aEvent.Source, uno::UNO_QUERY);
+
+    if( xContext.is() )
+    {
+        uno::Reference< accessibility::XAccessible > xParent( 
xContext->getAccessibleParent() );
+        if( xParent.is() )
+        {
+            uno::Reference< accessibility::XAccessibleContext > 
xParentContext( xParent->getAccessibleContext() );
+            if( xParentContext.is() )
+            {
+                return xParentContext->getAccessibleChild( 
xContext->getAccessibleIndexInParent() );
+            }
+        }
+    }
+
+    return uno::Reference< accessibility::XAccessible >();
+}
+
+void LOKDocumentFocusListener::attachRecursive(
+    const uno::Reference< accessibility::XAccessible >& xAccessible
+)
+{
+    SAL_INFO("lok.a11y", "LOKDocumentFocusListener::attachRecursive(1): 
xAccessible: " << xAccessible.get());
+
+    uno::Reference< accessibility::XAccessibleContext > xContext =
+        xAccessible->getAccessibleContext();
+
+    if( xContext.is() )
+        attachRecursive(xAccessible, xContext);
+}
+
+void LOKDocumentFocusListener::attachRecursive(
+    const uno::Reference< accessibility::XAccessible >& xAccessible,
+    const uno::Reference< accessibility::XAccessibleContext >& xContext
+)
+{
+    SAL_INFO("lok.a11y", "LOKDocumentFocusListener::attachRecursive(2): 
xAccessible: " << xAccessible.get()
+            << ", role: " << xContext->getAccessibleRole()
+            << ", name: " << xContext->getAccessibleName()
+            << ", parent: " << xContext->getAccessibleParent().get()
+            << ", child count: " << xContext->getAccessibleChildCount());
+
+    sal_Int64 nStateSet = xContext->getAccessibleStateSet();
+
+    attachRecursive(xAccessible, xContext, nStateSet);
+}
+
+void LOKDocumentFocusListener::attachRecursive(
+    const uno::Reference< accessibility::XAccessible >& xAccessible,
+    const uno::Reference< accessibility::XAccessibleContext >& xContext,
+    const sal_Int64 nStateSet
+)
+{
+    SAL_INFO("lok.a11y", "LOKDocumentFocusListener::attachRecursive(3) #1: 
this: " << this
+            << ", xAccessible: " << xAccessible.get()
+            << ", role: " << xContext->getAccessibleRole()
+            << ", name: " << xContext->getAccessibleName()
+            << ", parent: " << xContext->getAccessibleParent().get()
+            << ", child count: " << xContext->getAccessibleChildCount());
+
+    uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster =
+        uno::Reference< accessibility::XAccessibleEventBroadcaster >(xContext, 
uno::UNO_QUERY);
+
+    if (!xBroadcaster.is())
+        return;
+    SAL_INFO("lok.a11y", "LOKDocumentFocusListener::attachRecursive(3) #2: 
xBroadcaster.is()");
+    // If not already done, add the broadcaster to the list and attach as 
listener.
+    const uno::Reference< uno::XInterface >& xInterface = xBroadcaster;
+    if( m_aRefList.insert(xInterface).second )
+    {
+        SAL_INFO("lok.a11y", "LOKDocumentFocusListener::attachRecursive(3) #3: 
m_aRefList.insert(xInterface).second");
+        xBroadcaster->addAccessibleEventListener(static_cast< 
accessibility::XAccessibleEventListener *>(this));
+
+        const sal_Int32 MAX_ATTACHABLE_CHILDREN = 10;
+        sal_Int32 n, nmax = xContext->getAccessibleChildCount();
+        if( ( nStateSet & 
accessibility::AccessibleStateType::MANAGES_DESCENDANTS ) && nmax > 
MAX_ATTACHABLE_CHILDREN )
+            nmax = MAX_ATTACHABLE_CHILDREN;
+
+        for( n = 0; n < nmax; n++ )
+        {
+            uno::Reference< accessibility::XAccessible > xChild( 
xContext->getAccessibleChild( n ) );
+
+            if( xChild.is() )
+                attachRecursive(xChild);
+        }
+    }
+}
+
+void LOKDocumentFocusListener::detachRecursive(
+    const uno::Reference< accessibility::XAccessible >& xAccessible
+)
+{
+    uno::Reference< accessibility::XAccessibleContext > xContext =
+        xAccessible->getAccessibleContext();
+
+    if( xContext.is() )
+        detachRecursive(xContext);
+}
+
+void LOKDocumentFocusListener::detachRecursive(
+    const uno::Reference< accessibility::XAccessibleContext >& xContext
+)
+{
+    sal_Int64 nStateSet = xContext->getAccessibleStateSet();
+
+   detachRecursive(xContext, nStateSet);
+}
+
+void LOKDocumentFocusListener::detachRecursive(
+    const uno::Reference< accessibility::XAccessibleContext >& xContext,
+    const sal_Int64 nStateSet
+)
+{
+    uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster =
+        uno::Reference< accessibility::XAccessibleEventBroadcaster >(xContext, 
uno::UNO_QUERY);
+
+    if( xBroadcaster.is() && 0 < m_aRefList.erase(xBroadcaster) )
+    {
+        xBroadcaster->removeAccessibleEventListener(static_cast< 
accessibility::XAccessibleEventListener *>(this));
+
+        if( ( nStateSet & 
accessibility::AccessibleStateType::MANAGES_DESCENDANTS ) == 0 )
+        {
+            sal_Int32 n, nmax = xContext->getAccessibleChildCount();
+            for( n = 0; n < nmax; n++ )
+            {
+                uno::Reference< accessibility::XAccessible > xChild( 
xContext->getAccessibleChild( n ) );
+
+                if( xChild.is() )
+                    detachRecursive(xChild);
+            }
+        }
+    }
+}
+
 sal_uInt32 SfxViewShell_Impl::m_nLastViewShellId = 0;
 
 SfxViewShell_Impl::SfxViewShell_Impl(SfxViewShellFlags const nFlags, 
ViewShellDocId nDocId)
@@ -1069,6 +1426,8 @@ SfxViewShell::SfxViewShell
 ,   maLOKLanguageTag(LANGUAGE_NONE)
 ,   maLOKLocale(LANGUAGE_NONE)
 ,   maLOKDeviceFormFactor(LOKDeviceFormFactor::UNKNOWN)
+,   mbLOKAccessibilityEnabled(false)
+,   mpLOKDocumentFocusListener(nullptr)
 {
     SetMargin( pViewFrame->GetMargin_Impl() );
 
@@ -1643,6 +2002,57 @@ void SfxViewShell::SetLOKLanguageTag(const OUString& 
rBcp47LanguageTag)
         maLOKLanguageTag = aFallbackTag;
 }
 
+LOKDocumentFocusListener& SfxViewShell::GetLOKDocumentFocusListener()
+{
+    if (mpLOKDocumentFocusListener)
+        return *mpLOKDocumentFocusListener;
+
+    mpLOKDocumentFocusListener.reset(new LOKDocumentFocusListener);
+    return *mpLOKDocumentFocusListener;
+}
+
+void SfxViewShell::SetLOKAccessibilityState(bool bEnabled)
+{
+    if (bEnabled == mbLOKAccessibilityEnabled)
+        return;
+    mbLOKAccessibilityEnabled = bEnabled;
+
+    SAL_DEBUG("SfxViewShell::SetLOKAccessibilityState: bEnabled: " << 
bEnabled);
+    LOKDocumentFocusListener& rDocumentFocusListener = 
GetLOKDocumentFocusListener();
+
+    if (!pWindow)
+        return;
+
+    uno::Reference< accessibility::XAccessible > xAccessible =
+        pWindow->GetAccessible();
+
+    if (!xAccessible.is())
+        return;
+
+    if (mbLOKAccessibilityEnabled)
+    {
+        try
+        {
+            rDocumentFocusListener.attachRecursive(xAccessible);
+        }
+        catch (const uno::Exception&)
+        {
+            SAL_WARN("SetLOKAccessibilityState", "Exception caught processing 
LOKDocumentFocusListener::attachRecursive");
+        }
+    }
+    else
+    {
+        try
+        {
+            rDocumentFocusListener.detachRecursive(xAccessible);
+        }
+        catch (const uno::Exception&)
+        {
+            SAL_WARN("SetLOKAccessibilityState", "Exception caught processing 
LOKDocumentFocusListener::detachRecursive");
+        }
+    }
+}
+
 void SfxViewShell::SetLOKLocale(const OUString& rBcp47LanguageTag)
 {
     maLOKLocale = LanguageTag(rBcp47LanguageTag, true).makeFallback();

Reply via email to