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