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 #include "subcomponentmanager.hxx" 25 #include "AppController.hxx" 26 #include "dbustrings.hrc" 27 28 /** === begin UNO includes === **/ 29 #include <com/sun/star/frame/XFrame.hpp> 30 #include <com/sun/star/frame/XModel.hpp> 31 #include <com/sun/star/frame/XModel2.hpp> 32 #include <com/sun/star/util/XCloseable.hpp> 33 #include <com/sun/star/awt/XTopWindow.hpp> 34 #include <com/sun/star/embed/XComponentSupplier.hpp> 35 #include <com/sun/star/ucb/XCommandProcessor.hpp> 36 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp> 37 #include <com/sun/star/beans/XPropertySet.hpp> 38 /** === end UNO includes === **/ 39 40 #include <tools/diagnose_ex.h> 41 #include <vcl/svapp.hxx> 42 #include <vos/mutex.hxx> 43 44 #include <hash_map> 45 #include <algorithm> 46 #include <functional> 47 48 //...................................................................................................................... 49 namespace dbaui 50 { 51 //...................................................................................................................... 52 53 /** === begin UNO using === **/ 54 using ::com::sun::star::uno::Reference; 55 using ::com::sun::star::uno::XInterface; 56 using ::com::sun::star::uno::UNO_QUERY; 57 using ::com::sun::star::uno::UNO_QUERY_THROW; 58 using ::com::sun::star::uno::UNO_SET_THROW; 59 using ::com::sun::star::uno::Exception; 60 using ::com::sun::star::uno::RuntimeException; 61 using ::com::sun::star::uno::Any; 62 using ::com::sun::star::uno::makeAny; 63 using ::com::sun::star::uno::Sequence; 64 using ::com::sun::star::uno::Type; 65 using ::com::sun::star::frame::XFrame; 66 using ::com::sun::star::frame::XController; 67 using ::com::sun::star::frame::XModel; 68 using ::com::sun::star::lang::EventObject; 69 using ::com::sun::star::lang::XComponent; 70 using ::com::sun::star::frame::XModel2; 71 using ::com::sun::star::container::XEnumeration; 72 using ::com::sun::star::util::XCloseable; 73 using ::com::sun::star::awt::XTopWindow; 74 using ::com::sun::star::embed::XComponentSupplier; 75 using ::com::sun::star::ucb::XCommandProcessor; 76 using ::com::sun::star::ucb::Command; 77 using ::com::sun::star::document::XDocumentEventBroadcaster; 78 using ::com::sun::star::beans::XPropertySet; 79 using ::com::sun::star::beans::PropertyChangeEvent; 80 /** === end UNO using === **/ 81 82 //================================================================================================================== 83 //= helper structs 84 //================================================================================================================== 85 namespace 86 { 87 //.............................................................................................................. 88 struct SubComponentDescriptor 89 { 90 /// the name of the sub component, empty if it is yet unsaved 91 ::rtl::OUString sName; 92 /// type of the component - an ElementType value, except for relation design 93 sal_Int32 nComponentType; 94 /// the mode in which the sub component has been opened 95 ElementOpenMode eOpenMode; 96 /// the frame which the component resides in. Must not be <NULL/> 97 Reference< XFrame > xFrame; 98 /// the controller of the sub component. Must not be <NULL/> 99 Reference< XController > xController; 100 /// the model of the sub component. Might be <NULL/> 101 Reference< XModel > xModel; 102 /// the document definition which holds the component, if any; as CommandProcessor 103 Reference< XCommandProcessor > xComponentCommandProcessor; 104 /// the document definition which holds the component, if any; as PropertySet 105 Reference< XPropertySet > xDocumentDefinitionProperties; 106 SubComponentDescriptordbaui::__anonf38c9db30111::SubComponentDescriptor107 SubComponentDescriptor() 108 :sName() 109 ,nComponentType( -1 ) 110 ,eOpenMode( E_OPEN_NORMAL ) 111 ,xFrame() 112 ,xController() 113 ,xModel() 114 { 115 } 116 SubComponentDescriptordbaui::__anonf38c9db30111::SubComponentDescriptor117 SubComponentDescriptor( const ::rtl::OUString& i_rName, const sal_Int32 i_nComponentType, 118 const ElementOpenMode i_eOpenMode, const Reference< XComponent >& i_rComponent ) 119 :sName( i_rName ) 120 ,nComponentType( i_nComponentType ) 121 ,eOpenMode( i_eOpenMode ) 122 { 123 if ( !impl_constructFrom( i_rComponent ) ) 124 { 125 // i_rComponent is neither a model, nor a controller, nor a frame 126 // => it must be a css.sdb.DocumentDefinition 127 Reference< XComponentSupplier > xCompSupp( i_rComponent, UNO_QUERY_THROW ); 128 Reference< XComponent > xComponent( xCompSupp->getComponent(), UNO_QUERY_THROW ); 129 if ( !impl_constructFrom( xComponent ) ) 130 throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Illegal component type." ) ), NULL ); 131 xComponentCommandProcessor.set( i_rComponent, UNO_QUERY_THROW ); 132 xDocumentDefinitionProperties.set( i_rComponent, UNO_QUERY_THROW ); 133 } 134 } 135 isdbaui::__anonf38c9db30111::SubComponentDescriptor136 inline bool is() const { return xFrame.is(); } 137 138 private: impl_constructFromdbaui::__anonf38c9db30111::SubComponentDescriptor139 bool impl_constructFrom( const Reference< XComponent >& _rxComponent ) 140 { 141 // is it a model? 142 xModel.set( _rxComponent, UNO_QUERY ); 143 if ( xModel.is() ) 144 { 145 xController.set( xModel->getCurrentController() ); 146 if ( xController.is() ) 147 xFrame.set( xController->getFrame(), UNO_SET_THROW ); 148 } 149 else 150 { 151 // is it a controller? 152 xController.set( _rxComponent, UNO_QUERY ); 153 if ( xController.is() ) 154 { 155 xFrame.set( xController->getFrame(), UNO_SET_THROW ); 156 } 157 else 158 { 159 // is it a frame? 160 xFrame.set( _rxComponent, UNO_QUERY ); 161 if ( !xFrame.is() ) 162 return false; 163 164 // ensure we have a controller 165 xController.set( xFrame->getController(), UNO_SET_THROW ); 166 } 167 168 // check wether there is a model (not required) 169 xModel.set( xController->getModel() ); 170 } 171 172 return true; 173 } 174 }; 175 176 //.............................................................................................................. 177 struct SelectSubComponent : public ::std::unary_function< SubComponentDescriptor, Reference< XComponent > > 178 { operator ()dbaui::__anonf38c9db30111::SelectSubComponent179 Reference< XComponent > operator()( const SubComponentDescriptor _desc ) const 180 { 181 if ( _desc.xModel.is() ) 182 return _desc.xModel.get(); 183 OSL_ENSURE( _desc.xController.is(), "SelectSubComponent::operator(): illegal component!" ); 184 return _desc.xController.get(); 185 } 186 }; 187 188 //.............................................................................................................. 189 typedef ::std::vector< SubComponentDescriptor > SubComponents; 190 191 //.............................................................................................................. 192 struct SubComponentMatch : public ::std::unary_function< SubComponentDescriptor, bool > 193 { 194 public: SubComponentMatchdbaui::__anonf38c9db30111::SubComponentMatch195 SubComponentMatch( const ::rtl::OUString& i_rName, const sal_Int32 i_nComponentType, 196 const ElementOpenMode i_eOpenMode ) 197 :m_sName( i_rName ) 198 ,m_nComponentType( i_nComponentType ) 199 ,m_eOpenMode( i_eOpenMode ) 200 { 201 } 202 operator ()dbaui::__anonf38c9db30111::SubComponentMatch203 bool operator()( const SubComponentDescriptor& i_rCompareWith ) const 204 { 205 return ( m_sName == i_rCompareWith.sName ) 206 && ( m_nComponentType == i_rCompareWith.nComponentType ) 207 && ( m_eOpenMode == i_rCompareWith.eOpenMode ); 208 } 209 private: 210 const ::rtl::OUString m_sName; 211 const sal_Int32 m_nComponentType; 212 const ElementOpenMode m_eOpenMode; 213 }; 214 } 215 216 //================================================================================================================== 217 //= SubComponentManager_Data 218 //================================================================================================================== 219 struct SubComponentManager_Data 220 { SubComponentManager_Datadbaui::SubComponentManager_Data221 SubComponentManager_Data( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex ) 222 :m_rController( _rController ) 223 ,m_aMutex( _rMutex ) 224 { 225 } 226 227 OApplicationController& m_rController; 228 mutable ::comphelper::SharedMutex m_aMutex; 229 SubComponents m_aComponents; 230 getMutexdbaui::SubComponentManager_Data231 ::osl::Mutex& getMutex() const { return m_aMutex; } 232 }; 233 234 //================================================================================================================== 235 //= SubComponentManager 236 //================================================================================================================== 237 //------------------------------------------------------------------------------------------------------------------ SubComponentManager(OApplicationController & _rController,const::comphelper::SharedMutex & _rMutex)238 SubComponentManager::SubComponentManager( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex ) 239 :m_pData( new SubComponentManager_Data( _rController, _rMutex ) ) 240 { 241 } 242 243 //------------------------------------------------------------------------------------------------------------------ ~SubComponentManager()244 SubComponentManager::~SubComponentManager() 245 { 246 } 247 248 //------------------------------------------------------------------------------------------------------------------ disposing()249 void SubComponentManager::disposing() 250 { 251 ::osl::MutexGuard aGuard( m_pData->getMutex() ); 252 m_pData->m_aComponents.clear(); 253 } 254 255 //------------------------------------------------------------------------------------------------------------------ 256 namespace 257 { 258 //.............................................................................................................. lcl_fallbackToAnotherController(SubComponentDescriptor & _rCompDesc)259 bool lcl_fallbackToAnotherController( SubComponentDescriptor& _rCompDesc ) 260 { 261 Reference< XController > xFallback; 262 OSL_PRECOND( _rCompDesc.xModel.is(), "lcl_fallbackToAnotherController: illegal call!" ); 263 if ( !_rCompDesc.xModel.is() ) 264 return false; 265 266 xFallback.set( _rCompDesc.xModel->getCurrentController() ); 267 if ( xFallback == _rCompDesc.xController ) 268 // don't accept the very same controller as fallback 269 xFallback.clear(); 270 271 if ( !xFallback.is() ) 272 { 273 // perhaps XModel2 can be of help here 274 Reference< XModel2 > xModel2( _rCompDesc.xModel, UNO_QUERY ); 275 Reference< XEnumeration > xControllerEnum; 276 if ( xModel2.is() ) 277 xControllerEnum = xModel2->getControllers(); 278 while ( xControllerEnum.is() && xControllerEnum->hasMoreElements() ) 279 { 280 xFallback.set( xControllerEnum->nextElement(), UNO_QUERY ); 281 if ( xFallback == _rCompDesc.xController ) 282 xFallback.clear(); 283 } 284 } 285 286 if ( xFallback.is() ) 287 { 288 _rCompDesc.xController = xFallback; 289 _rCompDesc.xFrame.set( xFallback->getFrame(), UNO_SET_THROW ); 290 return true; 291 } 292 293 return false; 294 } 295 296 //.............................................................................................................. lcl_closeComponent(const Reference<XCommandProcessor> & _rxCommandProcessor)297 bool lcl_closeComponent( const Reference< XCommandProcessor >& _rxCommandProcessor ) 298 { 299 bool bSuccess = false; 300 try 301 { 302 Reference< XCommandProcessor > xCommandProcessor( _rxCommandProcessor, UNO_SET_THROW ); 303 sal_Int32 nCommandIdentifier = xCommandProcessor->createCommandIdentifier(); 304 305 Command aCommand; 306 aCommand.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "close" ) ); 307 xCommandProcessor->execute( aCommand, nCommandIdentifier, NULL ); 308 bSuccess = true; 309 } 310 catch( const Exception& ) 311 { 312 DBG_UNHANDLED_EXCEPTION(); 313 } 314 return bSuccess; 315 } 316 317 //.............................................................................................................. lcl_closeComponent(const SubComponentDescriptor & _rComponent)318 bool lcl_closeComponent( const SubComponentDescriptor& _rComponent ) 319 { 320 if ( _rComponent.xComponentCommandProcessor.is() ) 321 return lcl_closeComponent( _rComponent.xComponentCommandProcessor ); 322 323 Reference< XController > xController( _rComponent.xController ); 324 OSL_ENSURE( xController.is(), "lcl_closeComponent: invalid controller!" ); 325 326 // suspend the controller in the document 327 if ( xController.is() ) 328 if ( !xController->suspend( sal_True ) ) 329 return false; 330 331 bool bSuccess = false; 332 try 333 { 334 Reference< XCloseable > xCloseable( _rComponent.xFrame, UNO_QUERY_THROW ); 335 xCloseable->close( sal_True ); 336 bSuccess = true; 337 } 338 catch( const Exception& ) 339 { 340 DBG_UNHANDLED_EXCEPTION(); 341 } 342 return bSuccess; 343 } 344 345 //.............................................................................................................. lcl_notifySubComponentEvent(const SubComponentManager_Data & _rData,const sal_Char * _pAsciiEventName,const SubComponentDescriptor & _rComponent)346 void lcl_notifySubComponentEvent( const SubComponentManager_Data& _rData, const sal_Char* _pAsciiEventName, 347 const SubComponentDescriptor& _rComponent ) 348 { 349 try 350 { 351 Reference< XDocumentEventBroadcaster > xBroadcaster( _rData.m_rController.getModel(), UNO_QUERY_THROW ); 352 xBroadcaster->notifyDocumentEvent( 353 ::rtl::OUString::createFromAscii( _pAsciiEventName ), 354 &_rData.m_rController, 355 makeAny( _rComponent.xFrame ) 356 ); 357 } 358 catch( const Exception& ) 359 { 360 DBG_UNHANDLED_EXCEPTION(); 361 } 362 } 363 } 364 365 //------------------------------------------------------------------------------------------------------------------ propertyChange(const PropertyChangeEvent & i_rEvent)366 void SAL_CALL SubComponentManager::propertyChange( const PropertyChangeEvent& i_rEvent ) throw (RuntimeException) 367 { 368 if ( i_rEvent.PropertyName != PROPERTY_NAME ) 369 // by definition, it's allowed to broadcast more than what we've registered for 370 return; 371 372 // find the sub component whose name changed 373 for ( SubComponents::iterator comp = m_pData->m_aComponents.begin(); 374 comp != m_pData->m_aComponents.end(); 375 ++comp 376 ) 377 { 378 if ( comp->xDocumentDefinitionProperties != i_rEvent.Source ) 379 continue; 380 381 ::rtl::OUString sNewName; 382 OSL_VERIFY( i_rEvent.NewValue >>= sNewName ); 383 384 #if OSL_DEBUG_LEVEL > 0 385 ::rtl::OUString sOldKnownName( comp->sName ); 386 ::rtl::OUString sOldName; 387 OSL_VERIFY( i_rEvent.OldValue >>= sOldName ); 388 OSL_ENSURE( sOldName == sOldKnownName, "SubComponentManager::propertyChange: inconsistency in the old names!" ); 389 #endif 390 391 comp->sName = sNewName; 392 break; 393 } 394 } 395 396 //------------------------------------------------------------------------------------------------------------------ disposing(const EventObject & _rSource)397 void SAL_CALL SubComponentManager::disposing( const EventObject& _rSource ) throw (RuntimeException) 398 { 399 ::osl::ClearableMutexGuard aGuard( m_pData->getMutex() ); 400 401 SubComponentDescriptor aClosedComponent; 402 403 for ( SubComponents::iterator comp = m_pData->m_aComponents.begin(); 404 comp != m_pData->m_aComponents.end(); 405 ++comp 406 ) 407 { 408 bool bRemove = false; 409 410 if ( comp->xController == _rSource.Source ) 411 { 412 if ( !comp->xModel.is() ) 413 { 414 bRemove = true; 415 } 416 else 417 { 418 // maybe this is just one view to the sub document, and only this view is closed 419 if ( !lcl_fallbackToAnotherController( *comp ) ) 420 { 421 bRemove = true; 422 } 423 } 424 } 425 else if ( comp->xModel == _rSource.Source ) 426 { 427 bRemove = true; 428 } 429 430 if ( bRemove ) 431 { 432 aClosedComponent = *comp; 433 m_pData->m_aComponents.erase( comp ); 434 break; 435 } 436 } 437 438 if ( aClosedComponent.is() ) 439 { 440 aGuard.clear(); 441 lcl_notifySubComponentEvent( *m_pData, "OnSubComponentClosed", aClosedComponent ); 442 } 443 } 444 445 //------------------------------------------------------------------------------------------------------------------ getSubComponents() const446 Sequence< Reference< XComponent> > SubComponentManager::getSubComponents() const 447 { 448 ::osl::MutexGuard aGuard( m_pData->getMutex() ); 449 450 Sequence< Reference< XComponent > > aComponents( m_pData->m_aComponents.size() ); 451 ::std::transform( 452 m_pData->m_aComponents.begin(), 453 m_pData->m_aComponents.end(), 454 aComponents.getArray(), 455 SelectSubComponent() 456 ); 457 return aComponents; 458 } 459 460 //------------------------------------------------------------------------------------------------------------------ closeSubComponents()461 sal_Bool SubComponentManager::closeSubComponents() 462 { 463 ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); 464 ::osl::MutexGuard aGuard( m_pData->getMutex() ); 465 466 try 467 { 468 SubComponents aWorkingCopy( m_pData->m_aComponents ); 469 for ( SubComponents::const_iterator comp = aWorkingCopy.begin(); 470 comp != aWorkingCopy.end(); 471 ++comp 472 ) 473 { 474 lcl_closeComponent( *comp ); 475 } 476 } 477 catch ( const Exception& ) 478 { 479 DBG_UNHANDLED_EXCEPTION(); 480 } 481 482 return empty(); 483 } 484 485 //------------------------------------------------------------------------------------------------------------------ empty() const486 bool SubComponentManager::empty() const 487 { 488 ::osl::MutexGuard aGuard( m_pData->getMutex() ); 489 return m_pData->m_aComponents.empty(); 490 } 491 492 //------------------------------------------------------------------------------------------------------------------ onSubComponentOpened(const::rtl::OUString & _rName,const sal_Int32 _nComponentType,const ElementOpenMode _eOpenMode,const Reference<XComponent> & _rxComponent)493 void SubComponentManager::onSubComponentOpened( const ::rtl::OUString& _rName, const sal_Int32 _nComponentType, 494 const ElementOpenMode _eOpenMode, const Reference< XComponent >& _rxComponent ) 495 { 496 ::osl::ClearableMutexGuard aGuard( m_pData->getMutex() ); 497 498 #if OSL_DEBUG_LEVEL > 0 499 if ( _rName.getLength() ) 500 { 501 // check there does not already exist such a component 502 SubComponents::const_iterator existentPos = ::std::find_if( 503 m_pData->m_aComponents.begin(), 504 m_pData->m_aComponents.end(), 505 SubComponentMatch( _rName, _nComponentType, _eOpenMode ) 506 ); 507 OSL_ENSURE( existentPos == m_pData->m_aComponents.end(), "already existent!" ); 508 } 509 #endif 510 SubComponentDescriptor aElement( _rName, _nComponentType, _eOpenMode, _rxComponent ); 511 ENSURE_OR_THROW( aElement.xModel.is() || aElement.xController.is(), "illegal component" ); 512 513 m_pData->m_aComponents.push_back( aElement ); 514 515 // add as listener 516 if ( aElement.xController.is() ) 517 aElement.xController->addEventListener( this ); 518 if ( aElement.xModel.is() ) 519 aElement.xModel->addEventListener( this ); 520 if ( aElement.xDocumentDefinitionProperties.is() ) 521 aElement.xDocumentDefinitionProperties->addPropertyChangeListener( PROPERTY_NAME, this ); 522 523 // notify this to interested parties 524 aGuard.clear(); 525 lcl_notifySubComponentEvent( *m_pData, "OnSubComponentOpened", aElement ); 526 } 527 528 //------------------------------------------------------------------------------------------------------------------ activateSubFrame(const::rtl::OUString & _rName,const sal_Int32 _nComponentType,const ElementOpenMode _eOpenMode,Reference<XComponent> & o_rComponent) const529 bool SubComponentManager::activateSubFrame( const ::rtl::OUString& _rName, const sal_Int32 _nComponentType, 530 const ElementOpenMode _eOpenMode, Reference< XComponent >& o_rComponent ) const 531 { 532 ::osl::MutexGuard aGuard( m_pData->getMutex() ); 533 534 SubComponents::const_iterator pos = ::std::find_if( 535 m_pData->m_aComponents.begin(), 536 m_pData->m_aComponents.end(), 537 SubComponentMatch( _rName, _nComponentType, _eOpenMode ) 538 ); 539 if ( pos == m_pData->m_aComponents.end() ) 540 // no component with this name/type/open mode 541 return false; 542 543 const Reference< XFrame > xFrame( pos->xFrame, UNO_SET_THROW ); 544 const Reference< XTopWindow > xTopWindow( xFrame->getContainerWindow(), UNO_QUERY_THROW ); 545 xTopWindow->toFront(); 546 547 if ( pos->xModel.is() ) 548 o_rComponent = pos->xModel.get(); 549 else if ( pos->xController.is() ) 550 o_rComponent = pos->xController.get(); 551 else 552 o_rComponent = pos->xFrame.get(); 553 554 return true; 555 } 556 557 //------------------------------------------------------------------------------------------------------------------ closeSubFrames(const::rtl::OUString & i_rName,const sal_Int32 _nComponentType)558 bool SubComponentManager::closeSubFrames( const ::rtl::OUString& i_rName, const sal_Int32 _nComponentType ) 559 { 560 ::osl::MutexGuard aGuard( m_pData->getMutex() ); 561 ENSURE_OR_RETURN_FALSE( i_rName.getLength(), "SubComponentManager::closeSubFrames: illegal name!" ); 562 563 SubComponents aWorkingCopy( m_pData->m_aComponents ); 564 for ( SubComponents::const_iterator comp = aWorkingCopy.begin(); 565 comp != aWorkingCopy.end(); 566 ++comp 567 ) 568 { 569 if ( ( comp->sName != i_rName ) || ( comp->nComponentType != _nComponentType ) ) 570 continue; 571 572 if ( !lcl_closeComponent( *comp ) ) 573 return false; 574 } 575 576 return true; 577 } 578 579 //------------------------------------------------------------------------------------------------------------------ lookupSubComponent(const Reference<XComponent> & i_rComponent,::rtl::OUString & o_rName,sal_Int32 & o_rComponentType)580 bool SubComponentManager::lookupSubComponent( const Reference< XComponent >& i_rComponent, 581 ::rtl::OUString& o_rName, sal_Int32& o_rComponentType ) 582 { 583 for ( SubComponents::const_iterator comp = m_pData->m_aComponents.begin(); 584 comp != m_pData->m_aComponents.end(); 585 ++comp 586 ) 587 { 588 if ( ( comp->xModel.is() 589 && ( comp->xModel == i_rComponent ) 590 ) 591 || ( comp->xController.is() 592 && ( comp->xController == i_rComponent ) 593 ) 594 || ( comp->xFrame.is() 595 && ( comp->xFrame == i_rComponent ) 596 ) 597 ) 598 { 599 o_rName = comp->sName; 600 o_rComponentType = comp->nComponentType; 601 return true; 602 } 603 } 604 return false; 605 } 606 607 //...................................................................................................................... 608 } // namespace dbaui 609 //...................................................................................................................... 610