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 32 33 34 #include "sal/config.h" 35 36 #include <cstddef> 37 38 #include "com/sun/star/beans/PropertyValue.hpp" 39 #include "com/sun/star/beans/NamedValue.hpp" 40 41 #include "com/sun/star/deployment/DependencyException.hpp" 42 #include "com/sun/star/deployment/LicenseException.hpp" 43 #include "com/sun/star/deployment/VersionException.hpp" 44 #include "com/sun/star/deployment/InstallException.hpp" 45 #include "com/sun/star/deployment/PlatformException.hpp" 46 47 #include "com/sun/star/deployment/ui/LicenseDialog.hpp" 48 #include "com/sun/star/deployment/DeploymentException.hpp" 49 #include "com/sun/star/deployment/UpdateInformationProvider.hpp" 50 #include "com/sun/star/deployment/XPackage.hpp" 51 52 #include "com/sun/star/task/XAbortChannel.hpp" 53 #include "com/sun/star/task/XInteractionAbort.hpp" 54 #include "com/sun/star/task/XInteractionApprove.hpp" 55 56 #include "com/sun/star/ucb/CommandAbortedException.hpp" 57 #include "com/sun/star/ucb/CommandFailedException.hpp" 58 #include "com/sun/star/ucb/XCommandEnvironment.hpp" 59 60 #include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp" 61 62 #include "com/sun/star/uno/Reference.hxx" 63 #include "com/sun/star/uno/RuntimeException.hpp" 64 #include "com/sun/star/uno/Sequence.hxx" 65 #include "com/sun/star/uno/XInterface.hpp" 66 #include "com/sun/star/uno/TypeClass.hpp" 67 #include "osl/diagnose.h" 68 #include "osl/mutex.hxx" 69 #include "rtl/ref.hxx" 70 #include "rtl/ustring.h" 71 #include "rtl/ustring.hxx" 72 #include "sal/types.h" 73 #include "ucbhelper/content.hxx" 74 #include "cppuhelper/exc_hlp.hxx" 75 #include "cppuhelper/implbase3.hxx" 76 #include "comphelper/anytostring.hxx" 77 #include "vcl/msgbox.hxx" 78 #include "toolkit/helper/vclunohelper.hxx" 79 #include "comphelper/processfactory.hxx" 80 81 #include "dp_gui.h" 82 #include "dp_gui_thread.hxx" 83 #include "dp_gui_extensioncmdqueue.hxx" 84 #include "dp_gui_dependencydialog.hxx" 85 #include "dp_gui_dialog2.hxx" 86 #include "dp_gui_shared.hxx" 87 #include "dp_gui_theextmgr.hxx" 88 #include "dp_gui_updatedialog.hxx" 89 #include "dp_gui_updateinstalldialog.hxx" 90 #include "dp_dependencies.hxx" 91 #include "dp_identifier.hxx" 92 #include "dp_version.hxx" 93 94 #include <queue> 95 #include <boost/shared_ptr.hpp> 96 97 #if (defined(_MSC_VER) && (_MSC_VER < 1400)) 98 #define _WIN32_WINNT 0x0400 99 #endif 100 101 #ifdef WNT 102 #include "tools/prewin.h" 103 #include <objbase.h> 104 #include "tools/postwin.h" 105 #endif 106 107 108 using namespace ::com::sun::star; 109 using ::rtl::OUString; 110 111 namespace { 112 113 OUString getVersion( OUString const & sVersion ) 114 { 115 return ( sVersion.getLength() == 0 ) ? OUString( RTL_CONSTASCII_USTRINGPARAM( "0" ) ) : sVersion; 116 } 117 118 OUString getVersion( const uno::Reference< deployment::XPackage > &rPackage ) 119 { 120 return getVersion( rPackage->getVersion()); 121 } 122 } 123 124 125 namespace dp_gui { 126 127 //============================================================================== 128 129 class ProgressCmdEnv 130 : public ::cppu::WeakImplHelper3< ucb::XCommandEnvironment, 131 task::XInteractionHandler, 132 ucb::XProgressHandler > 133 { 134 uno::Reference< task::XInteractionHandler> m_xHandler; 135 uno::Reference< uno::XComponentContext > m_xContext; 136 uno::Reference< task::XAbortChannel> m_xAbortChannel; 137 138 DialogHelper *m_pDialogHelper; 139 OUString m_sTitle; 140 bool m_bAborted; 141 bool m_bWarnUser; 142 sal_Int32 m_nCurrentProgress; 143 144 void updateProgress(); 145 146 void update_( uno::Any const & Status ) throw ( uno::RuntimeException ); 147 148 public: 149 virtual ~ProgressCmdEnv(); 150 151 /** When param bAskWhenInstalling = true, then the user is asked if he 152 agrees to install this extension. In case this extension is already installed 153 then the user is also notified and asked if he wants to replace that existing 154 extension. In first case an interaction request with an InstallException 155 will be handled and in the second case a VersionException will be handled. 156 */ 157 158 ProgressCmdEnv( const uno::Reference< uno::XComponentContext > rContext, 159 DialogHelper *pDialogHelper, 160 const OUString &rTitle ) 161 : m_xContext( rContext ), 162 m_pDialogHelper( pDialogHelper ), 163 m_sTitle( rTitle ), 164 m_bAborted( false ), 165 m_bWarnUser( false ) 166 {} 167 168 Dialog * activeDialog() { return m_pDialogHelper ? m_pDialogHelper->getWindow() : NULL; } 169 170 void setTitle( const OUString& rNewTitle ) { m_sTitle = rNewTitle; } 171 void startProgress(); 172 void stopProgress(); 173 void progressSection( const OUString &rText, 174 const uno::Reference< task::XAbortChannel > &xAbortChannel = 0 ); 175 inline bool isAborted() const { return m_bAborted; } 176 inline void setWarnUser( bool bNewVal ) { m_bWarnUser = bNewVal; } 177 178 // XCommandEnvironment 179 virtual uno::Reference< task::XInteractionHandler > SAL_CALL getInteractionHandler() 180 throw ( uno::RuntimeException ); 181 virtual uno::Reference< ucb::XProgressHandler > SAL_CALL getProgressHandler() 182 throw ( uno::RuntimeException ); 183 184 // XInteractionHandler 185 virtual void SAL_CALL handle( uno::Reference< task::XInteractionRequest > const & xRequest ) 186 throw ( uno::RuntimeException ); 187 188 // XProgressHandler 189 virtual void SAL_CALL push( uno::Any const & Status ) 190 throw ( uno::RuntimeException ); 191 virtual void SAL_CALL update( uno::Any const & Status ) 192 throw ( uno::RuntimeException ); 193 virtual void SAL_CALL pop() throw ( uno::RuntimeException ); 194 }; 195 196 //------------------------------------------------------------------------------ 197 struct ExtensionCmd 198 { 199 enum E_CMD_TYPE { ADD, ENABLE, DISABLE, REMOVE, CHECK_FOR_UPDATES, ACCEPT_LICENSE }; 200 201 E_CMD_TYPE m_eCmdType; 202 bool m_bWarnUser; 203 OUString m_sExtensionURL; 204 OUString m_sRepository; 205 uno::Reference< deployment::XPackage > m_xPackage; 206 std::vector< uno::Reference< deployment::XPackage > > m_vExtensionList; 207 208 ExtensionCmd( const E_CMD_TYPE eCommand, 209 const OUString &rExtensionURL, 210 const OUString &rRepository, 211 const bool bWarnUser ) 212 : m_eCmdType( eCommand ), 213 m_bWarnUser( bWarnUser ), 214 m_sExtensionURL( rExtensionURL ), 215 m_sRepository( rRepository ) {}; 216 ExtensionCmd( const E_CMD_TYPE eCommand, 217 const uno::Reference< deployment::XPackage > &rPackage ) 218 : m_eCmdType( eCommand ), 219 m_bWarnUser( false ), 220 m_xPackage( rPackage ) {}; 221 ExtensionCmd( const E_CMD_TYPE eCommand, 222 const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ) 223 : m_eCmdType( eCommand ), 224 m_bWarnUser( false ), 225 m_vExtensionList( vExtensionList ) {}; 226 }; 227 228 typedef ::boost::shared_ptr< ExtensionCmd > TExtensionCmd; 229 230 //------------------------------------------------------------------------------ 231 class ExtensionCmdQueue::Thread: public dp_gui::Thread 232 { 233 public: 234 Thread( DialogHelper *pDialogHelper, 235 TheExtensionManager *pManager, 236 const uno::Reference< uno::XComponentContext > & rContext ); 237 238 void addExtension( const OUString &rExtensionURL, 239 const OUString &rRepository, 240 const bool bWarnUser ); 241 void removeExtension( const uno::Reference< deployment::XPackage > &rPackage ); 242 void enableExtension( const uno::Reference< deployment::XPackage > &rPackage, 243 const bool bEnable ); 244 void checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ); 245 void acceptLicense( const uno::Reference< deployment::XPackage > &rPackage ); 246 void stop(); 247 bool isBusy(); 248 249 static OUString searchAndReplaceAll( const OUString &rSource, 250 const OUString &rWhat, 251 const OUString &rWith ); 252 private: 253 Thread( Thread & ); // not defined 254 void operator =( Thread & ); // not defined 255 256 virtual ~Thread(); 257 258 virtual void execute(); 259 virtual void SAL_CALL onTerminated(); 260 261 void _addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 262 const OUString &rPackageURL, 263 const OUString &rRepository, 264 const bool bWarnUser ); 265 void _removeExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 266 const uno::Reference< deployment::XPackage > &xPackage ); 267 void _enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 268 const uno::Reference< deployment::XPackage > &xPackage ); 269 void _disableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 270 const uno::Reference< deployment::XPackage > &xPackage ); 271 void _checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ); 272 void _acceptLicense( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 273 const uno::Reference< deployment::XPackage > &xPackage ); 274 275 enum Input { NONE, START, STOP }; 276 277 uno::Reference< uno::XComponentContext > m_xContext; 278 std::queue< TExtensionCmd > m_queue; 279 280 DialogHelper *m_pDialogHelper; 281 TheExtensionManager *m_pManager; 282 283 const OUString m_sEnablingPackages; 284 const OUString m_sDisablingPackages; 285 const OUString m_sAddingPackages; 286 const OUString m_sRemovingPackages; 287 const OUString m_sDefaultCmd; 288 const OUString m_sAcceptLicense; 289 osl::Condition m_wakeup; 290 osl::Mutex m_mutex; 291 Input m_eInput; 292 bool m_bTerminated; 293 bool m_bStopped; 294 bool m_bWorking; 295 }; 296 297 //------------------------------------------------------------------------------ 298 void ProgressCmdEnv::startProgress() 299 { 300 m_nCurrentProgress = 0; 301 302 if ( m_pDialogHelper ) 303 m_pDialogHelper->showProgress( true ); 304 } 305 306 //------------------------------------------------------------------------------ 307 void ProgressCmdEnv::stopProgress() 308 { 309 if ( m_pDialogHelper ) 310 m_pDialogHelper->showProgress( false ); 311 } 312 313 //------------------------------------------------------------------------------ 314 void ProgressCmdEnv::progressSection( const OUString &rText, 315 const uno::Reference< task::XAbortChannel > &xAbortChannel ) 316 { 317 m_xAbortChannel = xAbortChannel; 318 if (! m_bAborted) 319 { 320 m_nCurrentProgress = 0; 321 if ( m_pDialogHelper ) 322 { 323 m_pDialogHelper->updateProgress( rText, xAbortChannel ); 324 m_pDialogHelper->updateProgress( 5 ); 325 } 326 } 327 } 328 329 //------------------------------------------------------------------------------ 330 void ProgressCmdEnv::updateProgress() 331 { 332 if ( ! m_bAborted ) 333 { 334 long nProgress = ((m_nCurrentProgress*5) % 100) + 5; 335 if ( m_pDialogHelper ) 336 m_pDialogHelper->updateProgress( nProgress ); 337 } 338 } 339 340 //------------------------------------------------------------------------------ 341 ProgressCmdEnv::~ProgressCmdEnv() 342 { 343 // TODO: stop all threads and wait 344 } 345 346 347 //------------------------------------------------------------------------------ 348 // XCommandEnvironment 349 //------------------------------------------------------------------------------ 350 uno::Reference< task::XInteractionHandler > ProgressCmdEnv::getInteractionHandler() 351 throw ( uno::RuntimeException ) 352 { 353 return this; 354 } 355 356 //------------------------------------------------------------------------------ 357 uno::Reference< ucb::XProgressHandler > ProgressCmdEnv::getProgressHandler() 358 throw ( uno::RuntimeException ) 359 { 360 return this; 361 } 362 363 //------------------------------------------------------------------------------ 364 // XInteractionHandler 365 //------------------------------------------------------------------------------ 366 void ProgressCmdEnv::handle( uno::Reference< task::XInteractionRequest > const & xRequest ) 367 throw ( uno::RuntimeException ) 368 { 369 uno::Any request( xRequest->getRequest() ); 370 OSL_ASSERT( request.getValueTypeClass() == uno::TypeClass_EXCEPTION ); 371 dp_misc::TRACE( OUSTR("[dp_gui_cmdenv.cxx] incoming request:\n") 372 + ::comphelper::anyToString(request) + OUSTR("\n")); 373 374 lang::WrappedTargetException wtExc; 375 deployment::DependencyException depExc; 376 deployment::LicenseException licExc; 377 deployment::VersionException verExc; 378 deployment::InstallException instExc; 379 deployment::PlatformException platExc; 380 381 // selections: 382 bool approve = false; 383 bool abort = false; 384 385 if (request >>= wtExc) { 386 // handable deployment error signalled, e.g. 387 // bundle item registration failed, notify cause only: 388 uno::Any cause; 389 deployment::DeploymentException dpExc; 390 if (wtExc.TargetException >>= dpExc) 391 cause = dpExc.Cause; 392 else { 393 ucb::CommandFailedException cfExc; 394 if (wtExc.TargetException >>= cfExc) 395 cause = cfExc.Reason; 396 else 397 cause = wtExc.TargetException; 398 } 399 update_( cause ); 400 401 // ignore intermediate errors of legacy packages, i.e. 402 // former pkgchk behaviour: 403 const uno::Reference< deployment::XPackage > xPackage( wtExc.Context, uno::UNO_QUERY ); 404 OSL_ASSERT( xPackage.is() ); 405 if ( xPackage.is() ) 406 { 407 const uno::Reference< deployment::XPackageTypeInfo > xPackageType( xPackage->getPackageType() ); 408 OSL_ASSERT( xPackageType.is() ); 409 if (xPackageType.is()) 410 { 411 approve = ( xPackage->isBundle() && 412 xPackageType->getMediaType().matchAsciiL( 413 RTL_CONSTASCII_STRINGPARAM( 414 "application/" 415 "vnd.sun.star.legacy-package-bundle") )); 416 } 417 } 418 abort = !approve; 419 } 420 else if (request >>= depExc) 421 { 422 std::vector< rtl::OUString > deps; 423 for (sal_Int32 i = 0; i < depExc.UnsatisfiedDependencies.getLength(); 424 ++i) 425 { 426 deps.push_back( 427 dp_misc::Dependencies::getErrorText( depExc.UnsatisfiedDependencies[i]) ); 428 } 429 { 430 vos::OGuard guard(Application::GetSolarMutex()); 431 short n = DependencyDialog( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, deps ).Execute(); 432 // Distinguish between closing the dialog and programatically 433 // canceling the dialog (headless VCL): 434 approve = n == RET_OK 435 || (n == RET_CANCEL && !Application::IsDialogCancelEnabled()); 436 } 437 } 438 else if (request >>= licExc) 439 { 440 uno::Reference< ui::dialogs::XExecutableDialog > xDialog( 441 deployment::ui::LicenseDialog::create( 442 m_xContext, VCLUnoHelper::GetInterface( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL ), 443 licExc.ExtensionName, licExc.Text ) ); 444 sal_Int16 res = xDialog->execute(); 445 if ( res == ui::dialogs::ExecutableDialogResults::CANCEL ) 446 abort = true; 447 else if ( res == ui::dialogs::ExecutableDialogResults::OK ) 448 approve = true; 449 else 450 { 451 OSL_ASSERT(0); 452 } 453 } 454 else if (request >>= verExc) 455 { 456 sal_uInt32 id; 457 switch (dp_misc::compareVersions( 458 verExc.NewVersion, verExc.Deployed->getVersion() )) 459 { 460 case dp_misc::LESS: 461 id = RID_WARNINGBOX_VERSION_LESS; 462 break; 463 case dp_misc::EQUAL: 464 id = RID_WARNINGBOX_VERSION_EQUAL; 465 break; 466 default: // dp_misc::GREATER 467 id = RID_WARNINGBOX_VERSION_GREATER; 468 break; 469 } 470 OSL_ASSERT( verExc.Deployed.is() ); 471 bool bEqualNames = verExc.NewDisplayName.equals( 472 verExc.Deployed->getDisplayName()); 473 { 474 vos::OGuard guard(Application::GetSolarMutex()); 475 WarningBox box( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, ResId(id, *DeploymentGuiResMgr::get())); 476 String s; 477 if (bEqualNames) 478 { 479 s = box.GetMessText(); 480 } 481 else if (id == RID_WARNINGBOX_VERSION_EQUAL) 482 { 483 //hypothetical: requires two instances of an extension with the same 484 //version to have different display names. Probably the developer forgot 485 //to change the version. 486 s = String(ResId(RID_STR_WARNINGBOX_VERSION_EQUAL_DIFFERENT_NAMES, *DeploymentGuiResMgr::get())); 487 } 488 else if (id == RID_WARNINGBOX_VERSION_LESS) 489 { 490 s = String(ResId(RID_STR_WARNINGBOX_VERSION_LESS_DIFFERENT_NAMES, *DeploymentGuiResMgr::get())); 491 } 492 else if (id == RID_WARNINGBOX_VERSION_GREATER) 493 { 494 s = String(ResId(RID_STR_WARNINGBOX_VERSION_GREATER_DIFFERENT_NAMES, *DeploymentGuiResMgr::get())); 495 } 496 s.SearchAndReplaceAllAscii( "$NAME", verExc.NewDisplayName); 497 s.SearchAndReplaceAllAscii( "$OLDNAME", verExc.Deployed->getDisplayName()); 498 s.SearchAndReplaceAllAscii( "$NEW", getVersion(verExc.NewVersion) ); 499 s.SearchAndReplaceAllAscii( "$DEPLOYED", getVersion(verExc.Deployed) ); 500 box.SetMessText(s); 501 approve = box.Execute() == RET_OK; 502 abort = !approve; 503 } 504 } 505 else if (request >>= instExc) 506 { 507 if ( ! m_bWarnUser ) 508 { 509 approve = true; 510 } 511 else 512 { 513 if ( m_pDialogHelper ) 514 { 515 vos::OGuard guard(Application::GetSolarMutex()); 516 517 approve = m_pDialogHelper->installExtensionWarn( instExc.displayName ); 518 } 519 else 520 approve = false; 521 abort = !approve; 522 } 523 } 524 else if (request >>= platExc) 525 { 526 vos::OGuard guard( Application::GetSolarMutex() ); 527 String sMsg( ResId( RID_STR_UNSUPPORTED_PLATFORM, *DeploymentGuiResMgr::get() ) ); 528 sMsg.SearchAndReplaceAllAscii( "%Name", platExc.package->getDisplayName() ); 529 ErrorBox box( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, WB_OK, sMsg ); 530 box.Execute(); 531 approve = true; 532 } 533 534 if (approve == false && abort == false) 535 { 536 // forward to UUI handler: 537 if (! m_xHandler.is()) { 538 // late init: 539 uno::Sequence< uno::Any > handlerArgs( 1 ); 540 handlerArgs[ 0 ] <<= beans::PropertyValue( 541 OUSTR("Context"), -1, uno::Any( m_sTitle ), 542 beans::PropertyState_DIRECT_VALUE ); 543 m_xHandler.set( m_xContext->getServiceManager() 544 ->createInstanceWithArgumentsAndContext( 545 OUSTR("com.sun.star.uui.InteractionHandler"), 546 handlerArgs, m_xContext ), uno::UNO_QUERY_THROW ); 547 } 548 m_xHandler->handle( xRequest ); 549 } 550 else 551 { 552 // select: 553 uno::Sequence< uno::Reference< task::XInteractionContinuation > > conts( 554 xRequest->getContinuations() ); 555 uno::Reference< task::XInteractionContinuation > const * pConts = conts.getConstArray(); 556 sal_Int32 len = conts.getLength(); 557 for ( sal_Int32 pos = 0; pos < len; ++pos ) 558 { 559 if (approve) { 560 uno::Reference< task::XInteractionApprove > xInteractionApprove( pConts[ pos ], uno::UNO_QUERY ); 561 if (xInteractionApprove.is()) { 562 xInteractionApprove->select(); 563 // don't query again for ongoing continuations: 564 approve = false; 565 } 566 } 567 else if (abort) { 568 uno::Reference< task::XInteractionAbort > xInteractionAbort( pConts[ pos ], uno::UNO_QUERY ); 569 if (xInteractionAbort.is()) { 570 xInteractionAbort->select(); 571 // don't query again for ongoing continuations: 572 abort = false; 573 } 574 } 575 } 576 } 577 } 578 579 //------------------------------------------------------------------------------ 580 // XProgressHandler 581 //------------------------------------------------------------------------------ 582 void ProgressCmdEnv::push( uno::Any const & rStatus ) 583 throw( uno::RuntimeException ) 584 { 585 update_( rStatus ); 586 } 587 588 //------------------------------------------------------------------------------ 589 void ProgressCmdEnv::update_( uno::Any const & rStatus ) 590 throw( uno::RuntimeException ) 591 { 592 OUString text; 593 if ( rStatus.hasValue() && !( rStatus >>= text) ) 594 { 595 if ( rStatus.getValueTypeClass() == uno::TypeClass_EXCEPTION ) 596 text = static_cast< uno::Exception const *>( rStatus.getValue() )->Message; 597 if ( text.getLength() == 0 ) 598 text = ::comphelper::anyToString( rStatus ); // fallback 599 600 const ::vos::OGuard aGuard( Application::GetSolarMutex() ); 601 const ::std::auto_ptr< ErrorBox > aBox( new ErrorBox( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, WB_OK, text ) ); 602 aBox->Execute(); 603 } 604 ++m_nCurrentProgress; 605 updateProgress(); 606 } 607 608 //------------------------------------------------------------------------------ 609 void ProgressCmdEnv::update( uno::Any const & rStatus ) 610 throw( uno::RuntimeException ) 611 { 612 update_( rStatus ); 613 } 614 615 //------------------------------------------------------------------------------ 616 void ProgressCmdEnv::pop() 617 throw( uno::RuntimeException ) 618 { 619 update_( uno::Any() ); // no message 620 } 621 622 //------------------------------------------------------------------------------ 623 ExtensionCmdQueue::Thread::Thread( DialogHelper *pDialogHelper, 624 TheExtensionManager *pManager, 625 const uno::Reference< uno::XComponentContext > & rContext ) : 626 m_xContext( rContext ), 627 m_pDialogHelper( pDialogHelper ), 628 m_pManager( pManager ), 629 m_sEnablingPackages( DialogHelper::getResourceString( RID_STR_ENABLING_PACKAGES ) ), 630 m_sDisablingPackages( DialogHelper::getResourceString( RID_STR_DISABLING_PACKAGES ) ), 631 m_sAddingPackages( DialogHelper::getResourceString( RID_STR_ADDING_PACKAGES ) ), 632 m_sRemovingPackages( DialogHelper::getResourceString( RID_STR_REMOVING_PACKAGES ) ), 633 m_sDefaultCmd( DialogHelper::getResourceString( RID_STR_ADD_PACKAGES ) ), 634 m_sAcceptLicense( DialogHelper::getResourceString( RID_STR_ACCEPT_LICENSE ) ), 635 m_eInput( NONE ), 636 m_bTerminated( false ), 637 m_bStopped( false ), 638 m_bWorking( false ) 639 { 640 OSL_ASSERT( pDialogHelper ); 641 } 642 643 //------------------------------------------------------------------------------ 644 void ExtensionCmdQueue::Thread::addExtension( const ::rtl::OUString &rExtensionURL, 645 const ::rtl::OUString &rRepository, 646 const bool bWarnUser ) 647 { 648 ::osl::MutexGuard aGuard( m_mutex ); 649 650 //If someone called stop then we do not add the extension -> game over! 651 if ( m_bStopped ) 652 return; 653 654 if ( rExtensionURL.getLength() ) 655 { 656 TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::ADD, rExtensionURL, rRepository, bWarnUser ) ); 657 658 m_queue.push( pEntry ); 659 m_eInput = START; 660 m_wakeup.set(); 661 } 662 } 663 664 //------------------------------------------------------------------------------ 665 void ExtensionCmdQueue::Thread::removeExtension( const uno::Reference< deployment::XPackage > &rPackage ) 666 { 667 ::osl::MutexGuard aGuard( m_mutex ); 668 669 //If someone called stop then we do not remove the extension -> game over! 670 if ( m_bStopped ) 671 return; 672 673 if ( rPackage.is() ) 674 { 675 TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::REMOVE, rPackage ) ); 676 677 m_queue.push( pEntry ); 678 m_eInput = START; 679 m_wakeup.set(); 680 } 681 } 682 683 //------------------------------------------------------------------------------ 684 void ExtensionCmdQueue::Thread::acceptLicense( const uno::Reference< deployment::XPackage > &rPackage ) 685 { 686 ::osl::MutexGuard aGuard( m_mutex ); 687 688 //If someone called stop then we do not remove the extension -> game over! 689 if ( m_bStopped ) 690 return; 691 692 if ( rPackage.is() ) 693 { 694 TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::ACCEPT_LICENSE, rPackage ) ); 695 696 m_queue.push( pEntry ); 697 m_eInput = START; 698 m_wakeup.set(); 699 } 700 } 701 702 //------------------------------------------------------------------------------ 703 void ExtensionCmdQueue::Thread::enableExtension( const uno::Reference< deployment::XPackage > &rPackage, 704 const bool bEnable ) 705 { 706 ::osl::MutexGuard aGuard( m_mutex ); 707 708 //If someone called stop then we do not remove the extension -> game over! 709 if ( m_bStopped ) 710 return; 711 712 if ( rPackage.is() ) 713 { 714 TExtensionCmd pEntry( new ExtensionCmd( bEnable ? ExtensionCmd::ENABLE : 715 ExtensionCmd::DISABLE, 716 rPackage ) ); 717 m_queue.push( pEntry ); 718 m_eInput = START; 719 m_wakeup.set(); 720 } 721 } 722 723 //------------------------------------------------------------------------------ 724 void ExtensionCmdQueue::Thread::checkForUpdates( 725 const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ) 726 { 727 ::osl::MutexGuard aGuard( m_mutex ); 728 729 //If someone called stop then we do not update the extension -> game over! 730 if ( m_bStopped ) 731 return; 732 733 TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::CHECK_FOR_UPDATES, vExtensionList ) ); 734 m_queue.push( pEntry ); 735 m_eInput = START; 736 m_wakeup.set(); 737 } 738 739 //------------------------------------------------------------------------------ 740 //Stopping this thread will not abort the installation of extensions. 741 void ExtensionCmdQueue::Thread::stop() 742 { 743 osl::MutexGuard aGuard( m_mutex ); 744 m_bStopped = true; 745 m_eInput = STOP; 746 m_wakeup.set(); 747 } 748 749 //------------------------------------------------------------------------------ 750 bool ExtensionCmdQueue::Thread::isBusy() 751 { 752 osl::MutexGuard aGuard( m_mutex ); 753 return m_bWorking; 754 } 755 756 //------------------------------------------------------------------------------ 757 ExtensionCmdQueue::Thread::~Thread() {} 758 759 //------------------------------------------------------------------------------ 760 void ExtensionCmdQueue::Thread::execute() 761 { 762 #ifdef WNT 763 //Needed for use of the service "com.sun.star.system.SystemShellExecute" in 764 //DialogHelper::openWebBrowser 765 CoUninitialize(); 766 HRESULT r = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 767 #endif 768 for (;;) 769 { 770 if ( m_wakeup.wait() != osl::Condition::result_ok ) 771 { 772 dp_misc::TRACE( "dp_gui::ExtensionCmdQueue::Thread::run: ignored " 773 "osl::Condition::wait failure\n" ); 774 } 775 m_wakeup.reset(); 776 777 int nSize; 778 Input eInput; 779 { 780 osl::MutexGuard aGuard( m_mutex ); 781 eInput = m_eInput; 782 m_eInput = NONE; 783 nSize = m_queue.size(); 784 m_bWorking = false; 785 } 786 787 // If this thread has been woken up by anything else except start, stop 788 // then input is NONE and we wait again. 789 // We only install the extension which are currently in the queue. 790 // The progressbar will be set to show the progress of the current number 791 // of extensions. If we allowed to add extensions now then the progressbar may 792 // have reached the end while we still install newly added extensions. 793 if ( ( eInput == NONE ) || ( nSize == 0 ) ) 794 continue; 795 if ( eInput == STOP ) 796 break; 797 798 ::rtl::Reference< ProgressCmdEnv > currentCmdEnv( new ProgressCmdEnv( m_xContext, m_pDialogHelper, m_sDefaultCmd ) ); 799 800 // Do not lock the following part with addExtension. addExtension may be called in the main thread. 801 // If the message box "Do you want to install the extension (or similar)" is shown and then 802 // addExtension is called, which then blocks the main thread, then we deadlock. 803 bool bStartProgress = true; 804 805 while ( !currentCmdEnv->isAborted() && --nSize >= 0 ) 806 { 807 { 808 osl::MutexGuard aGuard( m_mutex ); 809 m_bWorking = true; 810 } 811 812 try 813 { 814 TExtensionCmd pEntry; 815 { 816 ::osl::MutexGuard queueGuard( m_mutex ); 817 pEntry = m_queue.front(); 818 m_queue.pop(); 819 } 820 821 if ( bStartProgress && ( pEntry->m_eCmdType != ExtensionCmd::CHECK_FOR_UPDATES ) ) 822 { 823 currentCmdEnv->startProgress(); 824 bStartProgress = false; 825 } 826 827 switch ( pEntry->m_eCmdType ) { 828 case ExtensionCmd::ADD : 829 _addExtension( currentCmdEnv, pEntry->m_sExtensionURL, pEntry->m_sRepository, pEntry->m_bWarnUser ); 830 break; 831 case ExtensionCmd::REMOVE : 832 _removeExtension( currentCmdEnv, pEntry->m_xPackage ); 833 break; 834 case ExtensionCmd::ENABLE : 835 _enableExtension( currentCmdEnv, pEntry->m_xPackage ); 836 break; 837 case ExtensionCmd::DISABLE : 838 _disableExtension( currentCmdEnv, pEntry->m_xPackage ); 839 break; 840 case ExtensionCmd::CHECK_FOR_UPDATES : 841 _checkForUpdates( pEntry->m_vExtensionList ); 842 break; 843 case ExtensionCmd::ACCEPT_LICENSE : 844 _acceptLicense( currentCmdEnv, pEntry->m_xPackage ); 845 break; 846 } 847 } 848 //catch ( deployment::DeploymentException &) 849 //{ 850 //} 851 //catch ( lang::IllegalArgumentException &) 852 //{ 853 //} 854 catch ( ucb::CommandAbortedException & ) 855 { 856 //This exception is thrown when the user clicks cancel on the progressbar. 857 //Then we cancel the installation of all extensions and remove them from 858 //the queue. 859 { 860 ::osl::MutexGuard queueGuard2(m_mutex); 861 while ( --nSize >= 0 ) 862 m_queue.pop(); 863 } 864 break; 865 } 866 catch ( ucb::CommandFailedException & ) 867 { 868 //This exception is thrown when a user clicked cancel in the messagebox which was 869 //startet by the interaction handler. For example the user will be asked if he/she 870 //really wants to install the extension. 871 //These interaction are run for exectly one extension at a time. Therefore we continue 872 //with installing the remaining extensions. 873 continue; 874 } 875 catch ( uno::Exception & ) 876 { 877 //Todo display the user an error 878 //see also DialogImpl::SyncPushButton::Click() 879 uno::Any exc( ::cppu::getCaughtException() ); 880 OUString msg; 881 deployment::DeploymentException dpExc; 882 if ((exc >>= dpExc) && 883 dpExc.Cause.getValueTypeClass() == uno::TypeClass_EXCEPTION) 884 { 885 // notify error cause only: 886 msg = reinterpret_cast< uno::Exception const * >( dpExc.Cause.getValue() )->Message; 887 } 888 if (msg.getLength() == 0) // fallback for debugging purposes 889 msg = ::comphelper::anyToString(exc); 890 891 const ::vos::OGuard guard( Application::GetSolarMutex() ); 892 ::std::auto_ptr<ErrorBox> box( 893 new ErrorBox( currentCmdEnv->activeDialog(), WB_OK, msg ) ); 894 if ( m_pDialogHelper ) 895 box->SetText( m_pDialogHelper->getWindow()->GetText() ); 896 box->Execute(); 897 //Continue with installation of the remaining extensions 898 } 899 { 900 osl::MutexGuard aGuard( m_mutex ); 901 m_bWorking = false; 902 } 903 } 904 905 { 906 // when leaving the while loop with break, we should set working to false, too 907 osl::MutexGuard aGuard( m_mutex ); 908 m_bWorking = false; 909 } 910 911 if ( !bStartProgress ) 912 currentCmdEnv->stopProgress(); 913 } 914 //end for 915 //enable all buttons 916 // m_pDialog->m_bAddingExtensions = false; 917 // m_pDialog->updateButtonStates(); 918 #ifdef WNT 919 CoUninitialize(); 920 #endif 921 } 922 923 //------------------------------------------------------------------------------ 924 void ExtensionCmdQueue::Thread::_addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 925 const OUString &rPackageURL, 926 const OUString &rRepository, 927 const bool bWarnUser ) 928 { 929 //check if we have a string in anyTitle. For example "unopkg gui \" caused anyTitle to be void 930 //and anyTitle.get<OUString> throws as RuntimeException. 931 uno::Any anyTitle; 932 try 933 { 934 anyTitle = ::ucbhelper::Content( rPackageURL, rCmdEnv.get() ).getPropertyValue( OUSTR("Title") ); 935 } 936 catch ( uno::Exception & ) 937 { 938 return; 939 } 940 941 OUString sName; 942 if ( ! (anyTitle >>= sName) ) 943 { 944 OSL_ENSURE(0, "Could not get file name for extension."); 945 return; 946 } 947 948 rCmdEnv->setWarnUser( bWarnUser ); 949 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager(); 950 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() ); 951 OUString sTitle = searchAndReplaceAll( m_sAddingPackages, OUSTR("%EXTENSION_NAME"), sName ); 952 rCmdEnv->progressSection( sTitle, xAbortChannel ); 953 954 try 955 { 956 xExtMgr->addExtension(rPackageURL, uno::Sequence<beans::NamedValue>(), 957 rRepository, xAbortChannel, rCmdEnv.get() ); 958 } 959 catch ( ucb::CommandFailedException & ) 960 { 961 // When the extension is already installed we'll get a dialog asking if we want to overwrite. If we then press 962 // cancel this exception is thrown. 963 } 964 catch ( ucb::CommandAbortedException & ) 965 { 966 // User clicked the cancel button 967 // TODO: handle cancel 968 } 969 rCmdEnv->setWarnUser( false ); 970 } 971 972 //------------------------------------------------------------------------------ 973 void ExtensionCmdQueue::Thread::_removeExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 974 const uno::Reference< deployment::XPackage > &xPackage ) 975 { 976 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager(); 977 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() ); 978 OUString sTitle = searchAndReplaceAll( m_sRemovingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() ); 979 rCmdEnv->progressSection( sTitle, xAbortChannel ); 980 981 OUString id( dp_misc::getIdentifier( xPackage ) ); 982 try 983 { 984 xExtMgr->removeExtension( id, xPackage->getName(), xPackage->getRepositoryName(), xAbortChannel, rCmdEnv.get() ); 985 } 986 catch ( deployment::DeploymentException & ) 987 {} 988 catch ( ucb::CommandFailedException & ) 989 {} 990 catch ( ucb::CommandAbortedException & ) 991 {} 992 993 // Check, if there are still updates to be notified via menu bar icon 994 uno::Sequence< uno::Sequence< rtl::OUString > > aItemList; 995 UpdateDialog::createNotifyJob( false, aItemList ); 996 } 997 998 //------------------------------------------------------------------------------ 999 void ExtensionCmdQueue::Thread::_checkForUpdates( 1000 const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ) 1001 { 1002 UpdateDialog* pUpdateDialog; 1003 std::vector< UpdateData > vData; 1004 1005 const ::vos::OGuard guard( Application::GetSolarMutex() ); 1006 1007 pUpdateDialog = new UpdateDialog( m_xContext, m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, vExtensionList, &vData ); 1008 1009 pUpdateDialog->notifyMenubar( true, false ); // prepare the checking, if there updates to be notified via menu bar icon 1010 1011 if ( ( pUpdateDialog->Execute() == RET_OK ) && !vData.empty() ) 1012 { 1013 // If there is at least one directly downloadable dialog then we 1014 // open the install dialog. 1015 ::std::vector< UpdateData > dataDownload; 1016 int countWebsiteDownload = 0; 1017 typedef std::vector< dp_gui::UpdateData >::const_iterator cit; 1018 1019 for ( cit i = vData.begin(); i < vData.end(); i++ ) 1020 { 1021 if ( i->sWebsiteURL.getLength() > 0 ) 1022 countWebsiteDownload ++; 1023 else 1024 dataDownload.push_back( *i ); 1025 } 1026 1027 short nDialogResult = RET_OK; 1028 if ( !dataDownload.empty() ) 1029 { 1030 nDialogResult = UpdateInstallDialog( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, dataDownload, m_xContext ).Execute(); 1031 pUpdateDialog->notifyMenubar( false, true ); // Check, if there are still pending updates to be notified via menu bar icon 1032 } 1033 else 1034 pUpdateDialog->notifyMenubar( false, false ); // Check, if there are pending updates to be notified via menu bar icon 1035 1036 //Now start the webbrowser and navigate to the websites where we get the updates 1037 if ( RET_OK == nDialogResult ) 1038 { 1039 for ( cit i = vData.begin(); i < vData.end(); i++ ) 1040 { 1041 if ( m_pDialogHelper && ( i->sWebsiteURL.getLength() > 0 ) ) 1042 m_pDialogHelper->openWebBrowser( i->sWebsiteURL, m_pDialogHelper->getWindow()->GetText() ); 1043 } 1044 } 1045 } 1046 else 1047 pUpdateDialog->notifyMenubar( false, false ); // check if there updates to be notified via menu bar icon 1048 1049 delete pUpdateDialog; 1050 } 1051 1052 //------------------------------------------------------------------------------ 1053 void ExtensionCmdQueue::Thread::_enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 1054 const uno::Reference< deployment::XPackage > &xPackage ) 1055 { 1056 if ( !xPackage.is() ) 1057 return; 1058 1059 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager(); 1060 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() ); 1061 OUString sTitle = searchAndReplaceAll( m_sEnablingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() ); 1062 rCmdEnv->progressSection( sTitle, xAbortChannel ); 1063 1064 try 1065 { 1066 xExtMgr->enableExtension( xPackage, xAbortChannel, rCmdEnv.get() ); 1067 if ( m_pDialogHelper ) 1068 m_pDialogHelper->updatePackageInfo( xPackage ); 1069 } 1070 catch ( ::ucb::CommandAbortedException & ) 1071 {} 1072 } 1073 1074 //------------------------------------------------------------------------------ 1075 void ExtensionCmdQueue::Thread::_disableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 1076 const uno::Reference< deployment::XPackage > &xPackage ) 1077 { 1078 if ( !xPackage.is() ) 1079 return; 1080 1081 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager(); 1082 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() ); 1083 OUString sTitle = searchAndReplaceAll( m_sDisablingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() ); 1084 rCmdEnv->progressSection( sTitle, xAbortChannel ); 1085 1086 try 1087 { 1088 xExtMgr->disableExtension( xPackage, xAbortChannel, rCmdEnv.get() ); 1089 if ( m_pDialogHelper ) 1090 m_pDialogHelper->updatePackageInfo( xPackage ); 1091 } 1092 catch ( ::ucb::CommandAbortedException & ) 1093 {} 1094 } 1095 1096 //------------------------------------------------------------------------------ 1097 void ExtensionCmdQueue::Thread::_acceptLicense( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 1098 const uno::Reference< deployment::XPackage > &xPackage ) 1099 { 1100 if ( !xPackage.is() ) 1101 return; 1102 1103 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager(); 1104 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() ); 1105 OUString sTitle = searchAndReplaceAll( m_sAcceptLicense, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() ); 1106 rCmdEnv->progressSection( sTitle, xAbortChannel ); 1107 1108 try 1109 { 1110 xExtMgr->checkPrerequisitesAndEnable( xPackage, xAbortChannel, rCmdEnv.get() ); 1111 if ( m_pDialogHelper ) 1112 m_pDialogHelper->updatePackageInfo( xPackage ); 1113 } 1114 catch ( ::ucb::CommandAbortedException & ) 1115 {} 1116 } 1117 1118 //------------------------------------------------------------------------------ 1119 void ExtensionCmdQueue::Thread::onTerminated() 1120 { 1121 ::osl::MutexGuard g(m_mutex); 1122 m_bTerminated = true; 1123 } 1124 1125 //------------------------------------------------------------------------------ 1126 OUString ExtensionCmdQueue::Thread::searchAndReplaceAll( const OUString &rSource, 1127 const OUString &rWhat, 1128 const OUString &rWith ) 1129 { 1130 OUString aRet( rSource ); 1131 sal_Int32 nLen = rWhat.getLength(); 1132 1133 if ( !nLen ) 1134 return aRet; 1135 1136 sal_Int32 nIndex = rSource.indexOf( rWhat ); 1137 while ( nIndex != -1 ) 1138 { 1139 aRet = aRet.replaceAt( nIndex, nLen, rWith ); 1140 nIndex = aRet.indexOf( rWhat, nIndex + rWith.getLength() ); 1141 } 1142 return aRet; 1143 } 1144 1145 1146 //------------------------------------------------------------------------------ 1147 //------------------------------------------------------------------------------ 1148 //------------------------------------------------------------------------------ 1149 ExtensionCmdQueue::ExtensionCmdQueue( DialogHelper * pDialogHelper, 1150 TheExtensionManager *pManager, 1151 const uno::Reference< uno::XComponentContext > &rContext ) 1152 : m_thread( new Thread( pDialogHelper, pManager, rContext ) ) 1153 { 1154 m_thread->launch(); 1155 } 1156 1157 ExtensionCmdQueue::~ExtensionCmdQueue() { 1158 stop(); 1159 } 1160 1161 void ExtensionCmdQueue::addExtension( const ::rtl::OUString & extensionURL, 1162 const ::rtl::OUString & repository, 1163 const bool bWarnUser ) 1164 { 1165 m_thread->addExtension( extensionURL, repository, bWarnUser ); 1166 } 1167 1168 void ExtensionCmdQueue::removeExtension( const uno::Reference< deployment::XPackage > &rPackage ) 1169 { 1170 m_thread->removeExtension( rPackage ); 1171 } 1172 1173 void ExtensionCmdQueue::enableExtension( const uno::Reference< deployment::XPackage > &rPackage, 1174 const bool bEnable ) 1175 { 1176 m_thread->enableExtension( rPackage, bEnable ); 1177 } 1178 1179 void ExtensionCmdQueue::checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ) 1180 { 1181 m_thread->checkForUpdates( vExtensionList ); 1182 } 1183 1184 void ExtensionCmdQueue::acceptLicense( const uno::Reference< deployment::XPackage > &rPackage ) 1185 { 1186 m_thread->acceptLicense( rPackage ); 1187 } 1188 1189 void ExtensionCmdQueue::syncRepositories( const uno::Reference< uno::XComponentContext > &xContext ) 1190 { 1191 dp_misc::syncRepositories( new ProgressCmdEnv( xContext, NULL, OUSTR("Extension Manager") ) ); 1192 } 1193 1194 void ExtensionCmdQueue::stop() 1195 { 1196 m_thread->stop(); 1197 } 1198 1199 bool ExtensionCmdQueue::isBusy() 1200 { 1201 return m_thread->isBusy(); 1202 } 1203 1204 void handleInteractionRequest( const uno::Reference< uno::XComponentContext > & xContext, 1205 const uno::Reference< task::XInteractionRequest > & xRequest ) 1206 { 1207 ::rtl::Reference< ProgressCmdEnv > xCmdEnv( new ProgressCmdEnv( xContext, NULL, OUSTR("Extension Manager") ) ); 1208 xCmdEnv->handle( xRequest ); 1209 } 1210 1211 } //namespace dp_gui 1212 1213