tdf#119388 add new UNO listener/broadcaster

so that we only need to fire each event to the exact shape that wants
it, instead of spamming all the shapes.
Takes deleting a column from 20s to 10s for me.

Note that none of the broadcasters are calling disposing(EventObject),
so I did not make XShapeEventListener extend lang::XEventListener.
If a memory leak regression points at this commit, possibly I
missed something.

Change-Id: I2b8db08247d3e0203d41faf77491368168994e4d
Reviewed-on: https://gerrit.libreoffice.org/77857
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/include/sfx2/sfxbasemodel.hxx b/include/sfx2/sfxbasemodel.hxx
index 9dcba7e..92c69b5 100644
--- a/include/sfx2/sfxbasemodel.hxx
+++ b/include/sfx2/sfxbasemodel.hxx
@@ -34,6 +34,7 @@
#include <com/sun/star/document/XUndoManagerSupplier.hpp>
#include <com/sun/star/rdf/XDocumentMetadataAccess.hpp>
#include <com/sun/star/document/XEventBroadcaster.hpp>
#include <com/sun/star/document/XShapeEventBroadcaster.hpp>
#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
#include <com/sun/star/document/XEventsSupplier.hpp>
#include <com/sun/star/document/XEmbeddedScripts.hpp>
@@ -119,7 +120,7 @@ typedef ::cppu::WeakImplHelper  <   css::container::XChild
                                        ,   css::rdf::XDocumentMetadataAccess
                                        ,   css::document::XDocumentRecovery
                                        ,   css::document::XUndoManagerSupplier
                                        ,   css::document::XEventBroadcaster
                                        ,   css::document::XShapeEventBroadcaster
                                        ,   css::document::XDocumentEventBroadcaster
                                        ,   css::lang::XEventListener
                                        ,   css::document::XEventsSupplier
@@ -494,24 +495,33 @@ public:
    virtual css::uno::Reference< css::document::XEmbeddedScripts > SAL_CALL getScriptContainer() override;


    //  XEventBroadcaster

    //  document::XEventBroadcaster

    /**___________________________________________________________________________________________________
        @descr      -   registers the given XEventListener.
    */

    virtual void SAL_CALL addEventListener( const css::uno::Reference< css::document::XEventListener >& xListener ) override;

    /**___________________________________________________________________________________________________
        @descr      -   unregisters the given XEventListener.
    */

    virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::document::XEventListener >& xListener ) override;


    //  XDocumentEventBroadcaster
    //  document::XShapeEventBroadcaster

    /**___________________________________________________________________________________________________
        @descr      -   registers the given XEventListener.
    */
    virtual void SAL_CALL addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::document::XShapeEventListener >& xListener ) override;

    /**___________________________________________________________________________________________________
        @descr      -   unregisters the given XEventListener.
    */
    virtual void SAL_CALL removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::document::XShapeEventListener >& xListener ) override;


    //  XDocumentEventBroadcaster

    virtual void SAL_CALL addDocumentEventListener( const css::uno::Reference< css::document::XDocumentEventListener >& Listener ) override;
    virtual void SAL_CALL removeDocumentEventListener( const css::uno::Reference< css::document::XDocumentEventListener >& Listener ) override;
diff --git a/include/svx/AccessibleControlShape.hxx b/include/svx/AccessibleControlShape.hxx
index 2ea2f73..9b7ff79 100644
--- a/include/svx/AccessibleControlShape.hxx
+++ b/include/svx/AccessibleControlShape.hxx
@@ -114,9 +114,6 @@ private:
    //---  XAccessibleEventListener ----------------------------
    virtual void SAL_CALL notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) override;

    //---  document::XEventListener ----------------------------
    using AccessibleShape::notifyEvent;

    // XVclContainerListener
    virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
    virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
