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