tdf#118634: Don't save embedded data source to a temporary preview document

Also don't use storeAsURL to store embedded datasource when the document
is being saved using storeToURL.

Change-Id: I69a7ee5ae066e591be5e45c87bcf57dff370decc
Reviewed-on: https://gerrit.libreoffice.org/57178
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
This commit is contained in:
Mike Kaganski
2018-07-09 19:49:34 +10:00
parent d7cdb7fcc4
commit edc62adae9
11 changed files with 98 additions and 24 deletions

View File

@@ -1029,15 +1029,8 @@ void ODatabaseDocument::impl_storeAs_throw( const OUString& _rURL, const ::comph
if ( bLocationChanged )
{
// create storage for target URL
uno::Reference<embed::XStorage> xTargetStorage;
_rArguments.get("TargetStorage") >>= xTargetStorage;
if (!xTargetStorage.is())
xTargetStorage = impl_createStorageFor_throw(_rURL);
// In case we got a StreamRelPath, then xTargetStorage should reference that sub-storage.
OUString sStreamRelPath = _rArguments.getOrDefault("StreamRelPath", OUString());
if (!sStreamRelPath.isEmpty())
xTargetStorage = xTargetStorage->openStorageElement(sStreamRelPath, embed::ElementModes::READWRITE);
uno::Reference<embed::XStorage> xTargetStorage(
impl_GetStorageOrCreateFor_throw(_rArguments, _rURL));
if ( m_pImpl->isEmbeddedDatabase() )
m_pImpl->clearConnections();
@@ -1130,6 +1123,24 @@ Reference< XStorage > ODatabaseDocument::impl_createStorageFor_throw( const OUSt
return Reference< XStorage >( xStorageFactory->createInstanceWithArguments( aParam ), UNO_QUERY_THROW );
}
css::uno::Reference<css::embed::XStorage> ODatabaseDocument::impl_GetStorageOrCreateFor_throw(
const ::comphelper::NamedValueCollection& _rArguments, const OUString& _rURL) const
{
// Try to get the storage from arguments, then create storage for target URL
uno::Reference<embed::XStorage> xTargetStorage;
_rArguments.get("TargetStorage") >>= xTargetStorage;
if (!xTargetStorage.is())
xTargetStorage = impl_createStorageFor_throw(_rURL);
// In case we got a StreamRelPath, then xTargetStorage should reference that sub-storage.
OUString sStreamRelPath = _rArguments.getOrDefault("StreamRelPath", OUString());
if (!sStreamRelPath.isEmpty())
xTargetStorage
= xTargetStorage->openStorageElement(sStreamRelPath, embed::ElementModes::READWRITE);
return xTargetStorage;
}
void SAL_CALL ODatabaseDocument::storeAsURL( const OUString& _rURL, const Sequence< PropertyValue >& _rArguments )
{
// SYNCHRONIZED ->
@@ -1232,11 +1243,12 @@ void SAL_CALL ODatabaseDocument::storeToURL( const OUString& _rURL, const Sequen
try
{
const ::comphelper::NamedValueCollection aArguments(_rArguments);
// create storage for target URL
Reference< XStorage > xTargetStorage( impl_createStorageFor_throw( _rURL ) );
Reference<XStorage> xTargetStorage(impl_GetStorageOrCreateFor_throw(aArguments, _rURL));
// extend media descriptor with URL
Sequence< PropertyValue > aMediaDescriptor( lcl_appendFileNameToDescriptor( _rArguments, _rURL ) );
Sequence<PropertyValue> aMediaDescriptor(lcl_appendFileNameToDescriptor(aArguments, _rURL));
// store to this storage
impl_storeToStorage_throw( xTargetStorage, aMediaDescriptor, aGuard );

View File

@@ -546,6 +546,19 @@ private:
const OUString& _rURL
) const;
/** Extracts storage from arguments, or creates for the given URL, truncating it if a file with
this name already exists
@throws Exception
if creating the storage failed
@return
the storage that is either extracted from arguments, or newly created for the file at
the given URL
*/
css::uno::Reference<css::embed::XStorage> impl_GetStorageOrCreateFor_throw(
const ::comphelper::NamedValueCollection& _rArguments, const OUString& _rURL) const;
/** sets our "modified" flag
will notify all our respective listeners, if the "modified" state actually changed

View File

@@ -584,7 +584,8 @@ public:
static bool CopyStoragesOfUnknownMediaType(
const css::uno::Reference< css::embed::XStorage >& xSource,
const css::uno::Reference< css::embed::XStorage >& xTarget );
const css::uno::Reference<css::embed::XStorage>& xTarget,
const css::uno::Sequence<OUString>& rExceptions = css::uno::Sequence<OUString>());
// The functions from SvPersist
void EnableSetModified( bool bEnable = true );

View File

@@ -174,7 +174,7 @@ class SfxDocumentInfoItem;
#define SID_CONTENTTYPE (SID_SFX_START + 1541)
#define SID_SAVETO (SID_SFX_START + 1546)
#define SID_SAVETO TypedWhichId<SfxBoolItem>(SID_SFX_START + 1546)
#define SID_VERSION (SID_SFX_START + 1583)
@@ -251,8 +251,11 @@ class SfxDocumentInfoItem;
#define SID_TOOLBAR_MODE (SID_SFX_START + 1728)
#define SID_NO_FILE_SYNC (SID_SFX_START + 1729)
#define SID_NO_THUMBNAIL (SID_SFX_START + 1730)
// Used to export a temporary file for preview in Mail Merge Wizard, where saving the data source is
// not required for preview, but interferes with not-yet-saved embedded data source for main document.
#define SID_NO_EMBEDDED_DS TypedWhichId<SfxBoolItem>(SID_SFX_START + 1731)
// SID_SFX_free_START (SID_SFX_START + 1731)
// SID_SFX_free_START (SID_SFX_START + 1732)
// SID_SFX_free_END (SID_SFX_START + 3999)
#define SID_OPEN_NEW_VIEW (SID_SFX_START + 520)

View File

@@ -170,6 +170,12 @@ public:
return nullptr;
}
template <class T>
static const T* GetItem(const SfxItemSet* pItemSet, TypedWhichId<T> nWhich,
bool bSearchInParent)
{
return GetItem<T>(pItemSet, static_cast<sal_uInt16>(nWhich), bSearchInParent);
}
sal_uInt16 GetWhichByPos(sal_uInt16 nPos) const;

View File

@@ -107,6 +107,7 @@ SfxFormalArgument const aFormalArgs[] = {
{ reinterpret_cast<SfxType*>(&aSfxBoolItem_Impl), "SaveACopy", SID_SAVEACOPYITEM },
{ reinterpret_cast<SfxType*>(&aSfxBoolItem_Impl), "NoFileSync", SID_NO_FILE_SYNC },
{ reinterpret_cast<SfxType*>(&aSfxBoolItem_Impl), "NoThumbnail", SID_NO_THUMBNAIL },
{ reinterpret_cast<SfxType*>(&aSfxBoolItem_Impl), "NoEmbDataSet", SID_NO_EMBEDDED_DS },
};
static sal_uInt16 nMediaArgsCount = SAL_N_ELEMENTS(aFormalArgs);

View File

@@ -3121,7 +3121,16 @@ bool SfxObjectShell::SaveAsChildren( SfxMedium& rMedium )
GetEmbeddedObjectContainer().StoreAsChildren(bOasis,SfxObjectCreateMode::EMBEDDED == eCreateMode,xStorage);
}
return CopyStoragesOfUnknownMediaType(GetStorage(), xStorage);
uno::Sequence<OUString> aExceptions;
if (const SfxBoolItem* pNoEmbDS
= SfxItemSet::GetItem(rMedium.GetItemSet(), SID_NO_EMBEDDED_DS, false))
{
// Don't save data source in case a temporary is being saved for preview in MM wizard
if (pNoEmbDS->GetValue())
aExceptions = uno::Sequence<OUString>{ "EmbeddedDatabase" };
}
return CopyStoragesOfUnknownMediaType(GetStorage(), xStorage, aExceptions);
}
bool SfxObjectShell::SaveCompletedChildren()
@@ -3350,8 +3359,9 @@ bool SfxObjectShell::SwitchPersistance( const uno::Reference< embed::XStorage >&
return bResult;
}
bool SfxObjectShell::CopyStoragesOfUnknownMediaType( const uno::Reference< embed::XStorage >& xSource,
const uno::Reference< embed::XStorage >& xTarget )
bool SfxObjectShell::CopyStoragesOfUnknownMediaType(const uno::Reference< embed::XStorage >& xSource,
const uno::Reference< embed::XStorage >& xTarget,
const uno::Sequence<OUString>& rExceptions)
{
// This method does not commit the target storage and should not do it
bool bResult = true;
@@ -3360,6 +3370,9 @@ bool SfxObjectShell::CopyStoragesOfUnknownMediaType( const uno::Reference< embed
{
for (const OUString& rSubElement : xSource->getElementNames())
{
if (std::find(rExceptions.begin(), rExceptions.end(), rSubElement) != rExceptions.end())
continue;
if (rSubElement == "Configurations")
{
// The workaround for compatibility with SO7, "Configurations" substorage must be preserved

View File

@@ -460,7 +460,7 @@ public:
static void StoreEmbeddedDataSource(const css::uno::Reference<css::frame::XStorable>& xStorable,
const css::uno::Reference<css::embed::XStorage>& xStorage,
const OUString& rStreamRelPath,
const OUString& rOwnURL);
const OUString& rOwnURL, bool bCopyTo = false);
SwDoc* getDoc() const;
/// Stop reacting to removed database registrations.

View File

@@ -111,10 +111,13 @@ SwMailMergeLayoutPage::SwMailMergeLayoutPage( SwMailMergeWizard* _pParent) :
aTempFile.EnableKillingFile();
}
SwView* pView = m_pWizard->GetSwView();
uno::Sequence< beans::PropertyValue > aValues(1);
uno::Sequence< beans::PropertyValue > aValues(2);
beans::PropertyValue* pValues = aValues.getArray();
pValues[0].Name = "FilterName";
pValues[0].Value <<= pSfxFlt->GetFilterName();
// Don't save embedded data set! It would steal it from current document.
pValues[1].Name = "NoEmbDataSet";
pValues[1].Value <<= true;
uno::Reference< frame::XStorable > xStore( pView->GetDocShell()->GetModel(), uno::UNO_QUERY);
xStore->storeToURL( m_sExampleURL, aValues );

View File

@@ -424,8 +424,17 @@ bool SwDocShell::SaveAs( SfxMedium& rMedium )
CalcLayoutForOLEObjects(); // format for OLE objects
bool bURLChanged = !GetMedium() || GetMedium()->GetURLObject() != rMedium.GetURLObject();
if (!m_xDoc->GetDBManager()->getEmbeddedName().isEmpty() && bURLChanged)
const bool bURLChanged = !GetMedium() || GetMedium()->GetURLObject() != rMedium.GetURLObject();
const bool bHasEmbedded = !m_xDoc->GetDBManager()->getEmbeddedName().isEmpty();
bool bSaveDS = bHasEmbedded && bURLChanged;
if (bSaveDS)
{
// Don't save data source in case a temporary is being saved for preview in MM wizard
if (const SfxBoolItem* pNoEmbDS
= SfxItemSet::GetItem(rMedium.GetItemSet(), SID_NO_EMBEDDED_DS, false))
bSaveDS = !pNoEmbDS->GetValue();
}
if (bSaveDS)
{
// We have an embedded data source definition, need to re-store it,
// otherwise relative references will break when the new file is in a
@@ -443,9 +452,19 @@ bool SwDocShell::SaveAs( SfxMedium& rMedium )
+ INetURLObject::encode(m_xDoc->GetDBManager()->getEmbeddedName(),
INetURLObject::PART_FPATH, INetURLObject::EncodeMechanism::All);
bool bCopyTo = GetCreateMode() == SfxObjectCreateMode::EMBEDDED;
if (!bCopyTo)
{
if (const SfxBoolItem* pSaveToItem
= SfxItemSet::GetItem(rMedium.GetItemSet(), SID_SAVETO, false))
bCopyTo = pSaveToItem->GetValue();
}
uno::Reference<sdb::XDocumentDataSource> xDataSource(xDatabaseContext->getByName(aURL), uno::UNO_QUERY);
uno::Reference<frame::XStorable> xStorable(xDataSource->getDatabaseDocument(), uno::UNO_QUERY);
SwDBManager::StoreEmbeddedDataSource(xStorable, rMedium.GetOutputStorage(), m_xDoc->GetDBManager()->getEmbeddedName(), rMedium.GetName());
SwDBManager::StoreEmbeddedDataSource(xStorable, rMedium.GetOutputStorage(),
m_xDoc->GetDBManager()->getEmbeddedName(),
rMedium.GetName(), bCopyTo);
}
// #i62875#

View File

@@ -2932,7 +2932,7 @@ OUString SwDBManager::LoadAndRegisterDataSource(weld::Window* pParent, SwDocShel
void SwDBManager::StoreEmbeddedDataSource(const uno::Reference<frame::XStorable>& xStorable,
const uno::Reference<embed::XStorage>& xStorage,
const OUString& rStreamRelPath,
const OUString& rOwnURL)
const OUString& rOwnURL, bool bCopyTo)
{
// Construct vnd.sun.star.pkg:// URL for later loading, and TargetStorage/StreamRelPath for storing.
OUString const sTmpName = ConstructVndSunStarPkgUrl(rOwnURL, rStreamRelPath);
@@ -2943,7 +2943,10 @@ void SwDBManager::StoreEmbeddedDataSource(const uno::Reference<frame::XStorable>
{"StreamRelPath", uno::makeAny(rStreamRelPath)},
{"BaseURI", uno::makeAny(rOwnURL)}
});
xStorable->storeAsURL(sTmpName, aSequence);
if (bCopyTo)
xStorable->storeToURL(sTmpName, aSequence);
else
xStorable->storeAsURL(sTmpName, aSequence);
}
OUString SwDBManager::LoadAndRegisterDataSource(const OUString &rURI, const OUString *pDestDir)