1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <dbaccess/controllerframe.hxx> 21 #include <dbaccess/IController.hxx> 22 23 #include <com/sun/star/awt/XTopWindow.hpp> 24 #include <com/sun/star/awt/XWindow2.hpp> 25 #include <com/sun/star/lang/DisposedException.hpp> 26 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp> 27 #include <com/sun/star/frame/XController2.hpp> 28 29 #include <cppuhelper/implbase.hxx> 30 #include <rtl/ref.hxx> 31 #include <sfx2/objsh.hxx> 32 #include <tools/diagnose_ex.h> 33 #include <toolkit/helper/vclunohelper.hxx> 34 #include <vcl/window.hxx> 35 36 namespace dbaui 37 { 38 39 using ::com::sun::star::uno::Reference; 40 using ::com::sun::star::uno::XInterface; 41 using ::com::sun::star::uno::UNO_QUERY; 42 using ::com::sun::star::uno::UNO_QUERY_THROW; 43 using ::com::sun::star::uno::UNO_SET_THROW; 44 using ::com::sun::star::uno::Exception; 45 using ::com::sun::star::uno::RuntimeException; 46 using ::com::sun::star::uno::Any; 47 using ::com::sun::star::frame::XFrame; 48 using ::com::sun::star::frame::FrameAction; 49 using ::com::sun::star::frame::FrameAction_FRAME_ACTIVATED; 50 using ::com::sun::star::frame::FrameAction_FRAME_UI_ACTIVATED; 51 using ::com::sun::star::frame::FrameAction_FRAME_DEACTIVATING; 52 using ::com::sun::star::frame::FrameAction_FRAME_UI_DEACTIVATING; 53 using ::com::sun::star::frame::XModel; 54 using ::com::sun::star::frame::XController; 55 using ::com::sun::star::frame::XController2; 56 using ::com::sun::star::awt::XTopWindow; 57 using ::com::sun::star::awt::XTopWindowListener; 58 using ::com::sun::star::awt::XWindow2; 59 using ::com::sun::star::lang::DisposedException; 60 using ::com::sun::star::lang::EventObject; 61 using ::com::sun::star::document::XDocumentEventBroadcaster; 62 using ::com::sun::star::awt::XWindow; 63 64 // FrameWindowActivationListener 65 typedef ::cppu::WeakImplHelper< XTopWindowListener 66 > FrameWindowActivationListener_Base; 67 68 namespace { 69 70 class FrameWindowActivationListener : public FrameWindowActivationListener_Base 71 { 72 public: 73 explicit FrameWindowActivationListener( ControllerFrame_Data& _rData ); 74 75 void dispose(); 76 77 protected: 78 virtual ~FrameWindowActivationListener() override; 79 80 // XTopWindowListener 81 virtual void SAL_CALL windowOpened( const css::lang::EventObject& e ) override; 82 virtual void SAL_CALL windowClosing( const css::lang::EventObject& e ) override; 83 virtual void SAL_CALL windowClosed( const css::lang::EventObject& e ) override; 84 virtual void SAL_CALL windowMinimized( const css::lang::EventObject& e ) override; 85 virtual void SAL_CALL windowNormalized( const css::lang::EventObject& e ) override; 86 virtual void SAL_CALL windowActivated( const css::lang::EventObject& e ) override; 87 virtual void SAL_CALL windowDeactivated( const css::lang::EventObject& e ) override; 88 89 // XEventListener 90 virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; 91 92 private: 93 void impl_checkDisposed_throw() const; 94 void impl_registerOnFrameContainerWindow_nothrow( bool _bRegister ); 95 96 private: 97 ControllerFrame_Data* m_pData; 98 }; 99 100 } 101 102 // ControllerFrame_Data 103 struct ControllerFrame_Data 104 { ControllerFrame_Datadbaui::ControllerFrame_Data105 explicit ControllerFrame_Data( IController& _rController ) 106 :m_rController( _rController ) 107 ,m_xFrame() 108 ,m_xDocEventBroadcaster() 109 ,m_pListener() 110 ,m_bActive( false ) 111 ,m_bIsTopLevelDocumentWindow( false ) 112 { 113 } 114 115 IController& m_rController; 116 Reference< XFrame > m_xFrame; 117 Reference< XDocumentEventBroadcaster > m_xDocEventBroadcaster; 118 ::rtl::Reference< FrameWindowActivationListener > m_pListener; 119 bool m_bActive; 120 bool m_bIsTopLevelDocumentWindow; 121 }; 122 123 // helper lcl_setFrame_nothrow(ControllerFrame_Data & _rData,const Reference<XFrame> & _rxFrame)124 static void lcl_setFrame_nothrow( ControllerFrame_Data& _rData, const Reference< XFrame >& _rxFrame ) 125 { 126 // release old listener 127 if (_rData.m_pListener) 128 { 129 _rData.m_pListener->dispose(); 130 _rData.m_pListener = nullptr; 131 } 132 133 // remember new frame 134 _rData.m_xFrame = _rxFrame; 135 136 // create new listener 137 if ( _rData.m_xFrame.is() ) 138 _rData.m_pListener = new FrameWindowActivationListener( _rData ); 139 140 // at this point in time, we can assume the controller also has a model set, if it supports models 141 try 142 { 143 Reference< XController > xController( _rData.m_rController.getXController(), UNO_SET_THROW ); 144 Reference< XModel > xModel( xController->getModel() ); 145 if ( xModel.is() ) 146 _rData.m_xDocEventBroadcaster.set( xModel, UNO_QUERY ); 147 } 148 catch( const Exception& ) 149 { 150 DBG_UNHANDLED_EXCEPTION("dbaccess"); 151 } 152 } 153 lcl_isActive_nothrow(const Reference<XFrame> & _rxFrame)154 static bool lcl_isActive_nothrow( const Reference< XFrame >& _rxFrame ) 155 { 156 bool bIsActive = false; 157 try 158 { 159 if ( _rxFrame.is() ) 160 { 161 Reference< XWindow2 > xWindow( _rxFrame->getContainerWindow(), UNO_QUERY_THROW ); 162 bIsActive = xWindow->isActive(); 163 } 164 165 } 166 catch( const Exception& ) 167 { 168 DBG_UNHANDLED_EXCEPTION("dbaccess"); 169 } 170 return bIsActive; 171 } 172 173 /** updates various global and local states with a new active component 174 175 In particular, the following are updated 176 * the global working document (aka Basic's ThisComponent in the application 177 Basic), with our controller's model, or the controller itself if there is no such 178 model. 179 */ lcl_updateActiveComponents_nothrow(const ControllerFrame_Data & _rData)180 static void lcl_updateActiveComponents_nothrow( const ControllerFrame_Data& _rData ) 181 { 182 try 183 { 184 Reference< XController > xCompController( _rData.m_rController.getXController() ); 185 OSL_ENSURE( xCompController.is(), "lcl_updateActiveComponents_nothrow: can't do anything without a controller!" ); 186 if ( !xCompController.is() ) 187 return; 188 189 if ( _rData.m_bActive && _rData.m_bIsTopLevelDocumentWindow ) 190 { 191 // set the "current component" at the SfxObjectShell 192 Reference< XModel > xModel( xCompController->getModel() ); 193 Reference< XInterface > xCurrentComponent; 194 if ( xModel.is() ) 195 xCurrentComponent = xModel; 196 else 197 xCurrentComponent = xCompController; 198 SfxObjectShell::SetCurrentComponent( xCurrentComponent ); 199 } 200 } 201 catch( const Exception& ) 202 { 203 DBG_UNHANDLED_EXCEPTION("dbaccess"); 204 } 205 } 206 207 /** broadcasts the OnFocus resp. OnUnfocus event 208 */ lcl_notifyFocusChange_nothrow(ControllerFrame_Data & _rData,bool _bActive)209 static void lcl_notifyFocusChange_nothrow( ControllerFrame_Data& _rData, bool _bActive ) 210 { 211 try 212 { 213 if ( _rData.m_xDocEventBroadcaster.is() ) 214 { 215 OUString sEventName = _bActive ? OUString("OnFocus") : OUString("OnUnfocus"); 216 Reference< XController2 > xController( _rData.m_rController.getXController(), UNO_QUERY_THROW ); 217 _rData.m_xDocEventBroadcaster->notifyDocumentEvent( sEventName, xController, Any() ); 218 } 219 } 220 catch( const Exception& ) 221 { 222 DBG_UNHANDLED_EXCEPTION("dbaccess"); 223 } 224 } 225 lcl_updateActive_nothrow(ControllerFrame_Data & _rData,bool _bActive)226 static void lcl_updateActive_nothrow( ControllerFrame_Data& _rData, bool _bActive ) 227 { 228 if ( _rData.m_bActive == _bActive ) 229 return; 230 _rData.m_bActive = _bActive; 231 232 lcl_updateActiveComponents_nothrow( _rData ); 233 lcl_notifyFocusChange_nothrow( _rData, _bActive ); 234 } 235 FrameWindowActivationListener(ControllerFrame_Data & _rData)236 FrameWindowActivationListener::FrameWindowActivationListener( ControllerFrame_Data& _rData ) 237 :m_pData( &_rData ) 238 { 239 impl_registerOnFrameContainerWindow_nothrow( true ); 240 } 241 ~FrameWindowActivationListener()242 FrameWindowActivationListener::~FrameWindowActivationListener() 243 { 244 } 245 dispose()246 void FrameWindowActivationListener::dispose() 247 { 248 impl_registerOnFrameContainerWindow_nothrow( false ); 249 m_pData = nullptr; 250 } 251 impl_registerOnFrameContainerWindow_nothrow(bool _bRegister)252 void FrameWindowActivationListener::impl_registerOnFrameContainerWindow_nothrow( bool _bRegister ) 253 { 254 OSL_ENSURE( m_pData && m_pData->m_xFrame.is(), "FrameWindowActivationListener::impl_registerOnFrameContainerWindow_nothrow: no frame!" ); 255 if ( !m_pData || !m_pData->m_xFrame.is() ) 256 return; 257 258 try 259 { 260 void ( SAL_CALL XTopWindow::*pListenerAction )( const Reference< XTopWindowListener >& ) = 261 _bRegister ? &XTopWindow::addTopWindowListener : &XTopWindow::removeTopWindowListener; 262 263 const Reference< XWindow > xContainerWindow( m_pData->m_xFrame->getContainerWindow(), UNO_SET_THROW ); 264 if ( _bRegister ) 265 { 266 const vcl::Window* pContainerWindow = VCLUnoHelper::GetWindow( xContainerWindow ); 267 ENSURE_OR_THROW( pContainerWindow, "no Window implementation for the frame's container window!" ); 268 269 m_pData->m_bIsTopLevelDocumentWindow = bool( pContainerWindow->GetExtendedStyle() & WindowExtendedStyle::Document ); 270 } 271 272 const Reference< XTopWindow > xFrameContainer( xContainerWindow, UNO_QUERY ); 273 if ( xFrameContainer.is() ) 274 (xFrameContainer.get()->*pListenerAction)( this ); 275 } 276 catch( const Exception& ) 277 { 278 DBG_UNHANDLED_EXCEPTION("dbaccess"); 279 } 280 } 281 impl_checkDisposed_throw() const282 void FrameWindowActivationListener::impl_checkDisposed_throw() const 283 { 284 if ( !m_pData ) 285 throw DisposedException( OUString(), *const_cast< FrameWindowActivationListener* >( this ) ); 286 } 287 windowOpened(const EventObject &)288 void SAL_CALL FrameWindowActivationListener::windowOpened( const EventObject& /*_rEvent*/ ) 289 { 290 // not interested in 291 } 292 windowClosing(const EventObject &)293 void SAL_CALL FrameWindowActivationListener::windowClosing( const EventObject& /*_rEvent*/ ) 294 { 295 // not interested in 296 } 297 windowClosed(const EventObject &)298 void SAL_CALL FrameWindowActivationListener::windowClosed( const EventObject& /*_rEvent*/ ) 299 { 300 // not interested in 301 } 302 windowMinimized(const EventObject &)303 void SAL_CALL FrameWindowActivationListener::windowMinimized( const EventObject& /*_rEvent*/ ) 304 { 305 // not interested in 306 } 307 windowNormalized(const EventObject &)308 void SAL_CALL FrameWindowActivationListener::windowNormalized( const EventObject& /*_rEvent*/ ) 309 { 310 // not interested in 311 } 312 windowActivated(const EventObject &)313 void SAL_CALL FrameWindowActivationListener::windowActivated( const EventObject& /*_rEvent*/ ) 314 { 315 impl_checkDisposed_throw(); 316 lcl_updateActive_nothrow( *m_pData, true ); 317 } 318 windowDeactivated(const EventObject &)319 void SAL_CALL FrameWindowActivationListener::windowDeactivated( const EventObject& /*_rEvent*/ ) 320 { 321 impl_checkDisposed_throw(); 322 lcl_updateActive_nothrow( *m_pData, false ); 323 } 324 disposing(const EventObject &)325 void SAL_CALL FrameWindowActivationListener::disposing( const EventObject& /*_rEvent*/ ) 326 { 327 dispose(); 328 } 329 330 // ControllerFrame ControllerFrame(IController & _rController)331 ControllerFrame::ControllerFrame( IController& _rController ) 332 :m_pData( new ControllerFrame_Data( _rController ) ) 333 { 334 } 335 ~ControllerFrame()336 ControllerFrame::~ControllerFrame() 337 { 338 } 339 attachFrame(const Reference<XFrame> & _rxFrame)340 const Reference< XFrame >& ControllerFrame::attachFrame( const Reference< XFrame >& _rxFrame ) 341 { 342 // set new frame, including listener handling 343 lcl_setFrame_nothrow( *m_pData, _rxFrame ); 344 345 // determine whether we're active 346 m_pData->m_bActive = lcl_isActive_nothrow( m_pData->m_xFrame ); 347 348 // update active component 349 if ( m_pData->m_bActive ) 350 { 351 lcl_updateActiveComponents_nothrow( *m_pData ); 352 lcl_notifyFocusChange_nothrow( *m_pData, true ); 353 } 354 355 return m_pData->m_xFrame; 356 } 357 getFrame() const358 const Reference< XFrame >& ControllerFrame::getFrame() const 359 { 360 return m_pData->m_xFrame; 361 } 362 isActive() const363 bool ControllerFrame::isActive() const 364 { 365 return m_pData->m_bActive; 366 } 367 frameAction(FrameAction _eAction)368 void ControllerFrame::frameAction( FrameAction _eAction ) 369 { 370 bool bActive = m_pData->m_bActive; 371 372 switch ( _eAction ) 373 { 374 case FrameAction_FRAME_ACTIVATED: 375 case FrameAction_FRAME_UI_ACTIVATED: 376 bActive = true; 377 break; 378 379 case FrameAction_FRAME_DEACTIVATING: 380 case FrameAction_FRAME_UI_DEACTIVATING: 381 bActive = false; 382 break; 383 384 default: 385 break; 386 } 387 388 lcl_updateActive_nothrow( *m_pData, bActive ); 389 } 390 391 } // namespace dbaui 392 393 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 394