diff --git a/include/svx/AccessibleShape.hxx b/include/svx/AccessibleShape.hxx
index 7d182e5..a70f95e 100644
--- a/include/svx/AccessibleShape.hxx
+++ b/include/svx/AccessibleShape.hxx
@@ -29,7 +29,7 @@
#include <com/sun/star/awt/Point.hpp>
#include <com/sun/star/awt/Rectangle.hpp>
#include <com/sun/star/awt/Size.hpp>
#include <com/sun/star/document/XEventListener.hpp>
#include <com/sun/star/document/XShapeEventListener.hpp>
#include <com/sun/star/lang/EventObject.hpp>
#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/uno/Reference.hxx>
@@ -99,7 +99,7 @@ class SVX_DLLPUBLIC AccessibleShape
        public css::accessibility::XAccessibleGroupPosition,
        public css::accessibility::XAccessibleHypertext,
        public IAccessibleViewForwarderListener,
        public css::document::XEventListener,
        public css::document::XShapeEventListener,
        public css::lang::XUnoTunnel
{
public:
@@ -312,18 +312,15 @@ public:
    //=====  IAccessibleViewForwarderListener  ================================
    virtual void ViewForwarderChanged() override;

    //=====  lang::XEventListener  ============================================

    /** Listen for disposing events of the model.  The accessible shape
        remains functional when this happens.
    */
    virtual void SAL_CALL
        disposing (const css::lang::EventObject& Source) override;
    void disposing (const css::lang::EventObject& Source);

    //=====  document::XEventListener  ========================================
    //=====  document::XShapeEventListener  ========================================

    virtual void SAL_CALL
        notifyEvent (const css::document::EventObject& rEventObject) override;
        notifyShapeEvent (const css::document::EventObject& rEventObject) override;


    //===== XUnoTunnel ========================================================
diff --git a/include/svx/AccessibleShapeTreeInfo.hxx b/include/svx/AccessibleShapeTreeInfo.hxx
index 0b5ddf8..82f9875 100644
--- a/include/svx/AccessibleShapeTreeInfo.hxx
+++ b/include/svx/AccessibleShapeTreeInfo.hxx
@@ -26,7 +26,7 @@

namespace com { namespace sun { namespace star {
    namespace accessibility { class XAccessibleComponent; }
    namespace document { class XEventBroadcaster; }
    namespace document { class XShapeEventBroadcaster; }
    namespace frame { class XController; }
} } }

@@ -89,7 +89,7 @@ public:
            reference may be passed to unset the broadcaster
    */
    void SetModelBroadcaster (const css::uno::Reference<
        css::document::XEventBroadcaster>& rxModelBroadcaster);
        css::document::XShapeEventBroadcaster>& rxModelBroadcaster);

    /** Return the current model broadcaster.
        @return
@@ -97,7 +97,7 @@ public:
            been set or has been set to an empty reference.
    */
    const css::uno::Reference<
        css::document::XEventBroadcaster>&
        css::document::XShapeEventBroadcaster>&
        GetModelBroadcaster() const { return mxModelBroadcaster;}

    /** Set the view that will be used to construct SvxTextEditSources which
@@ -173,7 +173,7 @@ private:
        This once was named mxControllerBroadcaster.
    */
    css::uno::Reference<
        css::document::XEventBroadcaster> mxModelBroadcaster;
        css::document::XShapeEventBroadcaster> mxModelBroadcaster;

    /** This view is necessary to construct an SvxTextEditSource which in
        turn is used to create an accessible edit engine.
diff --git a/offapi/UnoApi_offapi.mk b/offapi/UnoApi_offapi.mk
index 59d7e167..474fc58 100644
--- a/offapi/UnoApi_offapi.mk
+++ b/offapi/UnoApi_offapi.mk
@@ -2246,6 +2246,8 @@ $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/document,\
	XOOXMLDocumentPropertiesImporter \
	XRedlinesSupplier \
	XScriptInvocationContext \
	XShapeEventBroadcaster \
	XShapeEventListener \
	XStorageBasedDocument \
	XStorageChangeListener \
	XTypeDetection \
diff --git a/offapi/com/sun/star/document/XShapeEventBroadcaster.idl b/offapi/com/sun/star/document/XShapeEventBroadcaster.idl
new file mode 100644
index 0000000..52e49ec
--- /dev/null
+++ b/offapi/com/sun/star/document/XShapeEventBroadcaster.idl
@@ -0,0 +1,55 @@
/* -*- 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 __com_sun_star_document_XShapeEventBroadcaster_idl__
#define __com_sun_star_document_XShapeEventBroadcaster_idl__

#include <com/sun/star/document/XShapeEventListener.idl>
#include <com/sun/star/drawing/XShape.idl>


module com {   module sun {   module star {   module document {

/**
  Used to link a listener to a specific shape

  @since LibreOffice 6.4
 */
interface XShapeEventBroadcaster : com::sun::star::document::XEventBroadcaster
{
    /** registers the given listener

        @param Listener
            listener which is interested on such events
     */
    void addShapeEventListener( [in] com::sun::star::drawing::XShape Shape, [in] XShapeEventListener Listener );

    /** unregisters the given listener

        @param Listener
            listener which isn't interested on such events any longer
     */
    void removeShapeEventListener( [in] com::sun::star::drawing::XShape Shape, [in] XShapeEventListener Listener );
};


}; }; }; };

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/offapi/com/sun/star/document/XShapeEventListener.idl b/offapi/com/sun/star/document/XShapeEventListener.idl
new file mode 100644
index 0000000..56634d1
--- /dev/null
+++ b/offapi/com/sun/star/document/XShapeEventListener.idl
@@ -0,0 +1,49 @@
/* -*- 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 __com_sun_star_document_XShapeEventListener_idl__
#define __com_sun_star_document_XShapeEventListener_idl__

#include <com/sun/star/document/EventObject.idl>


module com {  module sun {  module star {  module document {

/** makes it possible to register listeners, which are called whenever
    a document or document content event occurs

    <p>Such events will be broadcasted by a XShapeEventBroadcaster.</p>

    @since LibreOffice 6.4
 */
interface XShapeEventListener
{
    /** is called whenever a document event (see EventObject) occurs

        @param Event
            specifies the event type
     */
    void notifyShapeEvent( [in] EventObject Event );
};


}; }; }; };

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/DrawModelBroadcaster.cxx b/sc/source/ui/Accessibility/DrawModelBroadcaster.cxx
index 4cf1567..5b63c99 100644
--- a/sc/source/ui/Accessibility/DrawModelBroadcaster.cxx
+++ b/sc/source/ui/Accessibility/DrawModelBroadcaster.cxx
@@ -21,6 +21,7 @@
#include <sal/log.hxx>
#include <svx/svdmodel.hxx>
#include <svx/unomod.hxx>
#include <svx/svdobj.hxx>
#include <tools/diagnose_ex.h>

using namespace ::com::sun::star;
@@ -49,6 +50,30 @@ void SAL_CALL ScDrawModelBroadcaster::removeEventListener( const uno::Reference<
    maEventListeners.removeInterface( xListener );
}

void SAL_CALL ScDrawModelBroadcaster::addShapeEventListener(
                const css::uno::Reference< css::drawing::XShape >& xShape,
                const uno::Reference< document::XShapeEventListener >& xListener )
{
    osl::MutexGuard aGuard(maListenerMutex);
    auto rv = maShapeListeners.emplace(xShape, xListener);
    assert(rv.second && "duplicate listener?");
    (void)rv;
}

void SAL_CALL ScDrawModelBroadcaster::removeShapeEventListener(
                const css::uno::Reference< css::drawing::XShape >& xShape,
                const uno::Reference< document::XShapeEventListener >& xListener )
{
    osl::MutexGuard aGuard(maListenerMutex);
    auto it = maShapeListeners.find(xShape);
    if (it != maShapeListeners.end())
    {
        assert(it->second == xListener && "removing wrong listener?");
        (void)xListener;
        maShapeListeners.erase(it);
    }
}

void ScDrawModelBroadcaster::Notify( SfxBroadcaster&,
        const SfxHint& rHint )
{
@@ -73,6 +98,17 @@ void ScDrawModelBroadcaster::Notify( SfxBroadcaster&,
            TOOLS_WARN_EXCEPTION("sc.ui", "Runtime exception caught while notifying shape");
        }
    }

    // right now, we're only handling the specific event necessary to fix this performance problem
    if (pSdrHint->GetKind() == SdrHintKind::ObjectChange)
    {
        auto pSdrObject = const_cast<SdrObject*>(pSdrHint->GetObject());
        uno::Reference<drawing::XShape> xShape(pSdrObject->getUnoShape(), uno::UNO_QUERY);
        osl::MutexGuard aGuard(maListenerMutex);
        auto it = maShapeListeners.find(xShape);
        if (it != maShapeListeners.end())
            it->second->notifyShapeEvent(aEvent);
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/DrawModelBroadcaster.hxx b/sc/source/ui/inc/DrawModelBroadcaster.hxx
index 6a967a0..0d5966b 100644
--- a/sc/source/ui/inc/DrawModelBroadcaster.hxx
+++ b/sc/source/ui/inc/DrawModelBroadcaster.hxx
@@ -24,14 +24,17 @@
#include <comphelper/interfacecontainer3.hxx>
#include <cppuhelper/implbase.hxx>
#include <com/sun/star/document/XEventBroadcaster.hpp>
#include <com/sun/star/document/XShapeEventBroadcaster.hpp>
#include <unordered_map>

class SdrModel;

class ScDrawModelBroadcaster : public SfxListener,
    public ::cppu::WeakImplHelper< css::document::XEventBroadcaster >
    public ::cppu::WeakImplHelper< css::document::XShapeEventBroadcaster >
{
    mutable ::osl::Mutex maListenerMutex;
    ::comphelper::OInterfaceContainerHelper3<css::document::XEventListener> maEventListeners;
    std::unordered_map<css::uno::Reference< css::drawing::XShape >, css::uno::Reference< css::document::XShapeEventListener >> maShapeListeners;
    SdrModel *mpDrawModel;

public:
@@ -39,8 +42,12 @@ public:
    ScDrawModelBroadcaster( SdrModel *pDrawModel );
    virtual ~ScDrawModelBroadcaster() override;

    // css::document::XEventBroadcaster
    virtual void SAL_CALL addEventListener( const css::uno::Reference< css::document::XEventListener >& xListener ) override;
    virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::document::XEventListener >& xListener ) override;
    // css::document::XShapeEventBroadcaster
    virtual void SAL_CALL addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::document::XShapeEventListener >& xListener ) override;
    virtual void SAL_CALL removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::document::XShapeEventListener >& xListener ) override;

    virtual void        Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
};
diff --git a/sd/source/ui/accessibility/AccessibleDocumentViewBase.cxx b/sd/source/ui/accessibility/AccessibleDocumentViewBase.cxx
index 1d2d101..fe80803 100644
--- a/sd/source/ui/accessibility/AccessibleDocumentViewBase.cxx
+++ b/sd/source/ui/accessibility/AccessibleDocumentViewBase.cxx
@@ -20,7 +20,7 @@
#include <AccessibleDocumentViewBase.hxx>
#include <com/sun/star/drawing/XDrawView.hpp>
#include <com/sun/star/frame/XController.hpp>
#include <com/sun/star/document/XEventBroadcaster.hpp>
#include <com/sun/star/document/XShapeEventBroadcaster.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
@@ -76,8 +76,8 @@ AccessibleDocumentViewBase::AccessibleDocumentViewBase (

    // Fill the shape tree info.
    maShapeTreeInfo.SetModelBroadcaster (
        uno::Reference<document::XEventBroadcaster>(
            mxModel, uno::UNO_QUERY));
        uno::Reference<document::XShapeEventBroadcaster>(
            mxModel, uno::UNO_QUERY_THROW));
    maShapeTreeInfo.SetController (mxController);
    maShapeTreeInfo.SetSdrView (pViewShell->GetView());
    maShapeTreeInfo.SetDevice (pSdWindow);
