diff options
author | Michael Stahl <Michael.Stahl@cib.de> | 2019-02-15 17:50:38 +0100 |
---|---|---|
committer | Samuel Mehrbrodt <Samuel.Mehrbrodt@cib.de> | 2019-02-20 07:54:42 +0100 |
commit | 0a5ca5768f56db481dd3b947b3dddaab7ed96450 (patch) | |
tree | 59eb8e570e98485aaf0d3587a1876f0fe9add6e9 | |
parent | b95fa8525d42574ecce2c04f92b602c022adbd92 (diff) |
tdf#123293 sfx2: fix metadata loss when loading from stream
The problem is that when loading from a stream, there is no BaseURL and
also no storage for the document.
Due to the lack of BaseURL, the sfx2::createBaseURI() throws and loading
RDF metadata fails, which also pops up an annoying warning dialog.
Try to handle this in a similar way than a newly created document (see
GetDMA()), by using the vnd.sun.star.tdoc scheme URL for the document;
this however currently requires that the document has a XStorage, which
is also not the case here.
So add another UNO method to tdoc UCP's tdoc_ucp::ContentProvider,
to split out the creation of the tdoc schema URL from the creation of
the ucb Content, to get rid of the XStorage requirement.
Change-Id: Ica62743f9d21db0b1464b70db1a62ebc61989ef8
Reviewed-on: https://gerrit.libreoffice.org/67882
Tested-by: Jenkins
Reviewed-by: Samuel Mehrbrodt <Samuel.Mehrbrodt@cib.de>
-rw-r--r-- | include/sfx2/DocumentMetadataAccess.hxx | 9 | ||||
-rw-r--r-- | offapi/UnoApi_offapi.mk | 1 | ||||
-rw-r--r-- | offapi/com/sun/star/frame/XTransientDocumentsDocumentContentIdentifierFactory.idl | 59 | ||||
-rw-r--r-- | sc/source/filter/xml/xmlwrap.cxx | 4 | ||||
-rw-r--r-- | sfx2/source/doc/DocumentMetadataAccess.cxx | 39 | ||||
-rw-r--r-- | sw/source/filter/ww8/ww8par.cxx | 5 | ||||
-rw-r--r-- | sw/source/filter/xml/swxml.cxx | 4 | ||||
-rw-r--r-- | ucb/source/ucp/tdoc/tdoc_provider.cxx | 27 | ||||
-rw-r--r-- | ucb/source/ucp/tdoc/tdoc_provider.hxx | 13 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper.cxx | 4 |
10 files changed, 141 insertions, 24 deletions
diff --git a/include/sfx2/DocumentMetadataAccess.hxx b/include/sfx2/DocumentMetadataAccess.hxx index 31a61adebb01..cf5a2ddbcbac 100644 --- a/include/sfx2/DocumentMetadataAccess.hxx +++ b/include/sfx2/DocumentMetadataAccess.hxx @@ -44,6 +44,9 @@ namespace com { namespace sun { namespace star { namespace embed { class XStorage; } } } } +namespace com { namespace sun { namespace star { namespace frame { + class XModel; +} } } } class SfxObjectShell; namespace sfx2 { @@ -52,7 +55,7 @@ namespace sfx2 { /** create a base URI for loading metadata from an ODF (sub)document. @param i_xContext component context - @param i_xStorage storage for the document; FileSystemStorage is allowed + @param i_xModel model of the document (required if no URI is provided) @param i_rPkgURI the URI for the package @param i_rSubDocument (optional) path of the subdocument in package @@ -60,8 +63,8 @@ namespace sfx2 { */ css::uno::Reference< css::rdf::XURI> SFX2_DLLPUBLIC createBaseURI( - css::uno::Reference< css::uno::XComponentContext> const & i_xContext, - css::uno::Reference< css::embed::XStorage> const & i_xStorage, + css::uno::Reference<css::uno::XComponentContext> const & i_xContext, + css::uno::Reference<css::frame::XModel> const & i_xModel, OUString const & i_rPkgURI, OUString const & i_rSubDocument = OUString()); diff --git a/offapi/UnoApi_offapi.mk b/offapi/UnoApi_offapi.mk index f120c550e8e2..a1ffab05d2e8 100644 --- a/offapi/UnoApi_offapi.mk +++ b/offapi/UnoApi_offapi.mk @@ -2656,6 +2656,7 @@ $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/frame,\ XToolbarController \ XToolbarControllerListener \ XTransientDocumentsDocumentContentFactory \ + XTransientDocumentsDocumentContentIdentifierFactory \ XUIControllerFactory \ XUIControllerRegistration \ XUntitledNumbers \ diff --git a/offapi/com/sun/star/frame/XTransientDocumentsDocumentContentIdentifierFactory.idl b/offapi/com/sun/star/frame/XTransientDocumentsDocumentContentIdentifierFactory.idl new file mode 100644 index 000000000000..26359db3eec5 --- /dev/null +++ b/offapi/com/sun/star/frame/XTransientDocumentsDocumentContentIdentifierFactory.idl @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ +#ifndef __com_sun_star_frame_XTransientDocumentsDocumentContentIdentifierFactory_idl__ +#define __com_sun_star_frame_XTransientDocumentsDocumentContentIdentifierFactory_idl__ + +#include <com/sun/star/uno/XInterface.idl> +#include <com/sun/star/ucb/XContentIdentifier.idl> +#include <com/sun/star/frame/XModel.idl> +#include <com/sun/star/lang/IllegalArgumentException.idl> + + +module com { module sun { module star { module frame { + +/** a factory for identifiers of + com::sun::star::ucb::TransientDocumentsDocumentContents. + + @see com::sun::star::document::OfficeDocument + @see com::sun::star::ucb::XContentIdentifier + + @since LibreOffice 6.3 +*/ +interface XTransientDocumentsDocumentContentIdentifierFactory + : com::sun::star::uno::XInterface +{ + /** creates a com::sun::star::ucb::XContentIdentifier + based on a given com::sun::star::document::OfficeDocument. + + @param Model + the document model for which a + com::sun::star::ucb::XContentIdentifier + is requested. The model must be an implementation of service + com::sun::star::document::OfficeDocument. + + @returns + a content identifier based on the given document model. + + @throws com::sun::star::lang::IllegalArgumentException + if the document model cannot be associated with content for any reason. + */ + com::sun::star::ucb::XContentIdentifier + createDocumentContentIdentifier( + [in] com::sun::star::frame::XModel Model ) + raises ( com::sun::star::lang::IllegalArgumentException ); + +}; + + +}; }; }; }; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/xml/xmlwrap.cxx b/sc/source/filter/xml/xmlwrap.cxx index 45a38a6b1581..a377239ccd11 100644 --- a/sc/source/filter/xml/xmlwrap.cxx +++ b/sc/source/filter/xml/xmlwrap.cxx @@ -35,6 +35,7 @@ #include <sfx2/sfxsids.hrc> #include <com/sun/star/container/XChild.hpp> #include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/frame/XTransientDocumentsDocumentContentFactory.hpp> #include <com/sun/star/xml/sax/InputSource.hpp> #include <com/sun/star/xml/sax/Parser.hpp> #include <com/sun/star/xml/sax/XFastParser.hpp> @@ -74,6 +75,7 @@ #include <unonames.hxx> using namespace com::sun::star; +using namespace css::uno; ScXMLImportWrapper::ScXMLImportWrapper( ScDocShell& rDocSh, SfxMedium* pM, const uno::Reference < embed::XStorage >& xStor ) : mrDocShell(rDocSh), @@ -393,7 +395,7 @@ bool ScXMLImportWrapper::Import( ImportFlags nMode, ErrCode& rError ) const uno::Reference< rdf::XDocumentMetadataAccess > xDMA( xModel, uno::UNO_QUERY_THROW ); const uno::Reference< rdf::XURI > xBaseURI( - ::sfx2::createBaseURI( xContext, xStorage, aBaseURL, aName ) ); + ::sfx2::createBaseURI( xContext, xModel, aBaseURL, aName ) ); uno::Reference<task::XInteractionHandler> xHandler = mrDocShell.GetMedium()->GetInteractionHandler(); xDMA->loadMetadataFromStorage( xStorage, xBaseURI, xHandler ); diff --git a/sfx2/source/doc/DocumentMetadataAccess.cxx b/sfx2/source/doc/DocumentMetadataAccess.cxx index 51f50406b124..d26a2cd384b0 100644 --- a/sfx2/source/doc/DocumentMetadataAccess.cxx +++ b/sfx2/source/doc/DocumentMetadataAccess.cxx @@ -25,6 +25,7 @@ #include <com/sun/star/embed/ElementModes.hpp> #include <com/sun/star/embed/XStorage.hpp> #include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/frame/XTransientDocumentsDocumentContentIdentifierFactory.hpp> #include <com/sun/star/task/ErrorCodeIOException.hpp> #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> #include <com/sun/star/rdf/FileFormat.hpp> @@ -116,16 +117,44 @@ static bool isReservedFile(OUString const & i_rPath) uno::Reference<rdf::XURI> createBaseURI( uno::Reference<uno::XComponentContext> const & i_xContext, - uno::Reference<embed::XStorage> const & i_xStorage, + uno::Reference<frame::XModel> const & i_xModel, OUString const & i_rPkgURI, OUString const & i_rSubDocument) { - if (!i_xContext.is() || !i_xStorage.is() || i_rPkgURI.isEmpty()) { + if (!i_xContext.is() || (!i_xModel.is() && i_rPkgURI.isEmpty())) { throw uno::RuntimeException(); } + OUString pkgURI(i_rPkgURI); + + // tdf#123293 chicken/egg problem when loading from stream: there is no URI, + // and also the model doesn't have a storage yet, so we need to get the + // tdoc URI without a storage... + if (pkgURI.isEmpty()) + { + assert(i_xModel.is()); + uno::Reference<frame::XTransientDocumentsDocumentContentIdentifierFactory> + const xTDDCIF( + i_xContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.ucb.TransientDocumentsContentProvider", + i_xContext), + uno::UNO_QUERY_THROW); + uno::Reference<ucb::XContentIdentifier> const xContentId( + xTDDCIF->createDocumentContentIdentifier(i_xModel)); + SAL_WARN_IF(!xContentId.is(), "sfx", "createBaseURI: cannot create ContentIdentifier"); + if (!xContentId.is()) + { + throw uno::RuntimeException("createBaseURI: cannot create ContentIdentifier"); + } + pkgURI = xContentId->getContentIdentifier(); + assert(!pkgURI.isEmpty()); + if (!pkgURI.isEmpty() && !pkgURI.endsWith("/")) + { + pkgURI = pkgURI + "/"; + } + } + // #i108078# workaround non-hierarchical vnd.sun.star.expand URIs // this really should be done somewhere else, not here. - OUString pkgURI(i_rPkgURI); if (pkgURI.matchIgnoreAsciiCase("vnd.sun.star.expand:")) { // expand it here (makeAbsolute requires hierarchical URI) @@ -1283,11 +1312,11 @@ DocumentMetadataAccess::loadMetadataFromMedium( } uno::Reference<rdf::XURI> xBaseURI; try { - xBaseURI = createBaseURI(m_pImpl->m_xContext, xStorage, BaseURL); + xBaseURI = createBaseURI(m_pImpl->m_xContext, nullptr, BaseURL); } catch (const uno::Exception &) { // fall back to URL try { - xBaseURI = createBaseURI(m_pImpl->m_xContext, xStorage, URL); + xBaseURI = createBaseURI(m_pImpl->m_xContext, nullptr, URL); } catch (const uno::Exception &) { OSL_FAIL("cannot create base URI"); } diff --git a/sw/source/filter/ww8/ww8par.cxx b/sw/source/filter/ww8/ww8par.cxx index eb685c83edd0..4db2aaf145ff 100644 --- a/sw/source/filter/ww8/ww8par.cxx +++ b/sw/source/filter/ww8/ww8par.cxx @@ -4921,10 +4921,11 @@ ErrCode SwWW8ImplReader::CoreLoad(WW8Glossary const *pGloss) // Initialize RDF metadata, to be able to add statements during the import. try { - uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(m_rDoc.GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW); + uno::Reference<frame::XModel> const xModel(m_rDoc.GetDocShell()->GetBaseModel()); + uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY_THROW); uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext()); uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetTemporaryStorage(); - const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xComponentContext, xStorage, m_sBaseURL)); + const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xComponentContext, xModel, m_sBaseURL)); uno::Reference<task::XInteractionHandler> xHandler; xDocumentMetadataAccess->loadMetadataFromStorage(xStorage, xBaseURI, xHandler); } diff --git a/sw/source/filter/xml/swxml.cxx b/sw/source/filter/xml/swxml.cxx index 01fe0ef9eefa..0aec06ae11d0 100644 --- a/sw/source/filter/xml/swxml.cxx +++ b/sw/source/filter/xml/swxml.cxx @@ -796,8 +796,10 @@ ErrCode XMLReader::Read( SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPaM, con { const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(xModelComp, uno::UNO_QUERY_THROW); + const uno::Reference<frame::XModel> xModel(xModelComp, + uno::UNO_QUERY_THROW); const uno::Reference<rdf::XURI> xBaseURI( ::sfx2::createBaseURI( - xContext, xStorage, rBaseURL, StreamPath) ); + xContext, xModel, rBaseURL, StreamPath) ); const uno::Reference<task::XInteractionHandler> xHandler( pDocSh->GetMedium()->GetInteractionHandler() ); xDMA->loadMetadataFromStorage(xStorage, xBaseURI, xHandler); diff --git a/ucb/source/ucp/tdoc/tdoc_provider.cxx b/ucb/source/ucp/tdoc/tdoc_provider.cxx index fef2f3145f5e..fdcfd241502c 100644 --- a/ucb/source/ucp/tdoc/tdoc_provider.cxx +++ b/ucb/source/ucp/tdoc/tdoc_provider.cxx @@ -88,6 +88,7 @@ css::uno::Any SAL_CALL ContentProvider::queryInterface( const css::uno::Type & r static_cast< lang::XTypeProvider* >(this), static_cast< lang::XServiceInfo* >(this), static_cast< ucb::XContentProvider* >(this), + static_cast< frame::XTransientDocumentsDocumentContentIdentifierFactory* >(this), static_cast< frame::XTransientDocumentsDocumentContentFactory* >(this) ); return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); @@ -96,10 +97,11 @@ css::uno::Any SAL_CALL ContentProvider::queryInterface( const css::uno::Type & r // XTypeProvider methods. -XTYPEPROVIDER_IMPL_4( ContentProvider, +XTYPEPROVIDER_IMPL_5( ContentProvider, lang::XTypeProvider, lang::XServiceInfo, ucb::XContentProvider, + frame::XTransientDocumentsDocumentContentIdentifierFactory, frame::XTransientDocumentsDocumentContentFactory ); @@ -164,13 +166,11 @@ ContentProvider::queryContent( } -// XTransientDocumentsDocumentContentFactory methods. - +// XTransientDocumentsDocumentContentIdentifierFactory methods. -// virtual -uno::Reference< ucb::XContent > SAL_CALL -ContentProvider::createDocumentContent( - const uno::Reference< frame::XModel >& Model ) +uno::Reference<ucb::XContentIdentifier> SAL_CALL +ContentProvider::createDocumentContentIdentifier( + uno::Reference<frame::XModel> const& xModel) { // model -> id -> content identifier -> queryContent if ( !m_xDocsMgr.is() ) @@ -181,7 +181,7 @@ ContentProvider::createDocumentContent( 1 ); } - OUString aDocId = tdoc_ucp::OfficeDocumentsManager::queryDocumentId( Model ); + OUString aDocId = tdoc_ucp::OfficeDocumentsManager::queryDocumentId(xModel); if ( aDocId.isEmpty() ) { throw lang::IllegalArgumentException( @@ -196,6 +196,17 @@ ContentProvider::createDocumentContent( uno::Reference< ucb::XContentIdentifier > xId = new ::ucbhelper::ContentIdentifier( aBuffer.makeStringAndClear() ); + return xId; +} + +// XTransientDocumentsDocumentContentFactory methods. + +uno::Reference< ucb::XContent > SAL_CALL +ContentProvider::createDocumentContent( + uno::Reference<frame::XModel> const& xModel) +{ + uno::Reference<ucb::XContentIdentifier> const xId( + createDocumentContentIdentifier(xModel)); osl::MutexGuard aGuard( m_aMutex ); diff --git a/ucb/source/ucp/tdoc/tdoc_provider.hxx b/ucb/source/ucp/tdoc/tdoc_provider.hxx index 2f308bf3ff5c..f1dc515b1b84 100644 --- a/ucb/source/ucp/tdoc/tdoc_provider.hxx +++ b/ucb/source/ucp/tdoc/tdoc_provider.hxx @@ -22,6 +22,7 @@ #include <rtl/ref.hxx> #include <com/sun/star/frame/XTransientDocumentsDocumentContentFactory.hpp> +#include <com/sun/star/frame/XTransientDocumentsDocumentContentIdentifierFactory.hpp> #include <com/sun/star/packages/WrongPasswordException.hpp> #include <com/sun/star/lang/XSingleServiceFactory.hpp> #include <com/sun/star/lang/XMultiServiceFactory.hpp> @@ -53,9 +54,10 @@ namespace tdoc_ucp { class StorageElementFactory; -class ContentProvider : - public ::ucbhelper::ContentProviderImplHelper, - public css::frame::XTransientDocumentsDocumentContentFactory +class ContentProvider + : public ::ucbhelper::ContentProviderImplHelper + , public css::frame::XTransientDocumentsDocumentContentIdentifierFactory + , public css::frame::XTransientDocumentsDocumentContentFactory { public: explicit ContentProvider( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); @@ -88,6 +90,11 @@ public: virtual css::uno::Reference< css::ucb::XContent > SAL_CALL queryContent( const css::uno::Reference< css::ucb::XContentIdentifier >& Identifier ) override; + // XTransientDocumentsDocumentContentIdentifierFactory + virtual css::uno::Reference<css::ucb::XContentIdentifier> SAL_CALL + createDocumentContentIdentifier( + css::uno::Reference<css::frame::XModel> const& xModel) override; + // XTransientDocumentsDocumentContentFactory virtual css::uno::Reference< css::ucb::XContent > SAL_CALL createDocumentContent( const css::uno::Reference< diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index a8d861e271ac..020861e663d6 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -128,7 +128,9 @@ DomainMapper::DomainMapper( const uno::Reference< uno::XComponentContext >& xCon uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY_THROW); uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetTemporaryStorage(); OUString aBaseURL = rMediaDesc.getUnpackedValueOrDefault("URL", OUString()); - const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xContext, xStorage, aBaseURL, OUString())); + const uno::Reference<frame::XModel> xModel_(xModel, + uno::UNO_QUERY_THROW); + const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xContext, xModel_, aBaseURL, OUString())); const uno::Reference<task::XInteractionHandler> xHandler; xDocumentMetadataAccess->loadMetadataFromStorage(xStorage, xBaseURI, xHandler); } |