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_basctl.hxx" 26 27 #include "doceventnotifier.hxx" 28 #include "scriptdocument.hxx" 29 30 /** === begin UNO includes === **/ 31 #include <com/sun/star/document/XEventBroadcaster.hpp> 32 /** === end UNO includes === **/ 33 34 #include <vcl/svapp.hxx> 35 36 #include <tools/diagnose_ex.h> 37 38 #include <comphelper/componentcontext.hxx> 39 #include <comphelper/processfactory.hxx> 40 41 #include <vos/mutex.hxx> 42 43 #include <cppuhelper/compbase1.hxx> 44 #include <cppuhelper/basemutex.hxx> 45 46 //........................................................................ 47 namespace basctl 48 { 49 //........................................................................ 50 51 /** === begin UNO using === **/ 52 using ::com::sun::star::document::XEventBroadcaster; 53 using ::com::sun::star::document::XEventListener; 54 using ::com::sun::star::document::EventObject; 55 using ::com::sun::star::uno::RuntimeException; 56 using ::com::sun::star::uno::Reference; 57 using ::com::sun::star::uno::UNO_QUERY_THROW; 58 using ::com::sun::star::uno::Exception; 59 using ::com::sun::star::frame::XModel; 60 using ::com::sun::star::uno::UNO_QUERY; 61 /** === end UNO using === **/ 62 namespace csslang = ::com::sun::star::lang; 63 64 //==================================================================== 65 //= DocumentEventNotifier_Impl 66 //==================================================================== 67 typedef ::cppu::WeakComponentImplHelper1 < XEventListener 68 > DocumentEventNotifier_Impl_Base; 69 70 enum ListenerAction 71 { 72 RegisterListener, 73 RemoveListener 74 }; 75 76 /** impl class for DocumentEventNotifier 77 */ 78 class DocumentEventNotifier_Impl :public ::boost::noncopyable 79 ,public ::cppu::BaseMutex 80 ,public DocumentEventNotifier_Impl_Base 81 { 82 public: 83 DocumentEventNotifier_Impl( DocumentEventListener& _rListener, const Reference< XModel >& _rxDocument ); 84 85 // document::XEventListener 86 virtual void SAL_CALL notifyEvent( const EventObject& Event ) throw (RuntimeException); 87 88 // lang::XEventListener 89 virtual void SAL_CALL disposing( const csslang::EventObject& Event ) throw (RuntimeException); 90 91 // ComponentHelper 92 virtual void SAL_CALL disposing(); 93 94 protected: 95 ~DocumentEventNotifier_Impl(); 96 97 private: 98 /// determines whether the instance is already disposed impl_isDisposed_nothrow() const99 bool impl_isDisposed_nothrow() const { return m_pListener == NULL; } 100 101 /// disposes the instance 102 void impl_dispose_nothrow(); 103 104 /// registers or revokes the instance as listener at the global event broadcaster 105 void impl_listenerAction_nothrow( ListenerAction _eAction ); 106 107 private: 108 DocumentEventListener* m_pListener; 109 Reference< XModel > m_xModel; 110 }; 111 112 //-------------------------------------------------------------------- DocumentEventNotifier_Impl(DocumentEventListener & _rListener,const Reference<XModel> & _rxDocument)113 DocumentEventNotifier_Impl::DocumentEventNotifier_Impl( DocumentEventListener& _rListener, const Reference< XModel >& _rxDocument ) 114 :DocumentEventNotifier_Impl_Base( m_aMutex ) 115 ,m_pListener( &_rListener ) 116 ,m_xModel( _rxDocument ) 117 { 118 osl_incrementInterlockedCount( &m_refCount ); 119 impl_listenerAction_nothrow( RegisterListener ); 120 osl_decrementInterlockedCount( &m_refCount ); 121 } 122 123 //-------------------------------------------------------------------- ~DocumentEventNotifier_Impl()124 DocumentEventNotifier_Impl::~DocumentEventNotifier_Impl() 125 { 126 if ( !impl_isDisposed_nothrow() ) 127 { 128 acquire(); 129 dispose(); 130 } 131 } 132 133 //-------------------------------------------------------------------- notifyEvent(const EventObject & _rEvent)134 void SAL_CALL DocumentEventNotifier_Impl::notifyEvent( const EventObject& _rEvent ) throw (RuntimeException) 135 { 136 ::osl::ClearableMutexGuard aGuard( m_aMutex ); 137 138 OSL_PRECOND( !impl_isDisposed_nothrow(), "DocumentEventNotifier_Impl::notifyEvent: disposed, but still getting events?" ); 139 if ( impl_isDisposed_nothrow() ) 140 return; 141 142 Reference< XModel > xDocument( _rEvent.Source, UNO_QUERY ); 143 OSL_ENSURE( xDocument.is(), "DocumentEventNotifier_Impl::notifyEvent: illegal source document!" ); 144 if ( !xDocument.is() ) 145 return; 146 147 struct EventEntry 148 { 149 const sal_Char* pEventName; 150 void (DocumentEventListener::*listenerMethod)( const ScriptDocument& _rDocument ); 151 }; 152 EventEntry aEvents[] = { 153 { "OnNew", &DocumentEventListener::onDocumentCreated }, 154 { "OnLoad", &DocumentEventListener::onDocumentOpened }, 155 { "OnSave", &DocumentEventListener::onDocumentSave }, 156 { "OnSaveDone", &DocumentEventListener::onDocumentSaveDone }, 157 { "OnSaveAs", &DocumentEventListener::onDocumentSaveAs }, 158 { "OnSaveAsDone", &DocumentEventListener::onDocumentSaveAsDone }, 159 { "OnUnload", &DocumentEventListener::onDocumentClosed }, 160 { "OnTitleChanged", &DocumentEventListener::onDocumentTitleChanged }, 161 { "OnModeChanged", &DocumentEventListener::onDocumentModeChanged } 162 }; 163 164 for ( size_t i=0; i < sizeof( aEvents ) / sizeof( aEvents[0] ); ++i ) 165 { 166 if ( !_rEvent.EventName.equalsAscii( aEvents[i].pEventName ) ) 167 continue; 168 169 ScriptDocument aDocument( xDocument ); 170 { 171 // the listener implementations usually require the SolarMutex, so lock it here. 172 // But ensure the proper order of locking the solar and the own mutex 173 aGuard.clear(); 174 ::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() ); 175 ::osl::MutexGuard aGuard2( m_aMutex ); 176 177 if ( impl_isDisposed_nothrow() ) 178 // somebody took the chance to dispose us -> bail out 179 return; 180 181 (m_pListener->*aEvents[i].listenerMethod)( aDocument ); 182 } 183 break; 184 } 185 } 186 187 //-------------------------------------------------------------------- disposing(const csslang::EventObject &)188 void SAL_CALL DocumentEventNotifier_Impl::disposing( const csslang::EventObject& /*Event*/ ) throw (RuntimeException) 189 { 190 ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); 191 ::osl::MutexGuard aGuard( m_aMutex ); 192 193 if ( !impl_isDisposed_nothrow() ) 194 impl_dispose_nothrow(); 195 } 196 197 //-------------------------------------------------------------------- disposing()198 void SAL_CALL DocumentEventNotifier_Impl::disposing() 199 { 200 impl_listenerAction_nothrow( RemoveListener ); 201 impl_dispose_nothrow(); 202 } 203 204 //-------------------------------------------------------------------- impl_dispose_nothrow()205 void DocumentEventNotifier_Impl::impl_dispose_nothrow() 206 { 207 m_pListener = NULL; 208 m_xModel.clear(); 209 } 210 211 //-------------------------------------------------------------------- impl_listenerAction_nothrow(ListenerAction _eAction)212 void DocumentEventNotifier_Impl::impl_listenerAction_nothrow( ListenerAction _eAction ) 213 { 214 try 215 { 216 Reference< XEventBroadcaster > xBroadcaster; 217 if ( m_xModel.is() ) 218 xBroadcaster.set( m_xModel, UNO_QUERY_THROW ); 219 else 220 { 221 ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); 222 xBroadcaster.set( 223 aContext.createComponent( "com.sun.star.frame.GlobalEventBroadcaster" ), 224 UNO_QUERY_THROW ); 225 } 226 227 void ( SAL_CALL XEventBroadcaster::*listenerAction )( const Reference< XEventListener >& ) = 228 ( _eAction == RegisterListener ) ? &XEventBroadcaster::addEventListener : &XEventBroadcaster::removeEventListener; 229 (xBroadcaster.get()->*listenerAction)( this ); 230 } 231 catch( const Exception& ) 232 { 233 DBG_UNHANDLED_EXCEPTION(); 234 } 235 } 236 237 //==================================================================== 238 //= DocumentEventNotifier 239 //==================================================================== 240 //-------------------------------------------------------------------- DocumentEventNotifier(DocumentEventListener & _rListener,const Reference<XModel> & _rxDocument)241 DocumentEventNotifier::DocumentEventNotifier( DocumentEventListener& _rListener, const Reference< XModel >& _rxDocument ) 242 :m_pImpl( new DocumentEventNotifier_Impl( _rListener, _rxDocument ) ) 243 { 244 } 245 246 //-------------------------------------------------------------------- DocumentEventNotifier(DocumentEventListener & _rListener)247 DocumentEventNotifier::DocumentEventNotifier( DocumentEventListener& _rListener ) 248 :m_pImpl( new DocumentEventNotifier_Impl( _rListener, Reference< XModel >() ) ) 249 { 250 } 251 252 //-------------------------------------------------------------------- ~DocumentEventNotifier()253 DocumentEventNotifier::~DocumentEventNotifier() 254 { 255 } 256 257 //-------------------------------------------------------------------- dispose()258 void DocumentEventNotifier::dispose() 259 { 260 m_pImpl->dispose(); 261 } 262 263 //==================================================================== 264 //= DocumentEventListener 265 //==================================================================== ~DocumentEventListener()266 DocumentEventListener::~DocumentEventListener() 267 { 268 } 269 270 //........................................................................ 271 } // namespace basctl 272 //........................................................................ 273