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