docthemes: Save themes def. to a file when added to ColorSets
[LibreOffice.git] / desktop / source / app / check_ext_deps.cxx
blob90446384f3110cf59632890f30bd6f97a5b9e2ac
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_folders.h>
21 #include <config_features.h>
23 #include <rtl/bootstrap.hxx>
24 #include <rtl/ustring.hxx>
25 #include <sal/log.hxx>
26 #include <cppuhelper/implbase.hxx>
28 #include <comphelper/diagnose_ex.hxx>
29 #include <toolkit/helper/vclunohelper.hxx>
31 #include <comphelper/lok.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <cppuhelper/exc_hlp.hxx>
34 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
35 #include <com/sun/star/ucb/CommandAbortedException.hpp>
36 #include <com/sun/star/ucb/CommandFailedException.hpp>
37 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
38 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <com/sun/star/beans/NamedValue.hpp>
40 #include <com/sun/star/configuration/theDefaultProvider.hpp>
41 #include <com/sun/star/deployment/DeploymentException.hpp>
42 #include <com/sun/star/deployment/XPackage.hpp>
43 #include <com/sun/star/deployment/ExtensionManager.hpp>
44 #include <com/sun/star/deployment/LicenseException.hpp>
45 #include <com/sun/star/deployment/ui/LicenseDialog.hpp>
46 #include <com/sun/star/task/OfficeRestartManager.hpp>
47 #include <com/sun/star/task/XInteractionApprove.hpp>
48 #include <com/sun/star/task/XInteractionAbort.hpp>
49 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
50 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
51 #include <com/sun/star/util/XChangesBatch.hpp>
53 #include <app.hxx>
54 #include <utility>
56 #include <dp_misc.h>
58 using namespace desktop;
59 using namespace com::sun::star;
60 using namespace com::sun::star::lang;
61 using namespace com::sun::star::task;
62 using namespace com::sun::star::uno;
64 namespace
66 //For use with XExtensionManager.synchronize
67 class SilentCommandEnv
68 : public ::cppu::WeakImplHelper< ucb::XCommandEnvironment,
69 task::XInteractionHandler,
70 ucb::XProgressHandler >
72 uno::Reference<uno::XComponentContext> mxContext;
73 Desktop *mpDesktop;
74 sal_Int32 mnLevel;
75 sal_Int32 mnProgress;
77 public:
78 SilentCommandEnv(
79 uno::Reference<uno::XComponentContext> xContext,
80 Desktop* pDesktop );
81 virtual ~SilentCommandEnv() override;
83 // XCommandEnvironment
84 virtual uno::Reference<task::XInteractionHandler > SAL_CALL
85 getInteractionHandler() override;
86 virtual uno::Reference<ucb::XProgressHandler >
87 SAL_CALL getProgressHandler() override;
89 // XInteractionHandler
90 virtual void SAL_CALL handle(
91 uno::Reference<task::XInteractionRequest > const & xRequest ) override;
93 // XProgressHandler
94 virtual void SAL_CALL push( uno::Any const & Status ) override;
95 virtual void SAL_CALL update( uno::Any const & Status ) override;
96 virtual void SAL_CALL pop() override;
100 SilentCommandEnv::SilentCommandEnv(
101 uno::Reference<uno::XComponentContext> xContext,
102 Desktop* pDesktop ):
103 mxContext(std::move( xContext )),
104 mpDesktop( pDesktop ),
105 mnLevel( 0 ),
106 mnProgress( 25 )
110 SilentCommandEnv::~SilentCommandEnv()
112 if (mpDesktop)
113 mpDesktop->SetSplashScreenText(OUString());
117 Reference<task::XInteractionHandler> SilentCommandEnv::getInteractionHandler()
119 return this;
123 Reference<ucb::XProgressHandler> SilentCommandEnv::getProgressHandler()
125 return this;
129 // XInteractionHandler
130 void SilentCommandEnv::handle( Reference< task::XInteractionRequest> const & xRequest )
132 deployment::LicenseException licExc;
134 uno::Any request( xRequest->getRequest() );
135 bool bApprove = true;
137 if ( request >>= licExc )
139 uno::Reference< ui::dialogs::XExecutableDialog > xDialog(
140 deployment::ui::LicenseDialog::create(
141 mxContext, VCLUnoHelper::GetInterface( nullptr ),
142 licExc.ExtensionName, licExc.Text ) );
143 sal_Int16 res = xDialog->execute();
144 if ( res == ui::dialogs::ExecutableDialogResults::CANCEL )
145 bApprove = false;
146 else if ( res == ui::dialogs::ExecutableDialogResults::OK )
147 bApprove = true;
148 else
150 OSL_ASSERT(false);
154 // We approve everything here
155 uno::Sequence< Reference< task::XInteractionContinuation > > conts( xRequest->getContinuations() );
156 Reference< task::XInteractionContinuation > const * pConts = conts.getConstArray();
157 sal_Int32 len = conts.getLength();
159 for ( sal_Int32 pos = 0; pos < len; ++pos )
161 if ( bApprove )
163 uno::Reference< task::XInteractionApprove > xInteractionApprove( pConts[ pos ], uno::UNO_QUERY );
164 if ( xInteractionApprove.is() )
165 xInteractionApprove->select();
167 else
169 uno::Reference< task::XInteractionAbort > xInteractionAbort( pConts[ pos ], uno::UNO_QUERY );
170 if ( xInteractionAbort.is() )
171 xInteractionAbort->select();
177 // XProgressHandler
178 void SilentCommandEnv::push( uno::Any const & rStatus )
180 OUString sText;
181 mnLevel += 1;
183 if (mpDesktop && rStatus.hasValue() && (rStatus >>= sText))
185 if ( mnLevel <= 3 )
186 mpDesktop->SetSplashScreenText( sText );
187 else
188 mpDesktop->SetSplashScreenProgress( ++mnProgress );
193 void SilentCommandEnv::update( uno::Any const & rStatus )
195 OUString sText;
196 if (mpDesktop && rStatus.hasValue() && (rStatus >>= sText))
198 mpDesktop->SetSplashScreenText( sText );
203 void SilentCommandEnv::pop()
205 mnLevel -= 1;
208 } // end namespace
211 constexpr OUString aAccessSrvc = u"com.sun.star.configuration.ConfigurationUpdateAccess"_ustr;
213 static sal_Int16 impl_showExtensionDialog( uno::Reference< uno::XComponentContext > const &xContext )
215 uno::Reference< uno::XInterface > xService;
216 sal_Int16 nRet = 0;
218 uno::Reference< lang::XMultiComponentFactory > xServiceManager( xContext->getServiceManager() );
219 if( !xServiceManager.is() )
220 throw uno::RuntimeException(
221 u"impl_showExtensionDialog(): unable to obtain service manager from component context"_ustr, uno::Reference< uno::XInterface > () );
223 xService = xServiceManager->createInstanceWithContext( u"com.sun.star.deployment.ui.UpdateRequiredDialog"_ustr, xContext );
224 uno::Reference< ui::dialogs::XExecutableDialog > xExecutable( xService, uno::UNO_QUERY );
225 if ( xExecutable.is() )
226 nRet = xExecutable->execute();
228 return nRet;
232 // Check dependencies of all packages
234 static bool impl_checkDependencies( const uno::Reference< uno::XComponentContext > &xContext )
236 uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages;
237 uno::Reference< deployment::XExtensionManager > xExtensionManager = deployment::ExtensionManager::get( xContext );
239 if ( !xExtensionManager.is() )
241 SAL_WARN( "desktop.app", "Could not get the Extension Manager!" );
242 return true;
245 try {
246 xAllPackages = xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(),
247 uno::Reference< ucb::XCommandEnvironment >() );
249 catch ( const deployment::DeploymentException & ) { return true; }
250 catch ( const ucb::CommandFailedException & ) { return true; }
251 catch ( const ucb::CommandAbortedException & ) { return true; }
252 catch ( const lang::IllegalArgumentException & e ) {
253 css::uno::Any anyEx = cppu::getCaughtException();
254 throw css::lang::WrappedTargetRuntimeException( e.Message,
255 e.Context, anyEx );
258 #if OSL_DEBUG_LEVEL >= 2
259 sal_Int32 const nMax = 3;
260 #else
261 sal_Int32 const nMax = 2;
262 #endif
264 for (uno::Sequence<uno::Reference<deployment::XPackage>> const& xPackageList : xAllPackages)
266 for ( sal_Int32 j = 0; (j<nMax) && (j < xPackageList.getLength()); ++j )
268 uno::Reference< deployment::XPackage > xPackage = xPackageList[j];
269 if ( xPackage.is() )
271 bool bRegistered = false;
272 try {
273 beans::Optional< beans::Ambiguous< sal_Bool > > option( xPackage->isRegistered( uno::Reference< task::XAbortChannel >(),
274 uno::Reference< ucb::XCommandEnvironment >() ) );
275 if ( option.IsPresent )
277 ::beans::Ambiguous< sal_Bool > const & reg = option.Value;
278 if ( reg.IsAmbiguous )
279 bRegistered = false;
280 else
281 bRegistered = reg.Value;
283 else
284 bRegistered = false;
286 catch ( const uno::RuntimeException & ) { throw; }
287 catch (const uno::Exception & ) {
288 TOOLS_WARN_EXCEPTION( "desktop.app", "" );
291 if ( bRegistered )
293 bool bDependenciesValid = false;
294 try {
295 bDependenciesValid = xPackage->checkDependencies( uno::Reference< ucb::XCommandEnvironment >() );
297 catch ( const deployment::DeploymentException & ) {}
298 if ( ! bDependenciesValid )
300 return false;
306 return true;
310 // resets the 'check needed' flag (needed, if aborted)
312 static void impl_setNeedsCompatCheck()
314 try {
315 Reference< XMultiServiceFactory > theConfigProvider(
316 configuration::theDefaultProvider::get(
317 comphelper::getProcessComponentContext() ) );
319 beans::NamedValue v( u"nodepath"_ustr,
320 Any( u"org.openoffice.Setup/Office"_ustr ) );
321 Sequence< Any > theArgs{ Any(v) };
322 Reference< beans::XPropertySet > pset(
323 theConfigProvider->createInstanceWithArguments( aAccessSrvc, theArgs ), UNO_QUERY_THROW );
325 Any value( u"never"_ustr );
327 pset->setPropertyValue(u"LastCompatibilityCheckID"_ustr, value );
328 Reference< util::XChangesBatch >( pset, UNO_QUERY_THROW )->commitChanges();
330 catch (const Exception&) {}
334 // to check if we need checking the dependencies of the extensions again, we compare
335 // the build id of the office with the one of the last check
337 static bool impl_needsCompatCheck()
339 bool bNeedsCheck = false;
340 OUString aLastCheckBuildID;
341 OUString aCurrentBuildID( u"${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ":buildid}"_ustr );
342 rtl::Bootstrap::expandMacros( aCurrentBuildID );
344 try {
345 Reference< XMultiServiceFactory > theConfigProvider(
346 configuration::theDefaultProvider::get(
347 comphelper::getProcessComponentContext() ) );
349 beans::NamedValue v( u"nodepath"_ustr,
350 Any( u"org.openoffice.Setup/Office"_ustr ) );
351 Sequence< Any > theArgs{ Any(v) };
352 Reference< beans::XPropertySet > pset(
353 theConfigProvider->createInstanceWithArguments( aAccessSrvc, theArgs ), UNO_QUERY_THROW );
355 Any result = pset->getPropertyValue(u"LastCompatibilityCheckID"_ustr);
357 result >>= aLastCheckBuildID;
358 if ( aLastCheckBuildID != aCurrentBuildID )
360 bNeedsCheck = true;
361 result <<= aCurrentBuildID;
362 pset->setPropertyValue(u"LastCompatibilityCheckID"_ustr, result );
363 Reference< util::XChangesBatch >( pset, UNO_QUERY_THROW )->commitChanges();
365 #if OSL_DEBUG_LEVEL >= 2
366 bNeedsCheck = true;
367 #endif
369 catch (const css::uno::Exception&) {}
371 return bNeedsCheck;
375 // Do we need to check the dependencies of the extensions?
376 // When there are unresolved issues, we can't continue with startup
377 bool Desktop::CheckExtensionDependencies()
379 if (!impl_needsCompatCheck())
381 return false;
384 const uno::Reference< uno::XComponentContext >& xContext(
385 comphelper::getProcessComponentContext());
387 bool bDependenciesValid = impl_checkDependencies( xContext );
389 short nRet = 0;
391 if ( !bDependenciesValid )
392 nRet = impl_showExtensionDialog( xContext );
394 if ( nRet == -1 )
396 impl_setNeedsCompatCheck();
397 return true;
399 else
400 return false;
403 void Desktop::SynchronizeExtensionRepositories(bool bCleanedExtensionCache, Desktop* pDesktop)
405 const uno::Reference< uno::XComponentContext >& context(
406 comphelper::getProcessComponentContext());
407 uno::Reference< ucb::XCommandEnvironment > silent(
408 new SilentCommandEnv(context, pDesktop));
409 if (bCleanedExtensionCache) {
410 deployment::ExtensionManager::get(context)->reinstallDeployedExtensions(
411 true, u"user"_ustr, Reference<task::XAbortChannel>(), silent);
412 #if !HAVE_FEATURE_MACOSX_SANDBOX
413 if (!comphelper::LibreOfficeKit::isActive())
414 task::OfficeRestartManager::get(context)->requestRestart(
415 silent->getInteractionHandler());
416 #endif
417 } else {
418 // reinstallDeployedExtensions above already calls syncRepositories internally
420 // Force syncing repositories on startup. There are cases where the extension
421 // registration becomes invalid which leads to extensions not starting up, although
422 // installed and active. Syncing extension repos on startup fixes that.
423 dp_misc::syncRepositories(/*force=*/true, silent);
427 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */