1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "documenteventnotifier.hxx"
22 #include <com/sun/star/frame/DoubleInitializationException.hpp>
24 #include <comphelper/asyncnotification.hxx>
25 #include <comphelper/interfacecontainer3.hxx>
26 #include <cppuhelper/weak.hxx>
27 #include <comphelper/diagnose_ex.hxx>
28 #include <vcl/svapp.hxx>
33 using ::com::sun::star::uno::Reference
;
34 using ::com::sun::star::uno::Exception
;
35 using ::com::sun::star::uno::Any
;
36 using ::com::sun::star::frame::DoubleInitializationException
;
37 using ::com::sun::star::document::XDocumentEventListener
;
38 using ::com::sun::star::document::DocumentEvent
;
39 using ::com::sun::star::frame::XController2
;
41 using namespace ::com::sun::star
;
43 // DocumentEventNotifier_Impl
44 class DocumentEventNotifier_Impl
: public ::comphelper::IEventProcessor
46 oslInterlockedCount m_refCount
;
47 ::cppu::OWeakObject
& m_rDocument
;
48 ::osl::Mutex
& m_rMutex
;
51 std::shared_ptr
<::comphelper::AsyncEventNotifierAutoJoin
> m_pEventBroadcaster
;
52 ::comphelper::OInterfaceContainerHelper3
<css::document::XEventListener
> m_aLegacyEventListeners
;
53 ::comphelper::OInterfaceContainerHelper3
<XDocumentEventListener
> m_aDocumentEventListeners
;
56 DocumentEventNotifier_Impl( ::cppu::OWeakObject
& _rBroadcasterDocument
, ::osl::Mutex
& _rMutex
)
58 ,m_rDocument( _rBroadcasterDocument
)
60 ,m_bInitialized( false )
62 ,m_aLegacyEventListeners( _rMutex
)
63 ,m_aDocumentEventListeners( _rMutex
)
68 virtual void SAL_CALL
acquire() noexcept override
;
69 virtual void SAL_CALL
release() noexcept override
;
71 void addLegacyEventListener( const Reference
< document::XEventListener
>& Listener
)
73 m_aLegacyEventListeners
.addInterface( Listener
);
76 void removeLegacyEventListener( const Reference
< document::XEventListener
>& Listener
)
78 m_aLegacyEventListeners
.removeInterface( Listener
);
81 void addDocumentEventListener( const Reference
< XDocumentEventListener
>& Listener
)
83 m_aDocumentEventListeners
.addInterface( Listener
);
86 void removeDocumentEventListener( const Reference
< XDocumentEventListener
>& Listener
)
88 m_aDocumentEventListeners
.removeInterface( Listener
);
93 void onDocumentInitialized();
95 void notifyDocumentEvent( const OUString
& EventName
, const Reference
< XController2
>& ViewController
,
96 const Any
& Supplement
)
98 impl_notifyEvent_nothrow( DocumentEvent(
99 m_rDocument
, EventName
, ViewController
, Supplement
) );
102 void notifyDocumentEventAsync( const OUString
& EventName
, const Reference
< XController2
>& ViewController
,
103 const Any
& Supplement
)
105 impl_notifyEventAsync_nothrow( DocumentEvent(
106 m_rDocument
, EventName
, ViewController
, Supplement
) );
110 virtual ~DocumentEventNotifier_Impl()
115 virtual void processEvent( const ::comphelper::AnyEvent
& _rEvent
) override
;
118 void impl_notifyEvent_nothrow( const DocumentEvent
& _rEvent
);
119 void impl_notifyEventAsync_nothrow( const DocumentEvent
& _rEvent
);
122 void SAL_CALL
DocumentEventNotifier_Impl::acquire() noexcept
124 osl_atomic_increment( &m_refCount
);
127 void SAL_CALL
DocumentEventNotifier_Impl::release() noexcept
129 if ( 0 == osl_atomic_decrement( &m_refCount
) )
133 void DocumentEventNotifier_Impl::disposing()
136 // cancel any pending asynchronous events
137 ::osl::ResettableMutexGuard
aGuard( m_rMutex
);
138 if (m_pEventBroadcaster
)
140 m_pEventBroadcaster
->removeEventsForProcessor( this );
141 m_pEventBroadcaster
->terminate();
144 auto xEventBroadcaster
= std::exchange(m_pEventBroadcaster
, {});
146 lang::EventObject
aEvent( m_rDocument
);
150 if (xEventBroadcaster
)
152 comphelper::SolarMutex
& rSolarMutex
= Application::GetSolarMutex();
153 // unblock threads blocked on that so we can join
154 sal_uInt32 nLockCount
= (rSolarMutex
.IsCurrentThread()) ? rSolarMutex
.release(true) : 0;
155 xEventBroadcaster
->join();
157 rSolarMutex
.acquire(nLockCount
);
158 xEventBroadcaster
.reset();
160 m_aLegacyEventListeners
.disposeAndClear( aEvent
);
161 m_aDocumentEventListeners
.disposeAndClear( aEvent
);
169 void DocumentEventNotifier_Impl::onDocumentInitialized()
171 if ( m_bInitialized
)
172 throw DoubleInitializationException();
174 m_bInitialized
= true;
175 if (m_pEventBroadcaster
)
177 // there are already pending asynchronous events
178 ::comphelper::AsyncEventNotifierAutoJoin::launch(m_pEventBroadcaster
);
182 void DocumentEventNotifier_Impl::impl_notifyEvent_nothrow( const DocumentEvent
& _rEvent
)
184 OSL_PRECOND( m_bInitialized
,
185 "DocumentEventNotifier_Impl::impl_notifyEvent_nothrow: only to be called when the document is already initialized!" );
188 document::EventObject
aLegacyEvent( _rEvent
.Source
, _rEvent
.EventName
);
189 m_aLegacyEventListeners
.notifyEach( &document::XEventListener::notifyEvent
, aLegacyEvent
);
191 catch(const Exception
&)
193 DBG_UNHANDLED_EXCEPTION("dbaccess");
197 m_aDocumentEventListeners
.notifyEach( &XDocumentEventListener::documentEventOccured
, _rEvent
);
199 catch( const Exception
& )
201 DBG_UNHANDLED_EXCEPTION("dbaccess");
205 void DocumentEventNotifier_Impl::impl_notifyEventAsync_nothrow( const DocumentEvent
& _rEvent
)
207 if (!m_pEventBroadcaster
)
209 m_pEventBroadcaster
= ::comphelper::AsyncEventNotifierAutoJoin
210 ::newAsyncEventNotifierAutoJoin("DocumentEventNotifier");
211 if ( m_bInitialized
)
213 // start processing the events if and only if we (our document, respectively) are
214 // already initialized
215 ::comphelper::AsyncEventNotifierAutoJoin::launch(m_pEventBroadcaster
);
218 m_pEventBroadcaster
->addEvent( new comphelper::DocumentEventHolder( _rEvent
), this );
221 void DocumentEventNotifier_Impl::processEvent( const ::comphelper::AnyEvent
& _rEvent
)
223 // beware, this is called from the notification thread
225 ::osl::MutexGuard
aGuard( m_rMutex
);
229 const comphelper::DocumentEventHolder
& rEventHolder
= dynamic_cast< const comphelper::DocumentEventHolder
& >( _rEvent
);
230 impl_notifyEvent_nothrow( rEventHolder
.getEventObject() );
233 // DocumentEventNotifier
234 DocumentEventNotifier::DocumentEventNotifier( ::cppu::OWeakObject
& _rBroadcasterDocument
, ::osl::Mutex
& _rMutex
)
235 :m_pImpl( new DocumentEventNotifier_Impl( _rBroadcasterDocument
, _rMutex
) )
239 DocumentEventNotifier::~DocumentEventNotifier()
243 void DocumentEventNotifier::disposing()
245 m_pImpl
->disposing();
248 void DocumentEventNotifier::onDocumentInitialized()
250 m_pImpl
->onDocumentInitialized();
253 void DocumentEventNotifier::addLegacyEventListener( const Reference
< document::XEventListener
>& Listener
)
255 m_pImpl
->addLegacyEventListener( Listener
);
258 void DocumentEventNotifier::removeLegacyEventListener( const Reference
< document::XEventListener
>& Listener
)
260 m_pImpl
->removeLegacyEventListener( Listener
);
263 void DocumentEventNotifier::addDocumentEventListener( const Reference
< XDocumentEventListener
>& Listener
)
265 m_pImpl
->addDocumentEventListener( Listener
);
268 void DocumentEventNotifier::removeDocumentEventListener( const Reference
< XDocumentEventListener
>& Listener
)
270 m_pImpl
->removeDocumentEventListener( Listener
);
273 void DocumentEventNotifier::notifyDocumentEvent( const OUString
& EventName
,
274 const Reference
< XController2
>& ViewController
, const Any
& Supplement
)
276 m_pImpl
->notifyDocumentEvent( EventName
, ViewController
, Supplement
);
279 void DocumentEventNotifier::notifyDocumentEventAsync( const OUString
& EventName
,
280 const Reference
< XController2
>& ViewController
, const Any
& Supplement
)
282 m_pImpl
->notifyDocumentEventAsync( EventName
, ViewController
, Supplement
);
285 } // namespace dbaccess
287 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */