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/layout.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 startProgress();
159 : void stopProgress();
160 : void progressSection( const OUString &rText,
161 : const uno::Reference< task::XAbortChannel > &xAbortChannel = 0 );
162 0 : inline bool isAborted() const { return m_bAborted; }
163 0 : inline void setWarnUser( bool bNewVal ) { m_bWarnUser = bNewVal; }
164 :
165 : // XCommandEnvironment
166 : virtual uno::Reference< task::XInteractionHandler > SAL_CALL getInteractionHandler()
167 : throw ( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
168 : virtual uno::Reference< ucb::XProgressHandler > SAL_CALL getProgressHandler()
169 : throw ( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
170 :
171 : // XInteractionHandler
172 : virtual void SAL_CALL handle( uno::Reference< task::XInteractionRequest > const & xRequest )
173 : throw ( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
174 :
175 : // XProgressHandler
176 : virtual void SAL_CALL push( uno::Any const & Status )
177 : throw ( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
178 : virtual void SAL_CALL update( uno::Any const & Status )
179 : throw ( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
180 : virtual void SAL_CALL pop() throw ( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
181 : };
182 :
183 :
184 0 : struct ExtensionCmd
185 : {
186 : enum E_CMD_TYPE { ADD, ENABLE, DISABLE, REMOVE, CHECK_FOR_UPDATES, ACCEPT_LICENSE };
187 :
188 : E_CMD_TYPE m_eCmdType;
189 : bool m_bWarnUser;
190 : OUString m_sExtensionURL;
191 : OUString m_sRepository;
192 : uno::Reference< deployment::XPackage > m_xPackage;
193 : std::vector< uno::Reference< deployment::XPackage > > m_vExtensionList;
194 :
195 0 : ExtensionCmd( const E_CMD_TYPE eCommand,
196 : const OUString &rExtensionURL,
197 : const OUString &rRepository,
198 : const bool bWarnUser )
199 : : m_eCmdType( eCommand ),
200 : m_bWarnUser( bWarnUser ),
201 : m_sExtensionURL( rExtensionURL ),
202 0 : m_sRepository( rRepository ) {};
203 0 : ExtensionCmd( const E_CMD_TYPE eCommand,
204 : const uno::Reference< deployment::XPackage > &rPackage )
205 : : m_eCmdType( eCommand ),
206 : m_bWarnUser( false ),
207 0 : m_xPackage( rPackage ) {};
208 0 : ExtensionCmd( const E_CMD_TYPE eCommand,
209 : const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
210 : : m_eCmdType( eCommand ),
211 : m_bWarnUser( false ),
212 0 : m_vExtensionList( vExtensionList ) {};
213 : };
214 :
215 : typedef ::boost::shared_ptr< ExtensionCmd > TExtensionCmd;
216 :
217 :
218 : class ExtensionCmdQueue::Thread: public salhelper::Thread
219 : {
220 : public:
221 : Thread( DialogHelper *pDialogHelper,
222 : TheExtensionManager *pManager,
223 : const uno::Reference< uno::XComponentContext > & rContext );
224 :
225 : void addExtension( const OUString &rExtensionURL,
226 : const OUString &rRepository,
227 : const bool bWarnUser );
228 : void removeExtension( const uno::Reference< deployment::XPackage > &rPackage );
229 : void enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
230 : const bool bEnable );
231 : void checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList );
232 : void acceptLicense( const uno::Reference< deployment::XPackage > &rPackage );
233 : void stop();
234 : bool isBusy();
235 :
236 : private:
237 : virtual ~Thread();
238 :
239 : virtual void execute() SAL_OVERRIDE;
240 :
241 : void _insert(const TExtensionCmd& rExtCmd);
242 :
243 : void _addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
244 : const OUString &rPackageURL,
245 : const OUString &rRepository,
246 : const bool bWarnUser );
247 : void _removeExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
248 : const uno::Reference< deployment::XPackage > &xPackage );
249 : void _enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
250 : const uno::Reference< deployment::XPackage > &xPackage );
251 : void _disableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
252 : const uno::Reference< deployment::XPackage > &xPackage );
253 : void _checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList );
254 : void _acceptLicense( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
255 : const uno::Reference< deployment::XPackage > &xPackage );
256 :
257 : enum Input { NONE, START, STOP };
258 :
259 : uno::Reference< uno::XComponentContext > m_xContext;
260 : std::queue< TExtensionCmd > m_queue;
261 :
262 : DialogHelper *m_pDialogHelper;
263 : TheExtensionManager *m_pManager;
264 :
265 : const OUString m_sEnablingPackages;
266 : const OUString m_sDisablingPackages;
267 : const OUString m_sAddingPackages;
268 : const OUString m_sRemovingPackages;
269 : const OUString m_sDefaultCmd;
270 : const OUString m_sAcceptLicense;
271 : osl::Condition m_wakeup;
272 : osl::Mutex m_mutex;
273 : Input m_eInput;
274 : bool m_bStopped;
275 : bool m_bWorking;
276 : };
277 :
278 :
279 0 : void ProgressCmdEnv::startProgress()
280 : {
281 0 : m_nCurrentProgress = 0;
282 :
283 0 : if ( m_pDialogHelper )
284 0 : m_pDialogHelper->showProgress( true );
285 0 : }
286 :
287 :
288 0 : void ProgressCmdEnv::stopProgress()
289 : {
290 0 : if ( m_pDialogHelper )
291 0 : m_pDialogHelper->showProgress( false );
292 0 : }
293 :
294 :
295 0 : void ProgressCmdEnv::progressSection( const OUString &rText,
296 : const uno::Reference< task::XAbortChannel > &xAbortChannel )
297 : {
298 0 : m_xAbortChannel = xAbortChannel;
299 0 : if (! m_bAborted)
300 : {
301 0 : m_nCurrentProgress = 0;
302 0 : if ( m_pDialogHelper )
303 : {
304 0 : m_pDialogHelper->updateProgress( rText, xAbortChannel );
305 0 : m_pDialogHelper->updateProgress( 5 );
306 : }
307 : }
308 0 : }
309 :
310 :
311 0 : void ProgressCmdEnv::updateProgress()
312 : {
313 0 : if ( ! m_bAborted )
314 : {
315 0 : long nProgress = ((m_nCurrentProgress*5) % 100) + 5;
316 0 : if ( m_pDialogHelper )
317 0 : m_pDialogHelper->updateProgress( nProgress );
318 : }
319 0 : }
320 :
321 :
322 0 : ProgressCmdEnv::~ProgressCmdEnv()
323 : {
324 : // TODO: stop all threads and wait
325 0 : }
326 :
327 :
328 :
329 : // XCommandEnvironment
330 :
331 0 : uno::Reference< task::XInteractionHandler > ProgressCmdEnv::getInteractionHandler()
332 : throw ( uno::RuntimeException, std::exception )
333 : {
334 0 : return this;
335 : }
336 :
337 :
338 0 : uno::Reference< ucb::XProgressHandler > ProgressCmdEnv::getProgressHandler()
339 : throw ( uno::RuntimeException, std::exception )
340 : {
341 0 : return this;
342 : }
343 :
344 :
345 : // XInteractionHandler
346 :
347 0 : void ProgressCmdEnv::handle( uno::Reference< task::XInteractionRequest > const & xRequest )
348 : throw ( uno::RuntimeException, std::exception )
349 : {
350 0 : uno::Any request( xRequest->getRequest() );
351 : OSL_ASSERT( request.getValueTypeClass() == uno::TypeClass_EXCEPTION );
352 : dp_misc::TRACE( "[dp_gui_cmdenv.cxx] incoming request:\n"
353 0 : + ::comphelper::anyToString(request) + "\n");
354 :
355 0 : lang::WrappedTargetException wtExc;
356 0 : deployment::DependencyException depExc;
357 0 : deployment::LicenseException licExc;
358 0 : deployment::VersionException verExc;
359 0 : deployment::InstallException instExc;
360 0 : deployment::PlatformException platExc;
361 :
362 : // selections:
363 0 : bool approve = false;
364 0 : bool abort = false;
365 :
366 0 : if (request >>= wtExc) {
367 : // handable deployment error signalled, e.g.
368 : // bundle item registration failed, notify cause only:
369 0 : uno::Any cause;
370 0 : deployment::DeploymentException dpExc;
371 0 : if (wtExc.TargetException >>= dpExc)
372 0 : cause = dpExc.Cause;
373 : else {
374 0 : ucb::CommandFailedException cfExc;
375 0 : if (wtExc.TargetException >>= cfExc)
376 0 : cause = cfExc.Reason;
377 : else
378 0 : cause = wtExc.TargetException;
379 : }
380 0 : update_( cause );
381 :
382 : // ignore intermediate errors of legacy packages, i.e.
383 : // former pkgchk behaviour:
384 0 : const uno::Reference< deployment::XPackage > xPackage( wtExc.Context, uno::UNO_QUERY );
385 : OSL_ASSERT( xPackage.is() );
386 0 : if ( xPackage.is() )
387 : {
388 0 : const uno::Reference< deployment::XPackageTypeInfo > xPackageType( xPackage->getPackageType() );
389 : OSL_ASSERT( xPackageType.is() );
390 0 : if (xPackageType.is())
391 : {
392 0 : approve = ( xPackage->isBundle() &&
393 0 : xPackageType->getMediaType().match(
394 0 : "application/vnd.sun.star.legacy-package-bundle" ));
395 0 : }
396 : }
397 0 : abort = !approve;
398 : }
399 0 : else if (request >>= depExc)
400 : {
401 0 : std::vector< OUString > deps;
402 0 : for (sal_Int32 i = 0; i < depExc.UnsatisfiedDependencies.getLength();
403 : ++i)
404 : {
405 : deps.push_back(
406 0 : dp_misc::Dependencies::getErrorText( depExc.UnsatisfiedDependencies[i]) );
407 : }
408 : {
409 0 : SolarMutexGuard guard;
410 0 : short n = ScopedVclPtrInstance<DependencyDialog>::Create( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, deps )->Execute();
411 : // Distinguish between closing the dialog and programatically
412 : // canceling the dialog (headless VCL):
413 : approve = n == RET_OK
414 0 : || (n == RET_CANCEL && !Application::IsDialogCancelEnabled());
415 0 : }
416 : }
417 0 : else if (request >>= licExc)
418 : {
419 : uno::Reference< ui::dialogs::XExecutableDialog > xDialog(
420 : deployment::ui::LicenseDialog::create(
421 0 : m_xContext, VCLUnoHelper::GetInterface( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL ),
422 0 : licExc.ExtensionName, licExc.Text ) );
423 0 : sal_Int16 res = xDialog->execute();
424 0 : if ( res == ui::dialogs::ExecutableDialogResults::CANCEL )
425 0 : abort = true;
426 0 : else if ( res == ui::dialogs::ExecutableDialogResults::OK )
427 0 : approve = true;
428 : else
429 : {
430 : OSL_ASSERT(false);
431 0 : }
432 : }
433 0 : else if (request >>= verExc)
434 : {
435 : sal_uInt32 id;
436 0 : switch (dp_misc::compareVersions(
437 0 : verExc.NewVersion, verExc.Deployed->getVersion() ))
438 : {
439 : case dp_misc::LESS:
440 0 : id = RID_STR_WARNING_VERSION_LESS;
441 0 : break;
442 : case dp_misc::EQUAL:
443 0 : id = RID_STR_WARNING_VERSION_EQUAL;
444 0 : break;
445 : default: // dp_misc::GREATER
446 0 : id = RID_STR_WARNING_VERSION_GREATER;
447 0 : break;
448 : }
449 : OSL_ASSERT( verExc.Deployed.is() );
450 : bool bEqualNames = verExc.NewDisplayName.equals(
451 0 : verExc.Deployed->getDisplayName());
452 : {
453 0 : SolarMutexGuard guard;
454 0 : ScopedVclPtrInstance<MessageDialog> box(m_pDialogHelper? m_pDialogHelper->getWindow() : NULL,
455 0 : ResId(id, *DeploymentGuiResMgr::get()), VCL_MESSAGE_WARNING, VCL_BUTTONS_OK_CANCEL);
456 0 : OUString s;
457 0 : if (bEqualNames)
458 : {
459 0 : s = box->get_primary_text();
460 : }
461 0 : else if (id == RID_STR_WARNING_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_STR_WARNING_VERSION_LESS)
469 : {
470 0 : s = ResId(RID_STR_WARNINGBOX_VERSION_LESS_DIFFERENT_NAMES, *DeploymentGuiResMgr::get()).toString();
471 : }
472 0 : else if (id == RID_STR_WARNING_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->set_primary_text(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 : ScopedVclPtrInstance< MessageDialog > box(m_pDialogHelper? m_pDialogHelper->getWindow() : nullptr, sMsg);
510 0 : box->Execute();
511 0 : approve = true;
512 : }
513 :
514 0 : if (!approve && !abort)
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 : ScopedVclPtrInstance< MessageDialog > aBox(m_pDialogHelper? m_pDialogHelper->getWindow() : nullptr, 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 = static_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 : ScopedVclPtr<MessageDialog> box(
817 0 : VclPtr<MessageDialog>::Create(currentCmdEnv->activeDialog(), 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 0 : const SolarMutexGuard guard;
927 :
928 0 : std::vector< UpdateData > vData;
929 0 : ScopedVclPtrInstance<UpdateDialog> pUpdateDialog( m_xContext, m_pDialogHelper? m_pDialogHelper->getWindow() : nullptr, vExtensionList, &vData );
930 :
931 0 : pUpdateDialog->notifyMenubar( true, false ); // prepare the checking, if there updates to be notified via menu bar icon
932 :
933 0 : if ( ( pUpdateDialog->Execute() == RET_OK ) && !vData.empty() )
934 : {
935 : // If there is at least one directly downloadable extension then we
936 : // open the install dialog.
937 0 : ::std::vector< UpdateData > dataDownload;
938 0 : int countWebsiteDownload = 0;
939 : typedef std::vector< dp_gui::UpdateData >::const_iterator cit;
940 :
941 0 : for ( cit i = vData.begin(); i < vData.end(); ++i )
942 : {
943 0 : if ( !i->sWebsiteURL.isEmpty() )
944 0 : countWebsiteDownload ++;
945 : else
946 0 : dataDownload.push_back( *i );
947 : }
948 :
949 0 : short nDialogResult = RET_OK;
950 0 : if ( !dataDownload.empty() )
951 : {
952 0 : nDialogResult = ScopedVclPtrInstance<UpdateInstallDialog>::Create( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, dataDownload, m_xContext )->Execute();
953 0 : pUpdateDialog->notifyMenubar( false, true ); // Check, if there are still pending updates to be notified via menu bar icon
954 : }
955 : else
956 0 : pUpdateDialog->notifyMenubar( false, false ); // Check, if there are pending updates to be notified via menu bar icon
957 :
958 : //Now start the webbrowser and navigate to the websites where we get the updates
959 0 : if ( RET_OK == nDialogResult )
960 : {
961 0 : for ( cit i = vData.begin(); i < vData.end(); ++i )
962 : {
963 0 : if ( m_pDialogHelper && ( !i->sWebsiteURL.isEmpty() ) )
964 0 : m_pDialogHelper->openWebBrowser( i->sWebsiteURL, m_pDialogHelper->getWindow()->GetText() );
965 : }
966 0 : }
967 : }
968 : else
969 0 : pUpdateDialog->notifyMenubar( false, false ); // check if there updates to be notified via menu bar icon
970 :
971 0 : pUpdateDialog.disposeAndClear();
972 0 : }
973 :
974 :
975 0 : void ExtensionCmdQueue::Thread::_enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
976 : const uno::Reference< deployment::XPackage > &xPackage )
977 : {
978 0 : if ( !xPackage.is() )
979 0 : return;
980 :
981 0 : uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
982 0 : uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
983 : OUString sTitle(
984 : m_sEnablingPackages.replaceAll("%EXTENSION_NAME",
985 0 : xPackage->getDisplayName()));
986 0 : rCmdEnv->progressSection( sTitle, xAbortChannel );
987 :
988 : try
989 : {
990 0 : xExtMgr->enableExtension( xPackage, xAbortChannel, rCmdEnv.get() );
991 0 : if ( m_pDialogHelper )
992 0 : m_pDialogHelper->updatePackageInfo( xPackage );
993 : }
994 0 : catch ( const ::ucb::CommandAbortedException & )
995 0 : {}
996 : }
997 :
998 :
999 0 : void ExtensionCmdQueue::Thread::_disableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
1000 : const uno::Reference< deployment::XPackage > &xPackage )
1001 : {
1002 0 : if ( !xPackage.is() )
1003 0 : return;
1004 :
1005 0 : uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
1006 0 : uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
1007 : OUString sTitle(
1008 : m_sDisablingPackages.replaceAll("%EXTENSION_NAME",
1009 0 : xPackage->getDisplayName()));
1010 0 : rCmdEnv->progressSection( sTitle, xAbortChannel );
1011 :
1012 : try
1013 : {
1014 0 : xExtMgr->disableExtension( xPackage, xAbortChannel, rCmdEnv.get() );
1015 0 : if ( m_pDialogHelper )
1016 0 : m_pDialogHelper->updatePackageInfo( xPackage );
1017 : }
1018 0 : catch ( const ::ucb::CommandAbortedException & )
1019 0 : {}
1020 : }
1021 :
1022 :
1023 0 : void ExtensionCmdQueue::Thread::_acceptLicense( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
1024 : const uno::Reference< deployment::XPackage > &xPackage )
1025 : {
1026 0 : if ( !xPackage.is() )
1027 0 : return;
1028 :
1029 0 : uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
1030 0 : uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
1031 : OUString sTitle(
1032 : m_sAcceptLicense.replaceAll("%EXTENSION_NAME",
1033 0 : xPackage->getDisplayName()));
1034 0 : rCmdEnv->progressSection( sTitle, xAbortChannel );
1035 :
1036 : try
1037 : {
1038 0 : xExtMgr->checkPrerequisitesAndEnable( xPackage, xAbortChannel, rCmdEnv.get() );
1039 0 : if ( m_pDialogHelper )
1040 0 : m_pDialogHelper->updatePackageInfo( xPackage );
1041 : }
1042 0 : catch ( const ::ucb::CommandAbortedException & )
1043 0 : {}
1044 : }
1045 :
1046 0 : void ExtensionCmdQueue::Thread::_insert(const TExtensionCmd& rExtCmd)
1047 : {
1048 0 : ::osl::MutexGuard aGuard( m_mutex );
1049 :
1050 : // If someone called stop then we do not process the command -> game over!
1051 0 : if ( m_bStopped )
1052 0 : return;
1053 :
1054 0 : m_queue.push( rExtCmd );
1055 0 : m_eInput = START;
1056 0 : m_wakeup.set();
1057 : }
1058 :
1059 :
1060 0 : ExtensionCmdQueue::ExtensionCmdQueue( DialogHelper * pDialogHelper,
1061 : TheExtensionManager *pManager,
1062 : const uno::Reference< uno::XComponentContext > &rContext )
1063 0 : : m_thread( new Thread( pDialogHelper, pManager, rContext ) )
1064 : {
1065 0 : m_thread->launch();
1066 0 : }
1067 :
1068 0 : ExtensionCmdQueue::~ExtensionCmdQueue() {
1069 0 : stop();
1070 0 : }
1071 :
1072 0 : void ExtensionCmdQueue::addExtension( const OUString & extensionURL,
1073 : const OUString & repository,
1074 : const bool bWarnUser )
1075 : {
1076 0 : m_thread->addExtension( extensionURL, repository, bWarnUser );
1077 0 : }
1078 :
1079 0 : void ExtensionCmdQueue::removeExtension( const uno::Reference< deployment::XPackage > &rPackage )
1080 : {
1081 0 : m_thread->removeExtension( rPackage );
1082 0 : }
1083 :
1084 0 : void ExtensionCmdQueue::enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
1085 : const bool bEnable )
1086 : {
1087 0 : m_thread->enableExtension( rPackage, bEnable );
1088 0 : }
1089 :
1090 0 : void ExtensionCmdQueue::checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
1091 : {
1092 0 : m_thread->checkForUpdates( vExtensionList );
1093 0 : }
1094 :
1095 0 : void ExtensionCmdQueue::acceptLicense( const uno::Reference< deployment::XPackage > &rPackage )
1096 : {
1097 0 : m_thread->acceptLicense( rPackage );
1098 0 : }
1099 :
1100 0 : void ExtensionCmdQueue::syncRepositories( const uno::Reference< uno::XComponentContext > &xContext )
1101 : {
1102 0 : dp_misc::syncRepositories( false, new ProgressCmdEnv( xContext, NULL, "Extension Manager" ) );
1103 0 : }
1104 :
1105 0 : void ExtensionCmdQueue::stop()
1106 : {
1107 0 : m_thread->stop();
1108 0 : }
1109 :
1110 0 : bool ExtensionCmdQueue::isBusy()
1111 : {
1112 0 : return m_thread->isBusy();
1113 : }
1114 :
1115 0 : void handleInteractionRequest( const uno::Reference< uno::XComponentContext > & xContext,
1116 : const uno::Reference< task::XInteractionRequest > & xRequest )
1117 : {
1118 0 : ::rtl::Reference< ProgressCmdEnv > xCmdEnv( new ProgressCmdEnv( xContext, NULL, "Extension Manager" ) );
1119 0 : xCmdEnv->handle( xRequest );
1120 0 : }
1121 :
1122 3 : } //namespace dp_gui
1123 :
1124 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|