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