diff --git a/sd/source/ui/accessibility/AccessiblePageShape.cxx b/sd/source/ui/accessibility/AccessiblePageShape.cxx
index 5e22d74..6390ce1 100644
--- a/sd/source/ui/accessibility/AccessiblePageShape.cxx
+++ b/sd/source/ui/accessibility/AccessiblePageShape.cxx
@@ -216,24 +216,10 @@ css::uno::Sequence< OUString> SAL_CALL
    return AccessibleShape::getSupportedServiceNames();
}

//=====  lang::XEventListener  ================================================

void SAL_CALL
    AccessiblePageShape::disposing (const css::lang::EventObject& aEvent)
{
    ThrowIfDisposed ();
    AccessibleShape::disposing (aEvent);
}

//=====  XComponent  ==========================================================

void AccessiblePageShape::dispose()
{
    // Unregister listeners.
    Reference<lang::XComponent> xComponent (mxShape, uno::UNO_QUERY);
    if (xComponent.is())
        xComponent->removeEventListener (this);

    // Cleanup.
    mxShape = nullptr;

diff --git a/sd/source/ui/inc/AccessiblePageShape.hxx b/sd/source/ui/inc/AccessiblePageShape.hxx
index 71cc0a7..ced504f 100644
--- a/sd/source/ui/inc/AccessiblePageShape.hxx
+++ b/sd/source/ui/inc/AccessiblePageShape.hxx
@@ -95,11 +95,6 @@ public:
    virtual css::uno::Sequence< OUString> SAL_CALL
        getSupportedServiceNames() override;

    //=====  lang::XEventListener  ============================================

    virtual void SAL_CALL
        disposing (const css::lang::EventObject& Source) override;

    using AccessibleShape::disposing;

protected:
diff --git a/sfx2/source/doc/sfxbasemodel.cxx b/sfx2/source/doc/sfxbasemodel.cxx
index 5c61dfb..19cfb2d 100644
--- a/sfx2/source/doc/sfxbasemodel.cxx
+++ b/sfx2/source/doc/sfxbasemodel.cxx
@@ -198,6 +198,8 @@ struct IMPL_SfxBaseModel_DataContainer : public ::sfx2::IModifiableDocument
    OUString                                                   m_sRuntimeUID            ;
    OUString                                                   m_aPreusedFilterName     ;
    ::cppu::OMultiTypeInterfaceContainerHelper                 m_aInterfaceContainer    ;
    std::unordered_map<css::uno::Reference< css::drawing::XShape >,
                       css::uno::Reference< css::document::XShapeEventListener >> maShapeListeners;
    Reference< XInterface >                                    m_xParent                ;
    Reference< frame::XController >                            m_xCurrent               ;
    Reference< document::XDocumentProperties >                 m_xDocumentProperties    ;
@@ -2370,6 +2372,33 @@ void SAL_CALL SfxBaseModel::removeEventListener( const Reference< document::XEve
    m_pData->m_aInterfaceContainer.removeInterface( cppu::UnoType<document::XEventListener>::get(), aListener );
}

//  XShapeEventBroadcaster

void SAL_CALL SfxBaseModel::addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const Reference< document::XShapeEventListener >& xListener )
{
    SfxModelGuard aGuard( *this, SfxModelGuard::E_INITIALIZING );

    auto rv = m_pData->maShapeListeners.emplace(xShape, xListener);
    assert(rv.second && "duplicate listener?");
    (void)rv;
}


//  XShapeEventBroadcaster


void SAL_CALL SfxBaseModel::removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const Reference< document::XShapeEventListener >& xListener )
{
    SfxModelGuard aGuard( *this );

    auto it = m_pData->maShapeListeners.find(xShape);
    if (it != m_pData->maShapeListeners.end())
    {
        assert(it->second == xListener && "removing wrong listener?");
        (void)xListener;
        m_pData->maShapeListeners.erase(it);
    }
}

//  XDocumentEventBroadcaster

