1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_basctl.hxx" 30 31 #include "doceventnotifier.hxx" 32 #include "scriptdocument.hxx" 33 34 /** === begin UNO includes === **/ 35 #include <com/sun/star/document/XEventBroadcaster.hpp> 36 /** === end UNO includes === **/ 37 38 #include <vcl/svapp.hxx> 39 40 #include <tools/diagnose_ex.h> 41 42 #include <comphelper/componentcontext.hxx> 43 #include <comphelper/processfactory.hxx> 44 45 #include <vos/mutex.hxx> 46 47 #include <cppuhelper/compbase1.hxx> 48 #include <cppuhelper/basemutex.hxx> 49 50 //........................................................................ 51 namespace basctl 52 { 53 //........................................................................ 54 55 /** === begin UNO using === **/ 56 using ::com::sun::star::document::XEventBroadcaster; 57 using ::com::sun::star::document::XEventListener; 58 using ::com::sun::star::document::EventObject; 59 using ::com::sun::star::uno::RuntimeException; 60 using ::com::sun::star::uno::Reference; 61 using ::com::sun::star::uno::UNO_QUERY_THROW; 62 using ::com::sun::star::uno::Exception; 63 using ::com::sun::star::frame::XModel; 64 using ::com::sun::star::uno::UNO_QUERY; 65 /** === end UNO using === **/ 66 namespace csslang = ::com::sun::star::lang; 67 68 //==================================================================== 69 //= DocumentEventNotifier_Impl 70 //==================================================================== 71 typedef ::cppu::WeakComponentImplHelper1 < XEventListener 72 > DocumentEventNotifier_Impl_Base; 73 74 enum ListenerAction 75 { 76 RegisterListener, 77 RemoveListener 78 }; 79 80 /** impl class for DocumentEventNotifier 81 */ 82 class DocumentEventNotifier_Impl :public ::boost::noncopyable 83 ,public ::cppu::BaseMutex 84 ,public DocumentEventNotifier_Impl_Base 85 { 86 public: 87 DocumentEventNotifier_Impl( DocumentEventListener& _rListener, const Reference< XModel >& _rxDocument ); 88 89 // document::XEventListener 90 virtual void SAL_CALL notifyEvent( const EventObject& Event ) throw (RuntimeException); 91 92 // lang::XEventListener 93 virtual void SAL_CALL disposing( const csslang::EventObject& Event ) throw (RuntimeException); 94 95 // ComponentHelper 96 virtual void SAL_CALL disposing(); 97 98 protected: 99 ~DocumentEventNotifier_Impl(); 100 101 private: 102 /// determines whether the instance is already disposed 103 bool impl_isDisposed_nothrow() const { return m_pListener == NULL; } 104 105 /// disposes the instance 106 void impl_dispose_nothrow(); 107 108 /// registers or revokes the instance as listener at the global event broadcaster 109 void impl_listenerAction_nothrow( ListenerAction _eAction ); 110 111 private: 112 DocumentEventListener* m_pListener; 113 Reference< XModel > m_xModel; 114 }; 115 116 //-------------------------------------------------------------------- 117 DocumentEventNotifier_Impl::DocumentEventNotifier_Impl( DocumentEventListener& _rListener, const Reference< XModel >& _rxDocument ) 118 :DocumentEventNotifier_Impl_Base( m_aMutex ) 119 ,m_pListener( &_rListener ) 120 ,m_xModel( _rxDocument ) 121 { 122 osl_incrementInterlockedCount( &m_refCount ); 123 impl_listenerAction_nothrow( RegisterListener ); 124 osl_decrementInterlockedCount( &m_refCount ); 125 } 126 127 //-------------------------------------------------------------------- 128 DocumentEventNotifier_Impl::~DocumentEventNotifier_Impl() 129 { 130 if ( !impl_isDisposed_nothrow() ) 131 { 132 acquire(); 133 dispose(); 134 } 135 } 136 137 //-------------------------------------------------------------------- 138 void SAL_CALL DocumentEventNotifier_Impl::notifyEvent( const EventObject& _rEvent ) throw (RuntimeException) 139 { 140 ::osl::ClearableMutexGuard aGuard( m_aMutex ); 141 142 OSL_PRECOND( !impl_isDisposed_nothrow(), "DocumentEventNotifier_Impl::notifyEvent: disposed, but still getting events?" ); 143 if ( impl_isDisposed_nothrow() ) 144 return; 145 146 Reference< XModel > xDocument( _rEvent.Source, UNO_QUERY ); 147 OSL_ENSURE( xDocument.is(), "DocumentEventNotifier_Impl::notifyEvent: illegal source document!" ); 148 if ( !xDocument.is() ) 149 return; 150 151 struct EventEntry 152 { 153 const sal_Char* pEventName; 154 void (DocumentEventListener::*listenerMethod)( const ScriptDocument& _rDocument ); 155 }; 156 EventEntry aEvents[] = { 157 { "OnNew", &DocumentEventListener::onDocumentCreated }, 158 { "OnLoad", &DocumentEventListener::onDocumentOpened }, 159 { "OnSave", &DocumentEventListener::onDocumentSave }, 160 { "OnSaveDone", &DocumentEventListener::onDocumentSaveDone }, 161 { "OnSaveAs", &DocumentEventListener::onDocumentSaveAs }, 162 { "OnSaveAsDone", &DocumentEventListener::onDocumentSaveAsDone }, 163 { "OnUnload", &DocumentEventListener::onDocumentClosed }, 164 { "OnTitleChanged", &DocumentEventListener::onDocumentTitleChanged }, 165 { "OnModeChanged", &DocumentEventListener::onDocumentModeChanged } 166 }; 167 168 for ( size_t i=0; i < sizeof( aEvents ) / sizeof( aEvents[0] ); ++i ) 169 { 170 if ( !_rEvent.EventName.equalsAscii( aEvents[i].pEventName ) ) 171 continue; 172 173 ScriptDocument aDocument( xDocument ); 174 { 175 // the listener implementations usually require the SolarMutex, so lock it here. 176 // But ensure the proper order of locking the solar and the own mutex 177 aGuard.clear(); 178 ::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() ); 179 ::osl::MutexGuard aGuard2( m_aMutex ); 180 181 if ( impl_isDisposed_nothrow() ) 182 // somebody took the chance to dispose us -> bail out 183 return; 184 185 (m_pListener->*aEvents[i].listenerMethod)( aDocument ); 186 } 187 break; 188 } 189 } 190 191 //-------------------------------------------------------------------- 192 void SAL_CALL DocumentEventNotifier_Impl::disposing( const csslang::EventObject& /*Event*/ ) throw (RuntimeException) 193 { 194 ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); 195 ::osl::MutexGuard aGuard( m_aMutex ); 196 197 if ( !impl_isDisposed_nothrow() ) 198 impl_dispose_nothrow(); 199 } 200 201 //-------------------------------------------------------------------- 202 void SAL_CALL DocumentEventNotifier_Impl::disposing() 203 { 204 impl_listenerAction_nothrow( RemoveListener ); 205 impl_dispose_nothrow(); 206 } 207 208 //-------------------------------------------------------------------- 209 void DocumentEventNotifier_Impl::impl_dispose_nothrow() 210 { 211 m_pListener = NULL; 212 m_xModel.clear(); 213 } 214 215 //-------------------------------------------------------------------- 216 void DocumentEventNotifier_Impl::impl_listenerAction_nothrow( ListenerAction _eAction ) 217 { 218 try 219 { 220 Reference< XEventBroadcaster > xBroadcaster; 221 if ( m_xModel.is() ) 222 xBroadcaster.set( m_xModel, UNO_QUERY_THROW ); 223 else 224 { 225 ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); 226 xBroadcaster.set( 227 aContext.createComponent( "com.sun.star.frame.GlobalEventBroadcaster" ), 228 UNO_QUERY_THROW ); 229 } 230 231 void ( SAL_CALL XEventBroadcaster::*listenerAction )( const Reference< XEventListener >& ) = 232 ( _eAction == RegisterListener ) ? &XEventBroadcaster::addEventListener : &XEventBroadcaster::removeEventListener; 233 (xBroadcaster.get()->*listenerAction)( this ); 234 } 235 catch( const Exception& ) 236 { 237 DBG_UNHANDLED_EXCEPTION(); 238 } 239 } 240 241 //==================================================================== 242 //= DocumentEventNotifier 243 //==================================================================== 244 //-------------------------------------------------------------------- 245 DocumentEventNotifier::DocumentEventNotifier( DocumentEventListener& _rListener, const Reference< XModel >& _rxDocument ) 246 :m_pImpl( new DocumentEventNotifier_Impl( _rListener, _rxDocument ) ) 247 { 248 } 249 250 //-------------------------------------------------------------------- 251 DocumentEventNotifier::DocumentEventNotifier( DocumentEventListener& _rListener ) 252 :m_pImpl( new DocumentEventNotifier_Impl( _rListener, Reference< XModel >() ) ) 253 { 254 } 255 256 //-------------------------------------------------------------------- 257 DocumentEventNotifier::~DocumentEventNotifier() 258 { 259 } 260 261 //-------------------------------------------------------------------- 262 void DocumentEventNotifier::dispose() 263 { 264 m_pImpl->dispose(); 265 } 266 267 //==================================================================== 268 //= DocumentEventListener 269 //==================================================================== 270 DocumentEventListener::~DocumentEventListener() 271 { 272 } 273 274 //........................................................................ 275 } // namespace basctl 276 //........................................................................ 277