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