@@ -3219,12 +3248,25 @@ void SfxBaseModel::notifyEvent( const document::EventObject& aEvent ) const
            aIt.remove();
        }
    }
    // for right now, we're only doing the event that this particular performance problem needed
    if (aEvent.EventName == "ShapeModified")
    {
        uno::Reference<drawing::XShape> xShape(aEvent.Source, uno::UNO_QUERY);
        if (xShape.is())
        {
            auto it = m_pData->maShapeListeners.find(xShape);
            if (it != m_pData->maShapeListeners.end())
                it->second->notifyShapeEvent(aEvent);
        }
    }
}

/** returns true if someone added a XEventListener to this XEventBroadcaster */
bool SfxBaseModel::hasEventListeners() const
{
    return !impl_isDisposed() && (nullptr != m_pData->m_aInterfaceContainer.getContainer( cppu::UnoType<document::XEventListener>::get()) );
    return !impl_isDisposed()
        && ( (nullptr != m_pData->m_aInterfaceContainer.getContainer( cppu::UnoType<document::XEventListener>::get()) )
             || !m_pData->maShapeListeners.empty());
}

void SAL_CALL SfxBaseModel::addPrintJobListener( const Reference< view::XPrintJobListener >& xListener )
diff --git a/svx/source/accessibility/AccessibleShape.cxx b/svx/source/accessibility/AccessibleShape.cxx
index 779ad7b..e9966e3 100644
--- a/svx/source/accessibility/AccessibleShape.cxx
+++ b/svx/source/accessibility/AccessibleShape.cxx
@@ -30,7 +30,7 @@
#include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/drawing/XShapes.hpp>
#include <com/sun/star/drawing/XShapeDescriptor.hpp>
#include <com/sun/star/document/XEventBroadcaster.hpp>
#include <com/sun/star/document/XShapeEventBroadcaster.hpp>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/text/XText.hpp>
@@ -141,8 +141,8 @@ void AccessibleShape::Init()

    // Register at model as document::XEventListener.
    if (maShapeTreeInfo.GetModelBroadcaster().is())
        maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
            static_cast<document::XEventListener*>(this));
        maShapeTreeInfo.GetModelBroadcaster()->addShapeEventListener(mxShape,
            static_cast<document::XShapeEventListener*>(this));

    // Beware! Here we leave the paths of the UNO API and descend into the
    // depths of the core.  Necessary for making the edit engine
@@ -750,8 +750,7 @@ css::uno::Any SAL_CALL
            static_cast<XAccessibleExtendedComponent*>(this),
            static_cast< css::accessibility::XAccessibleSelection* >(this),
            static_cast< css::accessibility::XAccessibleExtendedAttributes* >(this),
            static_cast<lang::XEventListener*>(this),
            static_cast<document::XEventListener*>(this),
            static_cast<document::XShapeEventListener*>(this),
            static_cast<lang::XUnoTunnel*>(this),
            static_cast<XAccessibleGroupPosition*>(this),
            static_cast<XAccessibleHypertext*>(this)
@@ -937,8 +936,7 @@ uno::Sequence<uno::Type> SAL_CALL
    reference to the model in the shape tree info.  Otherwise this object
    remains functional.
*/
void SAL_CALL
    AccessibleShape::disposing (const lang::EventObject& aEvent)
void AccessibleShape::disposing (const lang::EventObject& aEvent)
{
    SolarMutexGuard aSolarGuard;
    ::osl::MutexGuard aGuard (maMutex);
@@ -959,33 +957,27 @@ void SAL_CALL
    }
}

// document::XEventListener
// document::XShapeEventListener
void SAL_CALL
    AccessibleShape::notifyEvent (const document::EventObject& rEventObject)
    AccessibleShape::notifyShapeEvent (const document::EventObject& rEventObject)
{
    // First check if the event is for us.
    uno::Reference<drawing::XShape> xShape (
        rEventObject.Source, uno::UNO_QUERY);
    if ( xShape.get() == mxShape.get() )
    if (rEventObject.EventName == "ShapeModified")
    {
        if (rEventObject.EventName == "ShapeModified")
        {
            //Need to update text children when receiving ShapeModified hint when exiting edit mode for text box
            if (mpText)
                mpText->UpdateChildren();
        //Need to update text children when receiving ShapeModified hint when exiting edit mode for text box
        if (mpText)
            mpText->UpdateChildren();


            // Some property of a shape has been modified.  Send an event
            // that indicates a change of the visible data to all listeners.
            CommitChange (
                AccessibleEventId::VISIBLE_DATA_CHANGED,
                uno::Any(),
                uno::Any());
        // Some property of a shape has been modified.  Send an event
        // that indicates a change of the visible data to all listeners.
        CommitChange (
            AccessibleEventId::VISIBLE_DATA_CHANGED,
            uno::Any(),
            uno::Any());

            // Name and Description may have changed.  Update the local
            // values accordingly.
            UpdateNameAndDescription();
        }
        // Name and Description may have changed.  Update the local
        // values accordingly.
        UpdateNameAndDescription();
    }
}

@@ -1071,15 +1063,10 @@ void AccessibleShape::disposing()
    if (pStateSet != nullptr)
        pStateSet->RemoveState (AccessibleStateType::FOCUSED);

    // Unregister from broadcasters.
    Reference<lang::XComponent> xComponent (mxShape, uno::UNO_QUERY);
    if (xComponent.is())
        xComponent->removeEventListener (this);

    // Unregister from model.
    if (maShapeTreeInfo.GetModelBroadcaster().is())
        maShapeTreeInfo.GetModelBroadcaster()->removeEventListener (
            static_cast<document::XEventListener*>(this));
        maShapeTreeInfo.GetModelBroadcaster()->removeShapeEventListener(mxShape,
            static_cast<document::XShapeEventListener*>(this));

    // Release the child containers.
    if (mpChildrenManager != nullptr)
diff --git a/svx/source/accessibility/AccessibleShapeTreeInfo.cxx b/svx/source/accessibility/AccessibleShapeTreeInfo.cxx
index 88d24ac..edc7ef8 100644
--- a/svx/source/accessibility/AccessibleShapeTreeInfo.cxx
+++ b/svx/source/accessibility/AccessibleShapeTreeInfo.cxx
@@ -86,7 +86,7 @@ void AccessibleShapeTreeInfo::SetDocumentWindow (
}

void AccessibleShapeTreeInfo::SetModelBroadcaster (
    const Reference<document::XEventBroadcaster>& rxModelBroadcaster)
    const Reference<document::XShapeEventBroadcaster>& rxModelBroadcaster)
{
    mxModelBroadcaster = rxModelBroadcaster;
}
diff --git a/svx/source/accessibility/ChildrenManagerImpl.cxx b/svx/source/accessibility/ChildrenManagerImpl.cxx
index e08a5c2..2c0b953 100644
--- a/svx/source/accessibility/ChildrenManagerImpl.cxx
+++ b/svx/source/accessibility/ChildrenManagerImpl.cxx
@@ -31,7 +31,7 @@
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/document/XEventBroadcaster.hpp>
#include <com/sun/star/document/XShapeEventBroadcaster.hpp>
#include <com/sun/star/frame/XController.hpp>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
#include <com/sun/star/view/XSelectionSupplier.hpp>
diff --git a/sw/source/core/access/accmap.cxx b/sw/source/core/access/accmap.cxx
index cb5709c..b5f2c61 100644
--- a/sw/source/core/access/accmap.cxx
+++ b/sw/source/core/access/accmap.cxx
@@ -62,7 +62,7 @@
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/document/XEventBroadcaster.hpp>
#include <com/sun/star/document/XShapeEventBroadcaster.hpp>
#include <cppuhelper/implbase.hxx>
#include <comphelper/interfacecontainer2.hxx>
#include <pagepreviewlayout.hxx>
@@ -126,10 +126,11 @@ public:
};

class SwDrawModellListener_Impl : public SfxListener,
    public ::cppu::WeakImplHelper< document::XEventBroadcaster >
    public ::cppu::WeakImplHelper< document::XShapeEventBroadcaster >
{
    mutable ::osl::Mutex maListenerMutex;
    ::comphelper::OInterfaceContainerHelper2 maEventListeners;
    std::unordered_map<css::uno::Reference< css::drawing::XShape >, css::uno::Reference< css::document::XShapeEventListener >> maShapeListeners;
    SdrModel *mpDrawModel;
protected:
    virtual ~SwDrawModellListener_Impl() override;
@@ -137,8 +138,12 @@ protected:
public:
    explicit SwDrawModellListener_Impl( SdrModel *pDrawModel );

    // css::document::XEventBroadcaster
    virtual void SAL_CALL addEventListener( const uno::Reference< document::XEventListener >& xListener ) override;
    virtual void SAL_CALL removeEventListener( const uno::Reference< document::XEventListener >& xListener ) override;
    // css::document::XShapeEventBroadcaster
    virtual void SAL_CALL addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::document::XShapeEventListener >& xListener ) override;
    virtual void SAL_CALL removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::document::XShapeEventListener >& xListener ) override;

    virtual void        Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
    void Dispose();
@@ -166,6 +171,30 @@ void SAL_CALL SwDrawModellListener_Impl::removeEventListener( const uno::Referen
    maEventListeners.removeInterface( xListener );
}

void SAL_CALL SwDrawModellListener_Impl::addShapeEventListener(
                const css::uno::Reference< css::drawing::XShape >& xShape,
                const uno::Reference< document::XShapeEventListener >& xListener )
{
    osl::MutexGuard aGuard(maListenerMutex);
    auto rv = maShapeListeners.emplace(xShape, xListener);
    assert(rv.second && "duplicate listener?");
    (void)rv;
}

void SAL_CALL SwDrawModellListener_Impl::removeShapeEventListener(
                const css::uno::Reference< css::drawing::XShape >& xShape,
                const uno::Reference< document::XShapeEventListener >& xListener )
{
    osl::MutexGuard aGuard(maListenerMutex);
    auto it = maShapeListeners.find(xShape);
    if (it != maShapeListeners.end())
    {
        assert(it->second == xListener);
        (void)xListener;
        maShapeListeners.erase(it);
    }
}

void SwDrawModellListener_Impl::Notify( SfxBroadcaster& /*rBC*/,
        const SfxHint& rHint )
{
@@ -204,6 +233,17 @@ void SwDrawModellListener_Impl::Notify( SfxBroadcaster& /*rBC*/,
            TOOLS_WARN_EXCEPTION("sw.a11y", "Runtime exception caught while notifying shape");
        }
    }

    // right now, we're only handling the specific event necessary to fix this performance problem
    if (pSdrHint->GetKind() == SdrHintKind::ObjectChange)
    {
        auto pSdrObject = const_cast<SdrObject*>(pSdrHint->GetObject());
        uno::Reference<drawing::XShape> xShape(pSdrObject->getUnoShape(), uno::UNO_QUERY);
        osl::MutexGuard aGuard(maListenerMutex);
        auto it = maShapeListeners.find(xShape);
        if (it != maShapeListeners.end())
            it->second->notifyShapeEvent(aEvent);
    }
}

void SwDrawModellListener_Impl::Dispose()
@@ -247,7 +287,7 @@ public:
        maInfo.SetSdrView( pMap->GetShell()->GetDrawView() );
        maInfo.SetDevice( pMap->GetShell()->GetWin() );
        maInfo.SetViewForwarder( pMap );
        uno::Reference < document::XEventBroadcaster > xModelBroadcaster =
        uno::Reference < document::XShapeEventBroadcaster > xModelBroadcaster =
            new SwDrawModellListener_Impl(
                    pMap->GetShell()->getIDocumentDrawModelAccess().GetOrCreateDrawModel() );
        maInfo.SetModelBroadcaster( xModelBroadcaster );