1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_dbaccess.hxx"
26 
27 #include "documenteventnotifier.hxx"
28 
29 /** === begin UNO includes === **/
30 #include <com/sun/star/frame/DoubleInitializationException.hpp>
31 /** === end UNO includes === **/
32 
33 #include <comphelper/asyncnotification.hxx>
34 #include <cppuhelper/interfacecontainer.hxx>
35 #include <cppuhelper/weak.hxx>
36 #include <tools/diagnose_ex.h>
37 
38 //........................................................................
39 namespace dbaccess
40 {
41 //........................................................................
42 
43 	/** === begin UNO using === **/
44 	using ::com::sun::star::uno::Reference;
45 	using ::com::sun::star::uno::XInterface;
46 	using ::com::sun::star::uno::UNO_QUERY;
47 	using ::com::sun::star::uno::UNO_QUERY_THROW;
48 	using ::com::sun::star::uno::UNO_SET_THROW;
49 	using ::com::sun::star::uno::Exception;
50 	using ::com::sun::star::uno::RuntimeException;
51 	using ::com::sun::star::uno::Any;
52 	using ::com::sun::star::uno::makeAny;
53 	using ::com::sun::star::uno::Sequence;
54 	using ::com::sun::star::uno::Type;
55     using ::com::sun::star::frame::DoubleInitializationException;
56     using ::com::sun::star::document::XDocumentEventListener;
57     using ::com::sun::star::document::DocumentEvent;
58     using ::com::sun::star::frame::XController2;
59 	/** === end UNO using === **/
60 	using namespace ::com::sun::star;
61 
62     //==================================================================
63     //= DocumentEventHolder
64     //==================================================================
65     typedef ::comphelper::EventHolder< DocumentEvent >  DocumentEventHolder;
66 
67     //====================================================================
68 	//= DocumentEventNotifier_Impl
69 	//====================================================================
70     class DocumentEventNotifier_Impl : public ::comphelper::IEventProcessor
71     {
72         oslInterlockedCount                                     m_refCount;
73         ::cppu::OWeakObject&                                    m_rDocument;
74         ::osl::Mutex&                                           m_rMutex;
75         bool                                                    m_bInitialized;
76         bool                                                    m_bDisposed;
77         ::rtl::Reference< ::comphelper::AsyncEventNotifier >    m_pEventBroadcaster;
78         ::cppu::OInterfaceContainerHelper					    m_aLegacyEventListeners;
79         ::cppu::OInterfaceContainerHelper					    m_aDocumentEventListeners;
80 
81     public:
DocumentEventNotifier_Impl(::cppu::OWeakObject & _rBroadcasterDocument,::osl::Mutex & _rMutex)82         DocumentEventNotifier_Impl( ::cppu::OWeakObject& _rBroadcasterDocument, ::osl::Mutex& _rMutex )
83             :m_refCount( 0 )
84             ,m_rDocument( _rBroadcasterDocument )
85             ,m_rMutex( _rMutex )
86             ,m_bInitialized( false )
87             ,m_bDisposed( false )
88             ,m_aLegacyEventListeners( _rMutex )
89             ,m_aDocumentEventListeners( _rMutex )
90         {
91         }
92 
93         // IReference
94         virtual void SAL_CALL acquire();
95         virtual void SAL_CALL release();
96 
addLegacyEventListener(const Reference<document::XEventListener> & _Listener)97         void addLegacyEventListener( const Reference< document::XEventListener >& _Listener )
98         {
99             m_aLegacyEventListeners.addInterface( _Listener );
100         }
101 
removeLegacyEventListener(const Reference<document::XEventListener> & _Listener)102         void removeLegacyEventListener( const Reference< document::XEventListener >& _Listener )
103         {
104             m_aLegacyEventListeners.removeInterface( _Listener );
105         }
106 
addDocumentEventListener(const Reference<XDocumentEventListener> & _Listener)107         void addDocumentEventListener( const Reference< XDocumentEventListener >& _Listener )
108         {
109             m_aDocumentEventListeners.addInterface( _Listener );
110         }
111 
removeDocumentEventListener(const Reference<XDocumentEventListener> & _Listener)112         void removeDocumentEventListener( const Reference< XDocumentEventListener >& _Listener )
113         {
114             m_aDocumentEventListeners.removeInterface( _Listener );
115         }
116 
117         void disposing();
118 
119         void onDocumentInitialized();
120 
notifyDocumentEvent(const::rtl::OUString & _EventName,const Reference<XController2> & _ViewController,const Any & _Supplement)121         void    notifyDocumentEvent( const ::rtl::OUString& _EventName, const Reference< XController2 >& _ViewController,
122                     const Any& _Supplement )
123         {
124             impl_notifyEvent_nothrow( DocumentEvent(
125                 m_rDocument, _EventName, _ViewController, _Supplement ) );
126         }
127 
notifyDocumentEventAsync(const::rtl::OUString & _EventName,const Reference<XController2> & _ViewController,const Any & _Supplement)128         void    notifyDocumentEventAsync( const ::rtl::OUString& _EventName, const Reference< XController2 >& _ViewController,
129                     const Any& _Supplement )
130         {
131             impl_notifyEventAsync_nothrow( DocumentEvent(
132                 m_rDocument, _EventName, _ViewController, _Supplement ) );
133         }
134 
135     protected:
~DocumentEventNotifier_Impl()136         virtual ~DocumentEventNotifier_Impl()
137         {
138         }
139 
140         // IEventProcessor
141         virtual void processEvent( const ::comphelper::AnyEvent& _rEvent );
142 
143     private:
144         void impl_notifyEvent_nothrow( const DocumentEvent& _rEvent );
145         void impl_notifyEventAsync_nothrow( const DocumentEvent& _rEvent );
146     };
147 
148 	//--------------------------------------------------------------------
acquire()149     void SAL_CALL DocumentEventNotifier_Impl::acquire()
150     {
151         osl_incrementInterlockedCount( &m_refCount );
152     }
153 
154 	//--------------------------------------------------------------------
release()155     void SAL_CALL DocumentEventNotifier_Impl::release()
156     {
157         if ( 0 == osl_decrementInterlockedCount( &m_refCount ) )
158             delete this;
159     }
160 
161 	//--------------------------------------------------------------------
disposing()162     void DocumentEventNotifier_Impl::disposing()
163     {
164         // SYNCHRONIZED ->
165         // cancel any pending asynchronous events
166         ::osl::ResettableMutexGuard aGuard( m_rMutex );
167         if ( m_pEventBroadcaster.is() )
168         {
169             m_pEventBroadcaster->removeEventsForProcessor( this );
170             m_pEventBroadcaster->terminate();
171             m_pEventBroadcaster = NULL;
172         }
173 
174         lang::EventObject aEvent( m_rDocument );
175         aGuard.clear();
176         // <-- SYNCHRONIZED
177 
178         m_aLegacyEventListeners.disposeAndClear( aEvent );
179         m_aDocumentEventListeners.disposeAndClear( aEvent );
180 
181         // SYNCHRONIZED ->
182         aGuard.reset();
183         m_bDisposed = true;
184         // <-- SYNCHRONIZED
185     }
186 
187 	//--------------------------------------------------------------------
onDocumentInitialized()188     void DocumentEventNotifier_Impl::onDocumentInitialized()
189     {
190         if ( m_bInitialized )
191             throw DoubleInitializationException();
192 
193         m_bInitialized = true;
194         if ( m_pEventBroadcaster.is() )
195             // there are already pending asynchronous events
196             m_pEventBroadcaster->create();
197     }
198 
199 	//--------------------------------------------------------------------
impl_notifyEvent_nothrow(const DocumentEvent & _rEvent)200     void DocumentEventNotifier_Impl::impl_notifyEvent_nothrow( const DocumentEvent& _rEvent )
201     {
202         OSL_PRECOND( m_bInitialized,
203             "DocumentEventNotifier_Impl::impl_notifyEvent_nothrow: only to be called when the document is already initialized!" );
204 	    try
205 	    {
206             document::EventObject aLegacyEvent( _rEvent.Source, _rEvent.EventName );
207             m_aLegacyEventListeners.notifyEach( &document::XEventListener::notifyEvent, aLegacyEvent );
208 	    }
209 	    catch(const Exception&)
210 	    {
211             DBG_UNHANDLED_EXCEPTION();
212 	    }
213         try
214         {
215             m_aDocumentEventListeners.notifyEach( &XDocumentEventListener::documentEventOccured, _rEvent );
216         }
217         catch( const Exception& )
218         {
219         	DBG_UNHANDLED_EXCEPTION();
220         }
221     }
222 
223 	//--------------------------------------------------------------------
impl_notifyEventAsync_nothrow(const DocumentEvent & _rEvent)224     void DocumentEventNotifier_Impl::impl_notifyEventAsync_nothrow( const DocumentEvent& _rEvent )
225     {
226         if ( !m_pEventBroadcaster.is() )
227         {
228             m_pEventBroadcaster.set( new ::comphelper::AsyncEventNotifier );
229             if ( m_bInitialized )
230                 // start processing the events if and only if we (our document, respectively) are
231                 // already initialized
232                 m_pEventBroadcaster->create();
233         }
234         m_pEventBroadcaster->addEvent( new DocumentEventHolder( _rEvent ), this );
235     }
236 
237     // -----------------------------------------------------------------------------
processEvent(const::comphelper::AnyEvent & _rEvent)238     void DocumentEventNotifier_Impl::processEvent( const ::comphelper::AnyEvent& _rEvent )
239     {
240         // beware, this is called from the notification thread
241         {
242             ::osl::MutexGuard aGuard( m_rMutex );
243             if  ( m_bDisposed )
244                 return;
245         }
246         const DocumentEventHolder& rEventHolder = dynamic_cast< const DocumentEventHolder& >( _rEvent );
247         impl_notifyEvent_nothrow( rEventHolder.getEventObject() );
248     }
249 
250 	//====================================================================
251 	//= DocumentEventNotifier
252 	//====================================================================
253 	//--------------------------------------------------------------------
DocumentEventNotifier(::cppu::OWeakObject & _rBroadcasterDocument,::osl::Mutex & _rMutex)254     DocumentEventNotifier::DocumentEventNotifier( ::cppu::OWeakObject& _rBroadcasterDocument, ::osl::Mutex& _rMutex )
255         :m_pImpl( new DocumentEventNotifier_Impl( _rBroadcasterDocument, _rMutex ) )
256     {
257     }
258 
259 	//--------------------------------------------------------------------
~DocumentEventNotifier()260     DocumentEventNotifier::~DocumentEventNotifier()
261     {
262     }
263 
264 	//--------------------------------------------------------------------
disposing()265     void DocumentEventNotifier::disposing()
266     {
267         m_pImpl->disposing();
268     }
269 
270 	//--------------------------------------------------------------------
onDocumentInitialized()271     void DocumentEventNotifier::onDocumentInitialized()
272     {
273         m_pImpl->onDocumentInitialized();
274     }
275 
276 	//--------------------------------------------------------------------
addLegacyEventListener(const Reference<document::XEventListener> & _Listener)277     void DocumentEventNotifier::addLegacyEventListener( const Reference< document::XEventListener >& _Listener )
278     {
279         m_pImpl->addLegacyEventListener( _Listener );
280     }
281 
282 	//--------------------------------------------------------------------
removeLegacyEventListener(const Reference<document::XEventListener> & _Listener)283     void DocumentEventNotifier::removeLegacyEventListener( const Reference< document::XEventListener >& _Listener )
284     {
285         m_pImpl->removeLegacyEventListener( _Listener );
286     }
287 
288 	//--------------------------------------------------------------------
addDocumentEventListener(const Reference<XDocumentEventListener> & _Listener)289     void DocumentEventNotifier::addDocumentEventListener( const Reference< XDocumentEventListener >& _Listener )
290     {
291         m_pImpl->addDocumentEventListener( _Listener );
292     }
293 
294 	//--------------------------------------------------------------------
removeDocumentEventListener(const Reference<XDocumentEventListener> & _Listener)295     void DocumentEventNotifier::removeDocumentEventListener( const Reference< XDocumentEventListener >& _Listener )
296     {
297         m_pImpl->removeDocumentEventListener( _Listener );
298     }
299 
300 	//--------------------------------------------------------------------
notifyDocumentEvent(const::rtl::OUString & _EventName,const Reference<XController2> & _ViewController,const Any & _Supplement)301     void DocumentEventNotifier::notifyDocumentEvent( const ::rtl::OUString& _EventName,
302         const Reference< XController2 >& _ViewController, const Any& _Supplement )
303     {
304         m_pImpl->notifyDocumentEvent( _EventName, _ViewController, _Supplement );
305     }
306 
307 	//--------------------------------------------------------------------
notifyDocumentEventAsync(const::rtl::OUString & _EventName,const Reference<XController2> & _ViewController,const Any & _Supplement)308     void DocumentEventNotifier::notifyDocumentEventAsync( const ::rtl::OUString& _EventName,
309         const Reference< XController2 >& _ViewController, const Any& _Supplement )
310     {
311         m_pImpl->notifyDocumentEventAsync( _EventName, _ViewController, _Supplement );
312     }
313 
314 //........................................................................
315 } // namespace dbaccess
316 //........................................................................
317