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_desktop.hxx" 30 31 #include "vcl/svapp.hxx" 32 #include "vcl/msgbox.hxx" 33 34 #include "vos/mutex.hxx" 35 36 #include "toolkit/helper/vclunohelper.hxx" 37 38 #include "com/sun/star/beans/XPropertySet.hpp" 39 40 #include "dp_gui_dialog2.hxx" 41 #include "dp_gui_extensioncmdqueue.hxx" 42 #include "dp_gui_theextmgr.hxx" 43 #include "dp_gui_theextmgr.hxx" 44 #include "dp_identifier.hxx" 45 #include "dp_update.hxx" 46 47 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) 48 49 #define USER_PACKAGE_MANAGER OUSTR("user") 50 #define SHARED_PACKAGE_MANAGER OUSTR("shared") 51 #define BUNDLED_PACKAGE_MANAGER OUSTR("bundled") 52 53 using namespace ::com::sun::star; 54 using ::rtl::OUString; 55 56 namespace dp_gui { 57 58 //------------------------------------------------------------------------------ 59 60 ::rtl::Reference< TheExtensionManager > TheExtensionManager::s_ExtMgr; 61 62 //------------------------------------------------------------------------------ 63 // TheExtensionManager 64 //------------------------------------------------------------------------------ 65 66 TheExtensionManager::TheExtensionManager( Window *pParent, 67 const uno::Reference< uno::XComponentContext > &xContext ) : 68 m_xContext( xContext ), 69 m_pParent( pParent ), 70 m_pExtMgrDialog( NULL ), 71 m_pUpdReqDialog( NULL ), 72 m_pExecuteCmdQueue( NULL ) 73 { 74 m_xExtensionManager = deployment::ExtensionManager::get( xContext ); 75 m_xExtensionManager->addModifyListener( this ); 76 77 uno::Reference< lang::XMultiServiceFactory > xConfig( 78 xContext->getServiceManager()->createInstanceWithContext( 79 OUSTR("com.sun.star.configuration.ConfigurationProvider"), xContext ), uno::UNO_QUERY_THROW); 80 uno::Any args[1]; 81 beans::PropertyValue aValue( OUSTR("nodepath"), 0, uno::Any( OUSTR("/org.openoffice.Office.OptionsDialog/Nodes") ), 82 beans::PropertyState_DIRECT_VALUE ); 83 args[0] <<= aValue; 84 m_xNameAccessNodes = uno::Reference< container::XNameAccess >( 85 xConfig->createInstanceWithArguments( OUSTR("com.sun.star.configuration.ConfigurationAccess"), 86 uno::Sequence< uno::Any >( args, 1 )), uno::UNO_QUERY_THROW); 87 88 // get the 'get more extensions here' url 89 uno::Reference< container::XNameAccess > xNameAccessRepositories; 90 beans::PropertyValue aValue2( OUSTR("nodepath"), 0, uno::Any( OUSTR("/org.openoffice.Office.ExtensionManager/ExtensionRepositories") ), 91 beans::PropertyState_DIRECT_VALUE ); 92 args[0] <<= aValue2; 93 xNameAccessRepositories = uno::Reference< container::XNameAccess > ( 94 xConfig->createInstanceWithArguments( OUSTR("com.sun.star.configuration.ConfigurationAccess"), 95 uno::Sequence< uno::Any >( args, 1 )), uno::UNO_QUERY_THROW); 96 try 97 { //throws css::container::NoSuchElementException, css::lang::WrappedTargetException 98 uno::Any value = xNameAccessRepositories->getByName( OUSTR( "WebsiteLink" ) ); 99 m_sGetExtensionsURL = value.get< OUString > (); 100 } 101 catch ( uno::Exception& ) 102 {} 103 104 if ( dp_misc::office_is_running() ) 105 { 106 // the registration should be done after the construction has been ended 107 // otherwise an exception prevents object creation, but it is registered as a listener 108 m_xDesktop.set( xContext->getServiceManager()->createInstanceWithContext( 109 OUSTR("com.sun.star.frame.Desktop"), xContext ), uno::UNO_QUERY ); 110 if ( m_xDesktop.is() ) 111 m_xDesktop->addTerminateListener( this ); 112 } 113 } 114 115 //------------------------------------------------------------------------------ 116 TheExtensionManager::~TheExtensionManager() 117 { 118 if ( m_pUpdReqDialog ) 119 delete m_pUpdReqDialog; 120 if ( m_pExtMgrDialog ) 121 delete m_pExtMgrDialog; 122 if ( m_pExecuteCmdQueue ) 123 delete m_pExecuteCmdQueue; 124 } 125 126 //------------------------------------------------------------------------------ 127 void TheExtensionManager::createDialog( const bool bCreateUpdDlg ) 128 { 129 const ::vos::OGuard guard( Application::GetSolarMutex() ); 130 131 if ( bCreateUpdDlg ) 132 { 133 if ( !m_pUpdReqDialog ) 134 { 135 m_pUpdReqDialog = new UpdateRequiredDialog( NULL, this ); 136 delete m_pExecuteCmdQueue; 137 m_pExecuteCmdQueue = new ExtensionCmdQueue( (DialogHelper*) m_pUpdReqDialog, this, m_xContext ); 138 createPackageList(); 139 } 140 } 141 else if ( !m_pExtMgrDialog ) 142 { 143 m_pExtMgrDialog = new ExtMgrDialog( m_pParent, this ); 144 delete m_pExecuteCmdQueue; 145 m_pExecuteCmdQueue = new ExtensionCmdQueue( (DialogHelper*) m_pExtMgrDialog, this, m_xContext ); 146 m_pExtMgrDialog->setGetExtensionsURL( m_sGetExtensionsURL ); 147 createPackageList(); 148 } 149 } 150 151 //------------------------------------------------------------------------------ 152 void TheExtensionManager::Show() 153 { 154 const ::vos::OGuard guard( Application::GetSolarMutex() ); 155 156 getDialog()->Show(); 157 } 158 159 //------------------------------------------------------------------------------ 160 void TheExtensionManager::SetText( const ::rtl::OUString &rTitle ) 161 { 162 const ::vos::OGuard guard( Application::GetSolarMutex() ); 163 164 getDialog()->SetText( rTitle ); 165 } 166 167 //------------------------------------------------------------------------------ 168 void TheExtensionManager::ToTop( sal_uInt16 nFlags ) 169 { 170 const ::vos::OGuard guard( Application::GetSolarMutex() ); 171 172 getDialog()->ToTop( nFlags ); 173 } 174 175 //------------------------------------------------------------------------------ 176 bool TheExtensionManager::Close() 177 { 178 if ( m_pExtMgrDialog ) 179 return m_pExtMgrDialog->Close(); 180 else if ( m_pUpdReqDialog ) 181 return m_pUpdReqDialog->Close(); 182 else 183 return true; 184 } 185 186 //------------------------------------------------------------------------------ 187 sal_Int16 TheExtensionManager::execute() 188 { 189 sal_Int16 nRet = 0; 190 191 if ( m_pUpdReqDialog ) 192 { 193 nRet = m_pUpdReqDialog->Execute(); 194 delete m_pUpdReqDialog; 195 m_pUpdReqDialog = NULL; 196 } 197 198 return nRet; 199 } 200 201 //------------------------------------------------------------------------------ 202 bool TheExtensionManager::isVisible() 203 { 204 return getDialog()->IsVisible(); 205 } 206 207 //------------------------------------------------------------------------------ 208 bool TheExtensionManager::checkUpdates( bool /* bShowUpdateOnly */, bool /*bParentVisible*/ ) 209 { 210 std::vector< uno::Reference< deployment::XPackage > > vEntries; 211 uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages; 212 213 try { 214 xAllPackages = m_xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(), 215 uno::Reference< ucb::XCommandEnvironment >() ); 216 } catch ( deployment::DeploymentException & ) { 217 return false; 218 } catch ( ucb::CommandFailedException & ) { 219 return false; 220 } catch ( ucb::CommandAbortedException & ) { 221 return false; 222 } catch ( lang::IllegalArgumentException & e ) { 223 throw uno::RuntimeException( e.Message, e.Context ); 224 } 225 226 for ( sal_Int32 i = 0; i < xAllPackages.getLength(); ++i ) 227 { 228 uno::Reference< deployment::XPackage > xPackage = dp_misc::getExtensionWithHighestVersion(xAllPackages[i]); 229 OSL_ASSERT(xPackage.is()); 230 if ( xPackage.is() ) 231 { 232 vEntries.push_back( xPackage ); 233 } 234 } 235 236 m_pExecuteCmdQueue->checkForUpdates( vEntries ); 237 return true; 238 } 239 240 //------------------------------------------------------------------------------ 241 bool TheExtensionManager::installPackage( const OUString &rPackageURL, bool bWarnUser ) 242 { 243 if ( rPackageURL.getLength() == 0 ) 244 return false; 245 246 createDialog( false ); 247 248 bool bInstall = true; 249 bool bInstallForAll = false; 250 251 // DV! missing function is read only repository from extension manager 252 if ( !bWarnUser && ! m_xExtensionManager->isReadOnlyRepository( SHARED_PACKAGE_MANAGER ) ) 253 bInstall = getDialogHelper()->installForAllUsers( bInstallForAll ); 254 255 if ( !bInstall ) 256 return false; 257 258 if ( bInstallForAll ) 259 m_pExecuteCmdQueue->addExtension( rPackageURL, SHARED_PACKAGE_MANAGER, false ); 260 else 261 m_pExecuteCmdQueue->addExtension( rPackageURL, USER_PACKAGE_MANAGER, bWarnUser ); 262 263 return true; 264 } 265 266 //------------------------------------------------------------------------------ 267 bool TheExtensionManager::queryTermination() 268 { 269 if ( dp_misc::office_is_running() ) 270 return true; 271 // the standalone application unopkg must not close ( and quit ) the dialog 272 // when there are still actions in the queue 273 return true; 274 } 275 276 //------------------------------------------------------------------------------ 277 void TheExtensionManager::terminateDialog() 278 { 279 if ( ! dp_misc::office_is_running() ) 280 { 281 const ::vos::OGuard guard( Application::GetSolarMutex() ); 282 delete m_pExtMgrDialog; 283 m_pExtMgrDialog = NULL; 284 delete m_pUpdReqDialog; 285 m_pUpdReqDialog = NULL; 286 Application::Quit(); 287 } 288 } 289 290 //------------------------------------------------------------------------------ 291 void TheExtensionManager::createPackageList() 292 { 293 uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages; 294 295 try { 296 xAllPackages = m_xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(), 297 uno::Reference< ucb::XCommandEnvironment >() ); 298 } catch ( deployment::DeploymentException & ) { 299 return; 300 } catch ( ucb::CommandFailedException & ) { 301 return; 302 } catch ( ucb::CommandAbortedException & ) { 303 return; 304 } catch ( lang::IllegalArgumentException & e ) { 305 throw uno::RuntimeException( e.Message, e.Context ); 306 } 307 308 for ( sal_Int32 i = 0; i < xAllPackages.getLength(); ++i ) 309 { 310 uno::Sequence< uno::Reference< deployment::XPackage > > xPackageList = xAllPackages[i]; 311 312 for ( sal_Int32 j = 0; j < xPackageList.getLength(); ++j ) 313 { 314 uno::Reference< deployment::XPackage > xPackage = xPackageList[j]; 315 if ( xPackage.is() ) 316 { 317 PackageState eState = getPackageState( xPackage ); 318 getDialogHelper()->addPackageToList( xPackage ); 319 // When the package is enabled, we can stop here, otherwise we have to look for 320 // another version of this package 321 if ( ( eState == REGISTERED ) || ( eState == NOT_AVAILABLE ) ) 322 break; 323 } 324 } 325 } 326 327 uno::Sequence< uno::Reference< deployment::XPackage > > xNoLicPackages; 328 xNoLicPackages = m_xExtensionManager->getExtensionsWithUnacceptedLicenses( SHARED_PACKAGE_MANAGER, 329 uno::Reference< ucb::XCommandEnvironment >() ); 330 for ( sal_Int32 i = 0; i < xNoLicPackages.getLength(); ++i ) 331 { 332 uno::Reference< deployment::XPackage > xPackage = xNoLicPackages[i]; 333 if ( xPackage.is() ) 334 { 335 getDialogHelper()->addPackageToList( xPackage, true ); 336 } 337 } 338 } 339 340 //------------------------------------------------------------------------------ 341 PackageState TheExtensionManager::getPackageState( const uno::Reference< deployment::XPackage > &xPackage ) const 342 { 343 try { 344 beans::Optional< beans::Ambiguous< sal_Bool > > option( 345 xPackage->isRegistered( uno::Reference< task::XAbortChannel >(), 346 uno::Reference< ucb::XCommandEnvironment >() ) ); 347 if ( option.IsPresent ) 348 { 349 ::beans::Ambiguous< sal_Bool > const & reg = option.Value; 350 if ( reg.IsAmbiguous ) 351 return AMBIGUOUS; 352 else 353 return reg.Value ? REGISTERED : NOT_REGISTERED; 354 } 355 else 356 return NOT_AVAILABLE; 357 } 358 catch ( uno::RuntimeException & ) { 359 throw; 360 } 361 catch ( uno::Exception & exc) { 362 (void) exc; 363 OSL_ENSURE( 0, ::rtl::OUStringToOString( exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); 364 return NOT_AVAILABLE; 365 } 366 } 367 368 //------------------------------------------------------------------------------ 369 bool TheExtensionManager::isReadOnly( const uno::Reference< deployment::XPackage > &xPackage ) const 370 { 371 if ( m_xExtensionManager.is() && xPackage.is() ) 372 { 373 return m_xExtensionManager->isReadOnlyRepository( xPackage->getRepositoryName() ); 374 } 375 else 376 return true; 377 } 378 379 //------------------------------------------------------------------------------ 380 // The function investigates if the extension supports options. 381 bool TheExtensionManager::supportsOptions( const uno::Reference< deployment::XPackage > &xPackage ) const 382 { 383 bool bOptions = false; 384 385 if ( ! xPackage->isBundle() ) 386 return false; 387 388 beans::Optional< OUString > aId = xPackage->getIdentifier(); 389 390 //a bundle must always have an id 391 OSL_ASSERT( aId.IsPresent ); 392 393 //iterate over all available nodes 394 uno::Sequence< OUString > seqNames = m_xNameAccessNodes->getElementNames(); 395 396 for ( int i = 0; i < seqNames.getLength(); i++ ) 397 { 398 uno::Any anyNode = m_xNameAccessNodes->getByName( seqNames[i] ); 399 //If we have a node then then it must contain the set of leaves. This is part of OptionsDialog.xcs 400 uno::Reference< XInterface> xIntNode = anyNode.get< uno::Reference< XInterface > >(); 401 uno::Reference< container::XNameAccess > xNode( xIntNode, uno::UNO_QUERY_THROW ); 402 403 uno::Any anyLeaves = xNode->getByName( OUSTR("Leaves") ); 404 uno::Reference< XInterface > xIntLeaves = anyLeaves.get< uno::Reference< XInterface > >(); 405 uno::Reference< container::XNameAccess > xLeaves( xIntLeaves, uno::UNO_QUERY_THROW ); 406 407 //iterate over all available leaves 408 uno::Sequence< OUString > seqLeafNames = xLeaves->getElementNames(); 409 for ( int j = 0; j < seqLeafNames.getLength(); j++ ) 410 { 411 uno::Any anyLeaf = xLeaves->getByName( seqLeafNames[j] ); 412 uno::Reference< XInterface > xIntLeaf = anyLeaf.get< uno::Reference< XInterface > >(); 413 uno::Reference< beans::XPropertySet > xLeaf( xIntLeaf, uno::UNO_QUERY_THROW ); 414 //investigate the Id property if it matches the extension identifier which 415 //has been passed in. 416 uno::Any anyValue = xLeaf->getPropertyValue( OUSTR("Id") ); 417 418 OUString sId = anyValue.get< OUString >(); 419 if ( sId == aId.Value ) 420 { 421 bOptions = true; 422 break; 423 } 424 } 425 if ( bOptions ) 426 break; 427 } 428 return bOptions; 429 } 430 431 //------------------------------------------------------------------------------ 432 // XEventListener 433 void TheExtensionManager::disposing( lang::EventObject const & rEvt ) 434 throw ( uno::RuntimeException ) 435 { 436 bool shutDown = (rEvt.Source == m_xDesktop); 437 438 if ( shutDown && m_xDesktop.is() ) 439 { 440 m_xDesktop->removeTerminateListener( this ); 441 m_xDesktop.clear(); 442 } 443 444 if ( shutDown ) 445 { 446 if ( dp_misc::office_is_running() ) 447 { 448 const ::vos::OGuard guard( Application::GetSolarMutex() ); 449 delete m_pExtMgrDialog; 450 m_pExtMgrDialog = NULL; 451 delete m_pUpdReqDialog; 452 m_pUpdReqDialog = NULL; 453 } 454 s_ExtMgr.clear(); 455 } 456 } 457 458 //------------------------------------------------------------------------------ 459 // XTerminateListener 460 void TheExtensionManager::queryTermination( ::lang::EventObject const & ) 461 throw ( frame::TerminationVetoException, uno::RuntimeException ) 462 { 463 DialogHelper *pDialogHelper = getDialogHelper(); 464 465 if ( m_pExecuteCmdQueue->isBusy() || ( pDialogHelper && pDialogHelper->isBusy() ) ) 466 { 467 ToTop( TOTOP_RESTOREWHENMIN ); 468 throw frame::TerminationVetoException( 469 OUSTR("The office cannot be closed while the Extension Manager is running"), 470 uno::Reference<XInterface>(static_cast<frame::XTerminateListener*>(this), uno::UNO_QUERY)); 471 } 472 else 473 { 474 if ( m_pExtMgrDialog ) 475 m_pExtMgrDialog->Close(); 476 if ( m_pUpdReqDialog ) 477 m_pUpdReqDialog->Close(); 478 } 479 } 480 481 //------------------------------------------------------------------------------ 482 void TheExtensionManager::notifyTermination( ::lang::EventObject const & rEvt ) 483 throw ( uno::RuntimeException ) 484 { 485 disposing( rEvt ); 486 } 487 488 //------------------------------------------------------------------------------ 489 // XModifyListener 490 void TheExtensionManager::modified( ::lang::EventObject const & /*rEvt*/ ) 491 throw ( uno::RuntimeException ) 492 { 493 getDialogHelper()->prepareChecking(); 494 createPackageList(); 495 getDialogHelper()->checkEntries(); 496 } 497 498 //------------------------------------------------------------------------------ 499 ::rtl::Reference< TheExtensionManager > TheExtensionManager::get( const uno::Reference< uno::XComponentContext > &xContext, 500 const uno::Reference< awt::XWindow > &xParent, 501 const OUString & extensionURL ) 502 { 503 if ( s_ExtMgr.is() ) 504 { 505 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 506 if ( extensionURL.getLength() ) 507 s_ExtMgr->installPackage( extensionURL, true ); 508 return s_ExtMgr; 509 } 510 511 Window * pParent = DIALOG_NO_PARENT; 512 if ( xParent.is() ) 513 pParent = VCLUnoHelper::GetWindow(xParent); 514 515 ::rtl::Reference<TheExtensionManager> that( new TheExtensionManager( pParent, xContext ) ); 516 517 const ::vos::OGuard guard( Application::GetSolarMutex() ); 518 if ( ! s_ExtMgr.is() ) 519 { 520 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 521 s_ExtMgr = that; 522 } 523 524 if ( extensionURL.getLength() ) 525 s_ExtMgr->installPackage( extensionURL, true ); 526 527 return s_ExtMgr; 528 } 529 530 } //namespace dp_gui 531 532