tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / desktop / source / deployment / registry / dp_backend.cxx
blob9ffa9e1607d9f1c7d1e02872674985e2fc15604b
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 <sal/config.h>
22 #include <cassert>
24 #include <dp_backend.h>
25 #include <dp_misc.h>
26 #include <dp_ucb.h>
27 #include <rtl/ustring.hxx>
28 #include <rtl/bootstrap.hxx>
29 #include <sal/log.hxx>
30 #include <cppuhelper/exc_hlp.hxx>
31 #include <comphelper/unwrapargs.hxx>
32 #include <ucbhelper/content.hxx>
33 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
34 #include <com/sun/star/deployment/DeploymentException.hpp>
35 #include <com/sun/star/deployment/ExtensionRemovedException.hpp>
36 #include <com/sun/star/deployment/InvalidRemovedParameterException.hpp>
37 #include <com/sun/star/ucb/ContentCreationException.hpp>
38 #include <com/sun/star/ucb/CommandAbortedException.hpp>
39 #include <com/sun/star/ucb/CommandFailedException.hpp>
40 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
41 #include <com/sun/star/ucb/IOErrorCode.hpp>
42 #include <com/sun/star/beans/StringPair.hpp>
43 #include <com/sun/star/sdbc/XResultSet.hpp>
44 #include <com/sun/star/sdbc/XRow.hpp>
45 #include <comphelper/diagnose_ex.hxx>
46 #include <unotools/tempfile.hxx>
47 #include <optional>
48 #include <utility>
50 using namespace ::dp_misc;
51 using namespace ::com::sun::star;
52 using namespace ::com::sun::star::uno;
53 using namespace ::com::sun::star::ucb;
55 namespace dp_registry::backend {
58 PackageRegistryBackend::~PackageRegistryBackend()
63 void PackageRegistryBackend::disposing( lang::EventObject const & event )
65 Reference<deployment::XPackage> xPackage(
66 event.Source, UNO_QUERY_THROW );
67 OUString url( xPackage->getURL() );
68 ::osl::MutexGuard guard( m_aMutex );
69 if ( m_bound.erase( url ) != 1 )
71 SAL_WARN("desktop.deployment", "erase(" << url << ") != 1");
76 PackageRegistryBackend::PackageRegistryBackend(
77 Sequence<Any> const & args,
78 Reference<XComponentContext> const & xContext )
79 : t_BackendBase( m_aMutex ),
80 m_xComponentContext( xContext ),
81 m_eContext( Context::Unknown )
83 assert(xContext.is());
84 std::optional<OUString> cachePath;
85 std::optional<bool> readOnly;
86 comphelper::unwrapArgs( args, m_context, cachePath, readOnly );
87 if (cachePath)
88 m_cachePath = *cachePath;
90 if ( m_context == "user" )
91 m_eContext = Context::User;
92 else if ( m_context == "shared" )
93 m_eContext = Context::Shared;
94 else if ( m_context == "bundled" )
95 m_eContext = Context::Bundled;
96 else if ( m_context == "tmp" )
97 m_eContext = Context::Tmp;
98 else if (m_context.matchIgnoreAsciiCase("vnd.sun.star.tdoc:/"))
99 m_eContext = Context::Document;
100 else
101 m_eContext = Context::Unknown;
105 void PackageRegistryBackend::check()
107 ::osl::MutexGuard guard( m_aMutex );
108 if (rBHelper.bInDispose || rBHelper.bDisposed) {
109 throw lang::DisposedException(
110 u"PackageRegistryBackend instance has already been disposed!"_ustr,
111 static_cast<OWeakObject *>(this) );
116 void PackageRegistryBackend::disposing()
118 try {
119 for (auto const& elem : m_bound)
120 elem.second->removeEventListener(this);
121 m_bound.clear();
122 m_xComponentContext.clear();
123 WeakComponentImplHelperBase::disposing();
125 catch (const RuntimeException &) {
126 throw;
128 catch (const Exception &) {
129 Any exc( ::cppu::getCaughtException() );
130 throw lang::WrappedTargetRuntimeException(
131 u"caught unexpected exception while disposing!"_ustr,
132 static_cast<OWeakObject *>(this), exc );
136 // XPackageRegistry
138 Reference<deployment::XPackage> PackageRegistryBackend::bindPackage(
139 OUString const & url, OUString const & mediaType, sal_Bool bRemoved,
140 OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv )
142 ::osl::ResettableMutexGuard guard( m_aMutex );
143 check();
145 t_string2ref::const_iterator const iFind( m_bound.find( url ) );
146 if (iFind != m_bound.end())
148 Reference<deployment::XPackage> xPackage( iFind->second );
149 if (xPackage.is())
151 if (!mediaType.isEmpty() &&
152 mediaType != xPackage->getPackageType()->getMediaType())
153 throw lang::IllegalArgumentException
154 (u"XPackageRegistry::bindPackage: media type does not match"_ustr,
155 static_cast<OWeakObject*>(this), 1);
156 if (xPackage->isRemoved() != bRemoved)
157 throw deployment::InvalidRemovedParameterException(
158 u"XPackageRegistry::bindPackage: bRemoved parameter does not match"_ustr,
159 static_cast<OWeakObject*>(this), xPackage->isRemoved(), xPackage);
160 return xPackage;
164 guard.clear();
166 Reference<deployment::XPackage> xNewPackage;
167 try {
168 xNewPackage = bindPackage_( url, mediaType, bRemoved,
169 identifier, xCmdEnv );
171 catch (const RuntimeException &) {
172 throw;
174 catch (const CommandFailedException &) {
175 throw;
177 catch (const deployment::DeploymentException &) {
178 throw;
180 catch (const Exception &) {
181 Any exc( ::cppu::getCaughtException() );
182 throw deployment::DeploymentException(
183 "Error binding package: " + url,
184 static_cast<OWeakObject *>(this), exc );
187 guard.reset();
189 std::pair< t_string2ref::iterator, bool > insertion(
190 m_bound.emplace( url, xNewPackage ) );
191 if (insertion.second)
192 { // first insertion
193 SAL_WARN_IF(
194 Reference<XInterface>(insertion.first->second) != xNewPackage,
195 "desktop.deployment", "mismatch");
197 else
198 { // found existing entry
199 Reference<deployment::XPackage> xPackage( insertion.first->second );
200 if (xPackage.is())
201 return xPackage;
202 insertion.first->second = xNewPackage;
205 guard.clear();
206 xNewPackage->addEventListener( this ); // listen for disposing events
207 return xNewPackage;
210 OUString PackageRegistryBackend::createFolder(
211 Reference<ucb::XCommandEnvironment> const & xCmdEnv)
213 const OUString sDataFolder = makeURL(getCachePath(), OUString());
214 //make sure the folder exist
215 ucbhelper::Content dataContent;
216 ::dp_misc::create_folder(&dataContent, sDataFolder, xCmdEnv);
218 const OUString url = ::utl::CreateTempURL(&sDataFolder, true);
219 return sDataFolder + url.subView(url.lastIndexOf('/'));
222 //folderURL can have the extension .tmp or .tmp_
223 //Before OOo 3.4 the created a tmp file with osl_createTempFile and
224 //then created a Folder with a same name and a trailing '_'
225 //If the folderURL has no '_' then there is no corresponding tmp file.
226 void PackageRegistryBackend::deleteTempFolder(
227 OUString const & folderUrl)
229 if (!folderUrl.isEmpty())
231 erase_path( folderUrl, Reference<XCommandEnvironment>(),
232 false /* no throw: ignore errors */ );
234 if (folderUrl.endsWith("_"))
236 const OUString tempFile = folderUrl.copy(0, folderUrl.getLength() - 1);
237 erase_path( tempFile, Reference<XCommandEnvironment>(),
238 false /* no throw: ignore errors */ );
243 //usedFolders can contain folder names which have the extension .tmp or .tmp_
244 //Before OOo 3.4 we created a tmp file with osl_createTempFile and
245 //then created a Folder with a same name and a trailing '_'
246 //If the folderURL has no '_' then there is no corresponding tmp file.
247 void PackageRegistryBackend::deleteUnusedFolders(
248 std::vector< OUString> const & usedFolders)
252 const OUString sDataFolder = makeURL(getCachePath(), OUString());
253 ::ucbhelper::Content tempFolder(
254 sDataFolder, Reference<ucb::XCommandEnvironment>(), m_xComponentContext);
256 Reference<sdbc::XResultSet> xResultSet(
257 StrTitle::createCursor( tempFolder, ::ucbhelper::INCLUDE_FOLDERS_ONLY ) );
259 // get all temp directories:
260 std::vector<OUString> tempEntries;
262 while (xResultSet->next())
264 OUString title(
265 Reference<sdbc::XRow>(
266 xResultSet, UNO_QUERY_THROW )->getString(
267 1 /* Title */ ) );
269 if (title.endsWith(".tmp"))
270 tempEntries.push_back(
271 makeURLAppendSysPathSegment(sDataFolder, title));
274 for (const OUString & tempEntrie : tempEntries)
276 if (std::find( usedFolders.begin(), usedFolders.end(), tempEntrie ) ==
277 usedFolders.end())
279 deleteTempFolder(tempEntrie);
283 catch (const ucb::InteractiveAugmentedIOException& e)
285 //In case the folder containing all the data folder does not
286 //exist yet, we ignore the exception
287 if (e.Code != ucb::IOErrorCode_NOT_EXISTING)
288 throw;
294 Package::~Package()
299 Package::Package( ::rtl::Reference<PackageRegistryBackend> myBackend,
300 OUString url,
301 OUString aName,
302 OUString displayName,
303 Reference<deployment::XPackageTypeInfo> const & xPackageType,
304 bool bRemoved,
305 OUString identifier)
306 : t_PackageBase( m_aMutex ),
307 m_myBackend(std::move( myBackend )),
308 m_url(std::move( url )),
309 m_name(std::move( aName )),
310 m_displayName(std::move( displayName )),
311 m_xPackageType( xPackageType ),
312 m_bRemoved(bRemoved),
313 m_identifier(std::move(identifier))
315 if (m_bRemoved)
317 //We use the last segment of the URL
318 SAL_WARN_IF(
319 !m_name.isEmpty(), "desktop.deployment", "non-empty m_name");
320 OUString name = m_url;
321 rtl::Bootstrap::expandMacros(name);
322 sal_Int32 index = name.lastIndexOf('/');
323 if (index != -1 && index < name.getLength())
324 m_name = name.copy(index + 1);
329 void Package::disposing()
331 m_myBackend.clear();
332 WeakComponentImplHelperBase::disposing();
336 void Package::check() const
338 ::osl::MutexGuard guard( m_aMutex );
339 if (rBHelper.bInDispose || rBHelper.bDisposed) {
340 throw lang::DisposedException(
341 u"Package instance has already been disposed!"_ustr,
342 static_cast<OWeakObject *>(const_cast<Package *>(this)));
346 // XComponent
348 void Package::dispose()
350 //Do not call check here. We must not throw an exception here if the object
351 //is being disposed or is already disposed. See com.sun.star.lang.XComponent
352 WeakComponentImplHelperBase::dispose();
356 void Package::addEventListener(
357 Reference<lang::XEventListener> const & xListener )
359 //Do not call check here. We must not throw an exception here if the object
360 //is being disposed or is already disposed. See com.sun.star.lang.XComponent
361 WeakComponentImplHelperBase::addEventListener( xListener );
365 void Package::removeEventListener(
366 Reference<lang::XEventListener> const & xListener )
368 //Do not call check here. We must not throw an exception here if the object
369 //is being disposed or is already disposed. See com.sun.star.lang.XComponent
370 WeakComponentImplHelperBase::removeEventListener( xListener );
373 // XModifyBroadcaster
375 void Package::addModifyListener(
376 Reference<util::XModifyListener> const & xListener )
378 check();
379 rBHelper.addListener( cppu::UnoType<decltype(xListener)>::get(), xListener );
383 void Package::removeModifyListener(
384 Reference<util::XModifyListener> const & xListener )
386 check();
387 rBHelper.removeListener( cppu::UnoType<decltype(xListener)>::get(), xListener );
391 void Package::checkAborted(
392 ::rtl::Reference<AbortChannel> const & abortChannel )
394 if (abortChannel.is() && abortChannel->isAborted()) {
395 throw CommandAbortedException(
396 u"abort!"_ustr, static_cast<OWeakObject *>(this) );
400 // XPackage
402 Reference<task::XAbortChannel> Package::createAbortChannel()
404 check();
405 return new AbortChannel;
409 sal_Bool Package::isBundle()
411 return false; // default
415 ::sal_Int32 Package::checkPrerequisites(
416 const css::uno::Reference< css::task::XAbortChannel >&,
417 const css::uno::Reference< css::ucb::XCommandEnvironment >&,
418 sal_Bool)
420 if (m_bRemoved)
421 throw deployment::ExtensionRemovedException();
422 return 0;
426 sal_Bool Package::checkDependencies(
427 const css::uno::Reference< css::ucb::XCommandEnvironment >& )
429 if (m_bRemoved)
430 throw deployment::ExtensionRemovedException();
431 return true;
435 Sequence< Reference<deployment::XPackage> > Package::getBundle(
436 Reference<task::XAbortChannel> const &,
437 Reference<XCommandEnvironment> const & )
439 return Sequence< Reference<deployment::XPackage> >();
443 OUString Package::getName()
445 return m_name;
448 beans::Optional<OUString> Package::getIdentifier()
450 if (m_bRemoved)
451 return beans::Optional<OUString>(true, m_identifier);
453 return beans::Optional<OUString>();
457 OUString Package::getVersion()
459 if (m_bRemoved)
460 throw deployment::ExtensionRemovedException();
461 return OUString();
465 OUString Package::getURL()
467 return m_url;
471 OUString Package::getDisplayName()
473 if (m_bRemoved)
474 throw deployment::ExtensionRemovedException();
475 return m_displayName;
479 OUString Package::getDescription()
481 if (m_bRemoved)
482 throw deployment::ExtensionRemovedException();
483 return OUString();
487 OUString Package::getLicenseText()
489 if (m_bRemoved)
490 throw deployment::ExtensionRemovedException();
491 return OUString();
495 Sequence<OUString> Package::getUpdateInformationURLs()
497 if (m_bRemoved)
498 throw deployment::ExtensionRemovedException();
499 return Sequence<OUString>();
503 css::beans::StringPair Package::getPublisherInfo()
505 if (m_bRemoved)
506 throw deployment::ExtensionRemovedException();
507 css::beans::StringPair aEmptyPair;
508 return aEmptyPair;
512 uno::Reference< css::graphic::XGraphic > Package::getIcon( sal_Bool /*bHighContrast*/ )
514 if (m_bRemoved)
515 throw deployment::ExtensionRemovedException();
517 uno::Reference< css::graphic::XGraphic > aEmpty;
518 return aEmpty;
522 Reference<deployment::XPackageTypeInfo> Package::getPackageType()
524 return m_xPackageType;
527 void Package::exportTo(
528 OUString const & destFolderURL, OUString const & newTitle,
529 sal_Int32 nameClashAction, Reference<XCommandEnvironment> const & xCmdEnv )
531 if (m_bRemoved)
532 throw deployment::ExtensionRemovedException();
534 ::ucbhelper::Content destFolder( destFolderURL, xCmdEnv, getMyBackend()->getComponentContext() );
535 ::ucbhelper::Content sourceContent( getURL(), xCmdEnv, getMyBackend()->getComponentContext() );
536 bool bOk=true;
539 destFolder.transferContent(
540 sourceContent, ::ucbhelper::InsertOperation::Copy,
541 newTitle, nameClashAction);
543 catch (const css::ucb::ContentCreationException&)
545 bOk = false;
548 if (!bOk)
549 throw RuntimeException( u"UCB transferContent() failed!"_ustr, nullptr );
552 void Package::fireModified()
554 ::cppu::OInterfaceContainerHelper * container = rBHelper.getContainer(
555 cppu::UnoType<util::XModifyListener>::get() );
556 if (container == nullptr)
557 return;
559 const Sequence< Reference<XInterface> > elements(
560 container->getElements() );
561 lang::EventObject evt( static_cast<OWeakObject *>(this) );
562 for ( const Reference<XInterface>& x : elements )
564 Reference<util::XModifyListener> xListener( x, UNO_QUERY );
565 if (xListener.is())
566 xListener->modified( evt );
570 // XPackage
572 beans::Optional< beans::Ambiguous<sal_Bool> > Package::isRegistered(
573 Reference<task::XAbortChannel> const & xAbortChannel,
574 Reference<XCommandEnvironment> const & xCmdEnv )
576 try {
577 ::osl::ResettableMutexGuard guard( m_aMutex );
578 return isRegistered_( guard,
579 AbortChannel::get(xAbortChannel),
580 xCmdEnv );
582 catch (const RuntimeException &) {
583 throw;
585 catch (const CommandFailedException &) {
586 throw;
588 catch (const CommandAbortedException &) {
589 throw;
591 catch (const deployment::DeploymentException &) {
592 throw;
594 catch (const Exception & e) {
595 Any exc( ::cppu::getCaughtException() );
596 throw deployment::DeploymentException(
597 "unexpected " + exc.getValueTypeName() + ": " + e.Message,
598 static_cast<OWeakObject *>(this), exc );
603 void Package::processPackage_impl(
604 bool doRegisterPackage,
605 bool startup,
606 Reference<task::XAbortChannel> const & xAbortChannel,
607 Reference<XCommandEnvironment> const & xCmdEnv )
609 check();
610 bool action = false;
612 try {
613 try {
614 ::osl::ResettableMutexGuard guard( m_aMutex );
615 beans::Optional< beans::Ambiguous<sal_Bool> > option(
616 isRegistered_( guard, AbortChannel::get(xAbortChannel),
617 xCmdEnv ) );
618 action = (option.IsPresent &&
619 (option.Value.IsAmbiguous ||
620 (doRegisterPackage ? !option.Value.Value
621 : option.Value.Value)));
622 if (action) {
624 OUString displayName = isRemoved() ? getName() : getDisplayName();
625 ProgressLevel progress(
626 xCmdEnv,
627 (doRegisterPackage
628 ? PackageRegistryBackend::StrRegisteringPackage()
629 : PackageRegistryBackend::StrRevokingPackage())
630 + displayName );
631 processPackage_( guard,
632 doRegisterPackage,
633 startup,
634 AbortChannel::get(xAbortChannel),
635 xCmdEnv );
638 catch (lang::IllegalArgumentException &) {
639 Any e(cppu::getCaughtException());
640 throw deployment::DeploymentException(
641 ((doRegisterPackage
642 ? DpResId(RID_STR_ERROR_WHILE_REGISTERING)
643 : DpResId(RID_STR_ERROR_WHILE_REVOKING))
644 + getDisplayName()),
645 static_cast< OWeakObject * >(this), e);
647 catch (const RuntimeException &) {
648 TOOLS_WARN_EXCEPTION("desktop.deployment", "unexpected");
649 throw;
651 catch (const CommandFailedException &) {
652 throw;
654 catch (const CommandAbortedException &) {
655 throw;
657 catch (const deployment::DeploymentException &) {
658 throw;
660 catch (const Exception & e) {
661 Any exc( ::cppu::getCaughtException() );
662 throw deployment::DeploymentException(
663 (doRegisterPackage
664 ? DpResId(RID_STR_ERROR_WHILE_REGISTERING)
665 : DpResId(RID_STR_ERROR_WHILE_REVOKING))
666 + getDisplayName() + ": " + exc.getValueTypeName() + " \"" + e.Message
667 + "\"",
668 static_cast<OWeakObject *>(this), exc );
671 catch (...) {
672 if (action)
673 fireModified();
674 throw;
676 if (action)
677 fireModified();
681 void Package::registerPackage(
682 sal_Bool startup,
683 Reference<task::XAbortChannel> const & xAbortChannel,
684 Reference<XCommandEnvironment> const & xCmdEnv )
686 if (m_bRemoved)
687 throw deployment::ExtensionRemovedException();
688 processPackage_impl( true /* register */, startup, xAbortChannel, xCmdEnv );
692 void Package::revokePackage(
693 sal_Bool startup,
694 Reference<task::XAbortChannel> const & xAbortChannel,
695 Reference<XCommandEnvironment> const & xCmdEnv )
697 processPackage_impl( false /* revoke */, startup, xAbortChannel, xCmdEnv );
701 PackageRegistryBackend * Package::getMyBackend() const
703 PackageRegistryBackend * pBackend = m_myBackend.get();
704 if (nullptr == pBackend)
706 //May throw a DisposedException
707 check();
708 //We should never get here...
709 throw RuntimeException(
710 u"Failed to get the BackendImpl"_ustr,
711 static_cast<OWeakObject*>(const_cast<Package *>(this)));
713 return pBackend;
716 OUString Package::getRepositoryName()
718 PackageRegistryBackend * backEnd = getMyBackend();
719 return backEnd->getContext();
722 beans::Optional< OUString > Package::getRegistrationDataURL()
724 if (m_bRemoved)
725 throw deployment::ExtensionRemovedException();
726 return beans::Optional<OUString>();
729 sal_Bool Package::isRemoved()
731 return m_bRemoved;
734 Package::TypeInfo::~TypeInfo()
738 // XPackageTypeInfo
740 OUString Package::TypeInfo::getMediaType()
742 return m_mediaType;
746 OUString Package::TypeInfo::getDescription()
748 return getShortDescription();
752 OUString Package::TypeInfo::getShortDescription()
754 return m_shortDescr;
757 OUString Package::TypeInfo::getFileFilter()
759 return m_fileFilter;
762 Any Package::TypeInfo::getIcon( sal_Bool /*highContrast*/, sal_Bool /*smallIcon*/ )
764 return Any();
769 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */