Kaydet (Commit) 0a5ca576 authored tarafından Michael Stahl's avatar Michael Stahl Kaydeden (comit) Samuel Mehrbrodt

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: 's avatarSamuel Mehrbrodt <Samuel.Mehrbrodt@cib.de>
üst b95fa852
......@@ -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());
......
......@@ -2656,6 +2656,7 @@ $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/frame,\
XToolbarController \
XToolbarControllerListener \
XTransientDocumentsDocumentContentFactory \
XTransientDocumentsDocumentContentIdentifierFactory \
XUIControllerFactory \
XUIControllerRegistration \
XUntitledNumbers \
......
/* -*- 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: */
......@@ -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 );
......
......@@ -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");
}
......
......@@ -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);
}
......
......@@ -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);
......
......@@ -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 );
......
......@@ -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<
......
......@@ -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);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment