diff options
author | Michael Stahl <Michael.Stahl@cib.de> | 2019-02-15 17:50:38 +0100 |
---|---|---|
committer | Thorsten Behrens <Thorsten.Behrens@CIB.de> | 2019-08-13 11:06:55 +0200 |
commit | de6355afa4bf89199c7281ddb43a141e192d43d6 (patch) | |
tree | 7c349d3e4249c8fa82e4d7b1374f1403507dc221 | |
parent | 44a40b38d881fd2b9cfbedfc630290d1927fd72f (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>
(cherry picked from commit 0a5ca5768f56db481dd3b947b3dddaab7ed96450)
Reviewed-on: https://gerrit.libreoffice.org/69101
Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
(cherry picked from commit 98b99ef61c6d725962cdbaa05ff90c9d1aa72d57)
Reviewed-on: https://gerrit.libreoffice.org/75963
Reviewed-by: Michael Stahl <Michael.Stahl@cib.de>
Tested-by: Thorsten Behrens <Thorsten.Behrens@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 93a76c5908a2..f95f390777d2 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 2217a4a07838..ce5d7f360b55 100644 --- a/sc/source/filter/xml/xmlwrap.cxx +++ b/sc/source/filter/xml/xmlwrap.cxx @@ -37,6 +37,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 ff6ad06ea6a7..9e8c2a2bf601 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> @@ -114,16 +115,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) @@ -1234,11 +1263,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 bcc16adc2d98..5df28f764002 100644 --- a/sw/source/filter/ww8/ww8par.cxx +++ b/sw/source/filter/ww8/ww8par.cxx @@ -4925,10 +4925,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 cdeee03a3a96..faf4f4b4be91 100644 --- a/sw/source/filter/xml/swxml.cxx +++ b/sw/source/filter/xml/swxml.cxx @@ -791,8 +791,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 58f2652a4dc0..08590131231a 100644 --- a/ucb/source/ucp/tdoc/tdoc_provider.cxx +++ b/ucb/source/ucp/tdoc/tdoc_provider.cxx @@ -85,6 +85,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 ); @@ -93,10 +94,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 ); @@ -161,13 +163,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() ) @@ -178,7 +178,7 @@ ContentProvider::createDocumentContent( 1 ); } - OUString aDocId = tdoc_ucp::OfficeDocumentsManager::queryDocumentId( Model ); + OUString aDocId = tdoc_ucp::OfficeDocumentsManager::queryDocumentId(xModel); if ( aDocId.isEmpty() ) { throw lang::IllegalArgumentException( @@ -193,6 +193,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 3501bd4d8ec9..f8c2fb701e83 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 <ucbhelper/providerhelper.hxx> #include "tdoc_uri.hxx" @@ -51,9 +52,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 ); @@ -86,6 +88,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 b14db3d28767..7c53493e6f66 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -126,7 +126,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); } |