include/comphelper/interfacecontainer2.hxx |   68 +++++++++++++++++++++++++++++
 sfx2/source/notify/globalevents.cxx        |    6 +-
 2 files changed, 72 insertions(+), 2 deletions(-)

New commits:
commit c8b88a40a04e95b3f71e9b231ed68947007df671
Author:     Stephan Bergmann <stephan.bergm...@allotropia.de>
AuthorDate: Wed Nov 20 15:04:06 2024 +0100
Commit:     Stephan Bergmann <stephan.bergm...@allotropia.de>
CommitDate: Thu Nov 21 09:08:25 2024 +0100

    Catch exceptions thrown when notifying individual listeners
    
    Any such exceptions were already caught further up the stack (by
    SfxBaseModel::postEvent_Impl), but prevented later listeners from being 
notified
    as soon as one listener threw an exception (which I saw happen with some
    3rd-party extension).
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176854
    Tested-by: Jenkins
    Reviewed-by: Stephan Bergmann <stephan.bergm...@allotropia.de>
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>
    (cherry picked from commit 755b28d019db62d29ef36535a501809912182960)
    Conflicts:
            include/comphelper/interfacecontainer2.hxx
            include/comphelper/interfacecontainer4.hxx
            sfx2/source/notify/globalevents.cxx
    
    Change-Id: Ia6bd1c73d29ab6d6e131652df51939ba0c0e988e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176866
    Tested-by: allotropia jenkins <jenk...@allotropia.de>
    Reviewed-by: Stephan Bergmann <stephan.bergm...@allotropia.de>

diff --git a/include/comphelper/interfacecontainer2.hxx 
b/include/comphelper/interfacecontainer2.hxx
index 63888008d3ea..9c4d9c3f08eb 100644
--- a/include/comphelper/interfacecontainer2.hxx
+++ b/include/comphelper/interfacecontainer2.hxx
@@ -191,6 +191,24 @@ public:
     template <typename ListenerT, typename FuncT>
     inline void forEach( FuncT const& func );
 
+    /** Executes a functor for each contained listener of specified type, e.g.
+        <code>forEach<awt::XPaintListener>(...</code>.
+
+        If a css::lang::DisposedException occurs which relates to
+        the called listener, then that listener is removed from the container.
+
+        If any other UNO exception occurs, the exceptionFunc is called.
+
+        @tparam ListenerT listener type
+        @tparam FuncT unary functor type, let your compiler deduce this for you
+        @tparam ExceptionFuncT nullary functor type, let your compiler deduce 
this for you
+        @param func unary functor object expecting an argument of type
+                    css::uno::Reference<ListenerT>
+        @param exceptionFunc nullary functor object
+    */
+    template <typename ListenerT, typename FuncT, typename ExceptionFuncT>
+    inline void forEach( FuncT const& func, ExceptionFuncT const& 
exceptionFunc );
+
     /** Calls a UNO listener method for each contained listener.
 
         The listener method must take a single argument of type EventT,
@@ -215,6 +233,28 @@ public:
     template< typename ListenerT, typename EventT >
     inline void notifyEach( void ( SAL_CALL ListenerT::*NotificationMethod )( 
const EventT& ), const EventT& Event );
 
+    /** Calls a UNO listener method for each contained listener.
+
+        The listener method must take a single argument of type EventT,
+        and return <code>void</code>.
+
+        If a css::lang::DisposedException occurs which relates to
+        the called listener, then that listener is removed from the container.
+
+        If any other UNO exception occurs, the exceptionFunc is called.
+
+        @tparam ListenerT UNO event listener type, let your compiler deduce 
this for you
+        @tparam EventT event type, let your compiler deduce this for you
+        @tparam ExceptionFuncT nullary functor type, let your compiler deduce 
this for you
+        @param NotificationMethod
+            Pointer to a method of a ListenerT interface.
+        @param Event
+            Event to notify to all contained listeners
+        @param exceptionFunc nullary functor object
+    */
+    template< typename ListenerT, typename EventT, typename ExceptionFuncT >
+    inline void notifyEach( void ( SAL_CALL ListenerT::*NotificationMethod )( 
const EventT& ), const EventT& Event, const ExceptionFuncT& exceptionFunc );
+
 private:
 friend class OInterfaceIteratorHelper2;
     /**
@@ -273,12 +313,40 @@ inline void OInterfaceContainerHelper2::forEach( FuncT 
const& func )
     }
 }
 
+template <typename ListenerT, typename FuncT, typename ExceptionFuncT>
+inline void OInterfaceContainerHelper2::forEach(
+    FuncT const& func, ExceptionFuncT const& exceptionFunc )
+{
+    OInterfaceIteratorHelper2 iter( *this );
+    while (iter.hasMoreElements()) {
+        css::uno::Reference<ListenerT> const xListener( iter.next(), 
css::uno::UNO_QUERY );
+        if (xListener.is()) {
+            try {
+                func( xListener );
+            }
+            catch (css::lang::DisposedException const& exc) {
+                if (exc.Context == xListener)
+                    iter.remove();
+            }
+            catch (css::uno::Exception) {
+                exceptionFunc();
+            }
+        }
+    }
+}
+
 template< typename ListenerT, typename EventT >
 inline void OInterfaceContainerHelper2::notifyEach( void ( SAL_CALL 
ListenerT::*NotificationMethod )( const EventT& ), const EventT& Event )
 {
     forEach< ListenerT, NotifySingleListener< ListenerT, EventT > >( 
NotifySingleListener< ListenerT, EventT >( NotificationMethod, Event ) );
 }
 
+template< typename ListenerT, typename EventT, typename ExceptionFuncT >
+inline void OInterfaceContainerHelper2::notifyEach( void ( SAL_CALL 
ListenerT::*NotificationMethod )( const EventT& ), const EventT& Event, const 
ExceptionFuncT& exceptionFunc )
+{
+    forEach< ListenerT, NotifySingleListener< ListenerT, EventT > >( 
NotifySingleListener< ListenerT, EventT >( NotificationMethod, Event ), 
exceptionFunc );
+}
+
 }
 #endif
 
diff --git a/sfx2/source/notify/globalevents.cxx 
b/sfx2/source/notify/globalevents.cxx
index cfb994ac30f1..c1aa49a01bd7 100644
--- a/sfx2/source/notify/globalevents.cxx
+++ b/sfx2/source/notify/globalevents.cxx
@@ -384,9 +384,11 @@ void SfxGlobalEvents_Impl::implts_notifyListener(const 
document::DocumentEvent&
 {
     // containers are threadsafe
     document::EventObject aLegacyEvent(aEvent.Source, aEvent.EventName);
-    m_aLegacyListeners.notifyEach( &document::XEventListener::notifyEvent, 
aLegacyEvent );
+    m_aLegacyListeners.notifyEach(
+        &document::XEventListener::notifyEvent, aLegacyEvent,
+        [] { TOOLS_WARN_EXCEPTION("sfx.notify", "ignoring"); } );
 
-    m_aDocumentListeners.notifyEach( 
&document::XDocumentEventListener::documentEventOccured, aEvent );
+    m_aDocumentListeners.notifyEach( 
&document::XDocumentEventListener::documentEventOccured, aEvent, [] { 
TOOLS_WARN_EXCEPTION("sfx.notify", "ignoring"); } );
 }
 
 

Reply via email to