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