/* -*- 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/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/ #include <config_gpgme.h> #if HAVE_FEATURE_GPGME #include <com/sun/star/xml/crypto/GPGSEInitializer.hpp> #include <com/sun/star/xml/crypto/SEInitializer.hpp> #include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp> #endif #include <com/sun/star/security/DocumentDigitalSignatures.hpp> #include <com/sun/star/security/XCertificate.hpp>
sal_uInt16 getSlotIDFromMode( sal_Int16 nStoreMode )
{ // This is a temporary hardcoded solution must be removed when // dialogs do not need parameters in SidSet representation any more
if ( !aFilterProps.hasElements() )
{ // the default filter was not found, use just the first acceptable one
aFilterProps = GetDocServiceAnyFilter( nMust, nDont );
}
}
if ( nResult != STATUS_NO_ACTION && GetStorable()->hasLocation() )
{ // the saving is acceptable // in case the configuration entry is not set or set to false // or in case of version creation if ( officecfg::Office::Common::Save::Document::AlwaysSaveAs::get()
&& GetMediaDescr().find( u"VersionComment"_ustr ) == GetMediaDescr().end() )
{ // notify the user that SaveAs is going to be done
std::unique_ptr<weld::MessageDialog> xMessageBox(Application::CreateMessageDialog(SfxStoringHelper::GetModelWindow(m_xModel),
VclMessageType::Question, VclButtonsType::OkCancel, SfxResId(STR_NEW_FILENAME_SAVE))); if (xMessageBox->run() == RET_OK)
nResult = STATUS_SAVEAS; else
nResult = STATUS_NO_ACTION;
}
}
return nResult;
}
sal_Int8 ModelData_Impl::CheckStateForSave()
{ // if the document is readonly or a new one a SaveAs operation must be used if ( !GetStorable()->hasLocation() || GetStorable()->isReadonly() ) return STATUS_SAVEAS;
// check acceptable entries for media descriptor
::comphelper::SequenceAsHashMap aAcceptedArgs;
// remove unacceptable entry if there is any
DBG_ASSERT( GetMediaDescr().size() == aAcceptedArgs.size(), "Unacceptable parameters are provided in Save request!\n" ); if ( GetMediaDescr().size() != aAcceptedArgs.size() )
GetMediaDescr() = std::move(aAcceptedArgs);
// check that the old filter is acceptable return CheckFilter( GetDocProps().getUnpackedValueOrDefault(aFilterNameString, OUString()) );
}
// only a temporary solution until default filter retrieving feature is implemented // then GetDocServiceDefaultFilter() must be used
::comphelper::SequenceAsHashMap aDefFiltPropsHM = GetDocServiceDefaultFilterCheckFlags( SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT, SfxFilterFlags::NONE );
SfxFilterFlags nDefFiltFlags = static_cast<SfxFilterFlags>(aDefFiltPropsHM.getUnpackedValueOrDefault(u"Flags"_ustr, sal_Int32(0) ));
bool bAsk = false;
// if the old filter is not acceptable // and there is no default filter or it is not acceptable for requested parameters then proceed with saveAs if ( ( aFiltPropsHM.empty() || !( nFiltFlags & SfxFilterFlags::EXPORT ) )
&& ( aDefFiltPropsHM.empty() || !( nDefFiltFlags & SfxFilterFlags::EXPORT ) || nDefFiltFlags & SfxFilterFlags::INTERNAL ) ) return STATUS_SAVEAS;
// so at this point there is either an acceptable old filter or default one if ( aFiltPropsHM.empty() || !( nFiltFlags & SfxFilterFlags::EXPORT ) )
{ // so the default filter must be acceptable return STATUS_SAVEAS_STANDARDNAME;
} elseif ( ( !( nFiltFlags & SfxFilterFlags::OWN ) || ( nFiltFlags & SfxFilterFlags::ALIEN ) )
&& !aDefFiltPropsHM.empty()
&& ( nDefFiltFlags & SfxFilterFlags::EXPORT ) && !( nDefFiltFlags & SfxFilterFlags::INTERNAL ))
{
bAsk = true;
}
// check if EncryptionData supports this output format
{
OUString aSupportedFilters; const ::comphelper::SequenceAsHashMap& rDocumentProperties = GetDocProps(); const css::uno::Sequence<css::beans::NamedValue> aEncryptionData = rDocumentProperties.getUnpackedValueOrDefault(u"EncryptionData"_ustr, css::uno::Sequence<css::beans::NamedValue>()); if (aEncryptionData != css::uno::Sequence<css::beans::NamedValue>())
{ for (const css::beans::NamedValue& aNamedValue : aEncryptionData)
{ if (aNamedValue.Name == "SupportedFilters")
{
aNamedValue.Value >>= aSupportedFilters;
}
}
}
// if 'SupportedFilters' is empty assume that all filters are supported. if (!aSupportedFilters.isEmpty())
{ const OUString aSelectedFilter = aFiltPropsHM.getUnpackedValueOrDefault(u"UIName"_ustr, OUString());
// the file name must be specified if overwrite option is set if ( aOverwriteIter != GetMediaDescr().end() ) throw task::ErrorCodeIOException(
u"ModelData_Impl::OutputFileDialog: ERRCODE_IO_INVALIDPARAMETER"_ustr,
uno::Reference< uno::XInterface >(),
sal_uInt32(ERRCODE_IO_INVALIDPARAMETER));
// no target file name is specified // we need to show the file dialog
// check if we have a filter which allows for filter options, so we need a corresponding checkbox in the dialog bool bAllowOptions = false;
// in case of Export, filter options dialog is used if available if( !( nStoreMode & EXPORT_REQUESTED ) || ( nStoreMode & WIDEEXPORT_REQUESTED ) )
bAllowOptions = CheckFilterOptionsDialogExistence();
// get the filename by dialog ... // create the file dialog
sal_Int16 aDialogMode = bAllowOptions
? css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS
: css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD;
FileDialogFlags aDialogFlags = FileDialogFlags::NONE;
// Fall back to the document base URL - but only if the document is not based on a template. // Otherwise the template's directory would be used, which is not what we want. if (SfxViewShell* pViewShell = SfxViewShell::Current())
{
SfxObjectShell* pDocShell = pViewShell->GetObjectShell(); if (pDocShell && !pDocShell->IsBasedOnTemplate())
{ if (sPreselectedDir.isEmpty())
sPreselectedDir = GetDocProps().getUnpackedValueOrDefault("DocumentBaseURL", OUString()); if (sPreselectedDir.isEmpty() && GetStorable()->hasLocation())
sPreselectedDir = GetStorable()->getLocation();
}
}
INetURLObject aObj(sPreselectedDir);
aObj.removeSegment(); // remove file name from URL
sPreselectedDir = aObj.GetMainURL(INetURLObject::DecodeMechanism::NONE); if ( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) )
{ if ( ( nStoreMode & PDFEXPORT_REQUESTED ) && !aPreselectedFilterPropsHM.empty() )
{ // this is a PDF export // the filter options has been shown already const OUString aFilterUIName = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( u"UIName"_ustr, OUString() );
pFileDlg.reset(new sfx2::FileDialogHelper( aDialogMode, aDialogFlags, aFilterUIName, u"pdf", sPreselectedDir, rDenyList, pFrameWin ));
pFileDlg->SetCurrentFilter( aFilterUIName );
} elseif ((nStoreMode & EPUBEXPORT_REQUESTED) && !aPreselectedFilterPropsHM.empty())
{ // This is an EPUB export, the filter options has been shown already. const OUString aFilterUIName = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( u"UIName"_ustr, OUString() );
pFileDlg.reset(new sfx2::FileDialogHelper(aDialogMode, aDialogFlags, aFilterUIName, u"epub", sPreselectedDir, rDenyList, pFrameWin));
pFileDlg->SetCurrentFilter(aFilterUIName);
} else
{ // This is the normal dialog
pFileDlg.reset(new sfx2::FileDialogHelper( aDialogMode, aDialogFlags, aDocServiceName, nDialog, nMust, nDont, sPreselectedDir, rDenyList, pFrameWin ));
}
if ( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) )
{ // it is export, set the preselected filter
pFileDlg->SetCurrentFilter( aPreselectedFilterPropsHM.getUnpackedValueOrDefault( u"UIName"_ustr, OUString() ) );
aAdjustToType = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( u"Type"_ustr, OUString() );
} // it is no export, bSetStandardName == true means that user agreed to store document in the default (default default ;-)) format elseif ( bSetStandardName || GetStorable()->hasLocation() )
{
uno::Sequence< beans::PropertyValue > aOldFilterProps; const OUString aOldFilterName = GetDocProps().getUnpackedValueOrDefault( sFilterNameString, OUString() );
if ( !aOldFilterName.isEmpty() )
m_pOwner->GetFilterConfiguration()->getByName( aOldFilterName ) >>= aOldFilterProps;
// This is a temporary hardcoded solution must be removed when // dialogs do not need parameters in SidSet representation any more
sal_uInt16 nSlotID = getSlotIDFromMode( nStoreMode ); if ( !nSlotID ) throw lang::IllegalArgumentException(); // TODO:
// generate SidSet from MediaDescriptor and provide it into FileDialog // than merge changed SidSet back
std::optional<SfxAllItemSet> pDialogParams( SfxGetpApp()->GetPool() );
TransformParameters( nSlotID,
GetMediaDescr().getAsConstPropertyValueList(),
*pDialogParams );
if ( bPreselectPassword && !pDialogParams->HasItem( SID_ENCRYPTIONDATA ) )
{ // the file dialog preselects the password checkbox if the provided mediadescriptor has encryption data entry // after dialog execution the password interaction flag will be either removed or not
pDialogParams->Put( SfxBoolItem( SID_PASSWORDINTERACTION, true ) );
}
// aFilterName is a pure output parameter, pDialogParams is an in/out parameter
OUString aFilterName; // in LOK case we don't show File Picker so it will fail, but execute to do other preparations if (pFileDlg->Execute(pDialogParams, aFilterName, nScriptingSignatureState) != ERRCODE_NONE
&& !comphelper::LibreOfficeKit::isActive() )
{ throw task::ErrorCodeIOException(
u"ModelData_Impl::OutputFileDialog: ERRCODE_IO_ABORT"_ustr,
uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT));
} elseif (comphelper::LibreOfficeKit::isActive())
{
aFilterName = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( u"Name"_ustr, OUString() );
}
// the following two arguments can not be converted in MediaDescriptor, // so they should be removed from the ItemSet after retrieving const SfxBoolItem* pRecommendReadOnly = SfxItemSet::GetItem<SfxBoolItem>(&*pDialogParams, SID_RECOMMENDREADONLY, false);
m_bRecommendReadOnly = ( pRecommendReadOnly && pRecommendReadOnly->GetValue() );
pDialogParams->ClearItem( SID_RECOMMENDREADONLY );
// get the path from the dialog
INetURLObject aURL( pFileDlg->GetPath() );
if (comphelper::LibreOfficeKit::isActive())
{ #ifdef IOS // The iOS app (and maybe the Android app) have fails to set the URL to // save to so we need to set it to a temporary file. // Note: the iOS app is responsible for deleting the temporary file. if (nStoreMode & EXPORT_REQUESTED && aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE).isEmpty())
{ // Mirror the "export/docbasename.pdf" path format to match the // format used in the "downloadas" message handler in the iOS app's // -[DocumentViewController userContentController:didReceiveScriptMessage] // selector. // Important note: temporary files created here must be in their // own subdirectory since the iOS app's UIDocumentPickerDelegate // will try to delete both the temporary file and its parent // directory.
OUString aFullName = u"export/" + aRecommendedName;
OUString aBaseName;
OUString aExtension;
sal_Int32 nPos = aFullName.lastIndexOf( '.' ); if ( nPos >= 0 )
{
aBaseName = aFullName.copy(0, nPos);
aExtension = aFullName.copy(nPos, aFullName.getLength() - nPos);
}
aURL = INetURLObject(::utl::CreateTempURL( aBaseName, false, aExtension, nullptr, true));
// Remove any stale files left from a previous export
OUString fileURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE); if (!fileURL.isEmpty())
osl::File::remove(fileURL);
} else
{ #endif // keep name with extension
aSuggestedName = aRecommendedName;
OUString aExtension; if (size_t nPos = aSuggestedName.lastIndexOf('.') + 1)
aExtension = aSuggestedName.copy(nPos, aSuggestedName.getLength() - nPos);
aURL.SetExtension(aExtension); #ifdef IOS
} #endif
} else
{ // the path should be provided outside since it might be used for further calls to the dialog
aSuggestedName = aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset);
}
aSuggestedDir = pFileDlg->GetDisplayDirectory();
// old filter options should be cleared in case different filter is used
if ( aFilterName == aFilterFromMediaDescr )
{ // preserve current settings if any // if there no current settings and the name is the same // as old filter name use old filter settings
if ( ( !( nStoreMode & EXPORT_REQUESTED ) || ( nStoreMode & WIDEEXPORT_REQUESTED ) ) && bUseFilterOptions )
{ try
{ // for exporters: always show dialog if format uses options // for save: show dialog if format uses options and no options given or if forced by user
uno::Any aVal =
xExtFileDlg->getValue( ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS, 0 );
// merge in results of the dialog execution
GetMediaDescr()[u"URL"_ustr] <<= aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
GetMediaDescr()[sFilterNameString] <<= aFilterName;
// for Export - keep a runtime var for each document where the document was last exported to if (GetStorable()->hasLocation() && (nStoreMode & EXPORT_REQUESTED))
{
uno::Sequence< beans::PropertyValue > descriptor{
beans::PropertyValue(u"ExportDirectory"_ustr,
-1, uno::Any(aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE )), beans::PropertyState_DIRECT_VALUE),
};
GetModel()->setArgs(descriptor);
}
uno::Reference < util::XURLTransformer > xTransformer( util::URLTransformer::create( comphelper::getProcessComponentContext() ) ); if ( xTransformer->parseStrict( aURL ) )
{
uno::Reference< frame::XDispatch > xDispatch = xFrameDispatch->queryDispatch(
aURL,
u"_self"_ustr,
0 ); if ( xDispatch.is() )
{ // tdf#119206 use (abuse?) a SynchronMode of true, // which will become SfxRequest::IsSynchronCall of true // in SfxObjectShell::ExecFile_Impl to request that we // do not want the properties dialog to be run async
uno::Sequence< beans::PropertyValue > aProperties{
comphelper::makePropertyValue(u"SynchronMode"_ustr, true)
};
xDispatch->dispatch(aURL, aProperties);
bDialogUsed = true;
}
}
}
}
} catch ( const uno::Exception& )
{
}
OUString ModelData_Impl::GetRecommendedName( const OUString& aSuggestedName, const OUString& aTypeName )
{ // the last used name might be provided by aSuggestedName from the old selection, or from the MediaDescriptor if ( !aSuggestedName.isEmpty() ) return aSuggestedName;
m_bSetStandardName = false; // can be set only for SaveAs
m_bPreselectPassword = bPreselectPassword;
m_nScriptingSignatureState = nScriptingSignatureState;
// parse the slot name
m_bRemote = false;
m_nStoreMode = getStoreModeFromSlotName( aSlotName );
// if saving is not acceptable the warning must be shown even in case of SaveAs operation if ( ( m_nStoreMode & SAVEAS_REQUESTED ) && aModelData.CheckSaveAcceptable( STATUS_SAVEAS ) == STATUS_NO_ACTION ) throw task::ErrorCodeIOException(
u"SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT"_ustr,
uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT));
} elseif ( m_nStoreMode & SAVE_REQUESTED )
{ // if saving is not acceptable by the configuration the warning must be shown
nStatusSave = aModelData.CheckSaveAcceptable( STATUS_SAVE );
if ( nStatusSave == STATUS_NO_ACTION ) throw task::ErrorCodeIOException(
u"SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT"_ustr,
uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT)); elseif ( nStatusSave == STATUS_SAVE )
{ // check whether it is possible to use save operation
nStatusSave = aModelData.CheckStateForSave();
}
if ( nStatusSave == STATUS_NO_ACTION )
{ throw task::ErrorCodeIOException(
u"SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT"_ustr,
uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT));
} elseif ( nStatusSave != STATUS_SAVE )
{ // this should be a usual SaveAs operation
m_nStoreMode = SAVEAS_REQUESTED; if ( nStatusSave == STATUS_SAVEAS_STANDARDNAME )
m_bSetStandardName = true;
}
}
// if it is no export, warn user that the signature will be removed if ( !pDocShell->IsRememberingSignature()
&& (SignatureState::OK == nDocumentSignatureState
|| SignatureState::INVALID == nDocumentSignatureState
|| SignatureState::NOTVALIDATED == nDocumentSignatureState
|| SignatureState::PARTIAL_OK == nDocumentSignatureState) )
{
std::unique_ptr<weld::MessageDialog> xMessageBox(Application::CreateMessageDialog(SfxStoringHelper::GetModelWindow(xModel),
VclMessageType::Question, VclButtonsType::YesNo, SfxResId(RID_SVXSTR_XMLSEC_QUERY_LOSINGSIGNATURE))); if (xMessageBox->run() != RET_YES)
{ // the user has decided not to store the document throw task::ErrorCodeIOException(
u"SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT (Preserve Signature)"_ustr,
uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT));
}
}
}
if ( m_nStoreMode & SAVE_REQUESTED && nStatusSave == STATUS_SAVE )
{ // Document properties can contain streams that should be freed before storing
aModelData.FreeDocumentProps();
if ( aModelData.GetStorable2().is() )
{ try
{
aModelData.GetStorable2()->storeSelf( aModelData.GetMediaDescr().getAsConstPropertyValueList() );
} catch (const lang::IllegalArgumentException&)
{
TOOLS_WARN_EXCEPTION("sfx.doc", "Ignoring parameters! ModelData considers this illegal");
aModelData.GetStorable()->store();
}
} else
{
OSL_FAIL( "XStorable2 is not supported by the model!" );
aModelData.GetStorable()->store();
}
returnfalse;
}
// preselect a filter for the storing process
uno::Sequence< beans::PropertyValue > aFilterProps = aModelData.GetPreselectedFilter_Impl( m_nStoreMode );
DBG_ASSERT( aFilterProps.hasElements(), "No filter for storing!\n" ); if ( !aFilterProps.hasElements() ) throw task::ErrorCodeIOException(
u"SfxStoringHelper::GUIStoreModel: ERRCODE_IO_INVALIDPARAMETER"_ustr,
uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER));
for (;;)
{ // in case the dialog is opened a second time the folder should be the same as previously navigated to by the user, not what was handed over by initial parameters
bUseFilterOptions = aModelData.OutputFileDialog( nStoreMode, aFilterProps, bSetStandardName, aSuggestedName, bPreselectPassword, aSuggestedDir, nDialog, aDenyList, nScriptingSignatureState ); if ( nStoreMode == SAVEAS_REQUESTED )
{ // in case of saving check filter for possible alien warning const OUString aSelFilterName = aModelData.GetMediaDescr().getUnpackedValueOrDefault( sFilterNameString, OUString() );
sal_Int8 nStatusFilterSave = aModelData.CheckFilter( aSelFilterName ); if ( nStatusFilterSave == STATUS_SAVEAS_STANDARDNAME )
{ // switch to best filter
bSetStandardName = true;
} elseif ( nStatusFilterSave == STATUS_SAVE )
{ // user confirmed alien filter or "good" filter is used break;
}
} else break;
}
bDialogUsed = true;
aFileNameIter = aModelData.GetMediaDescr().find( u"URL"_ustr );
} else
{ // the target file name is provided so check if new filter options // are provided or old options can be used if ( aFilterFromMediaDescr == aOldFilterName )
{
::comphelper::SequenceAsHashMap::const_iterator aIter =
aModelData.GetDocProps().find( sFilterOptionsString ); if ( aIter != aModelData.GetDocProps().end()
&& aModelData.GetMediaDescr().find( sFilterOptionsString ) == aModelData.GetMediaDescr().end() )
aModelData.GetMediaDescr()[aIter->first] = aIter->second;
// check if the filter Dialog has not been called before if( !( nStoreMode & PDFEXPORT_REQUESTED ) && !( nStoreMode & EPUBEXPORT_REQUESTED ) && !bFilterFlagsSet
&& ( ( nStoreMode & EXPORT_REQUESTED ) || bUseFilterOptions ) )
{ // execute filter options dialog if ( aModelData.ExecuteFilterDialog_Impl( aFilterName, false ) )
{
bDialogUsed = true; // check if the file is a pdf or not and change the storing mode at convenience if (aFilterName.endsWith("pdf_Export"))
nStoreMode = EXPORT_REQUESTED | PDFEXPORT_REQUESTED;
}
}
// so the arguments will not change any more and can be stored to the main location
aArgsSequence = aModelData.GetMediaDescr().getAsConstPropertyValueList();
// store the document and handle it's docinfo // Restore when exporting (which is also done when LoKit is enable, see below). constbool bRestore
= (nStoreMode & EXPORT_REQUESTED)
|| ((nStoreMode & SAVEAS_REQUESTED) && comphelper::LibreOfficeKit::isActive());
DocumentSettingsGuard aSettingsGuard(aModelData.GetModel(), aModelData.IsRecommendReadOnly(),
bRestore);
// Treat attempted PDF export like a print: update document print statistics if ((nStoreMode & PDFEXPORT_REQUESTED) && SfxViewShell::Current())
{
SfxObjectShell* pDocShell = SfxViewShell::Current()->GetObjectShell(); constbool bWasEnableSetModified = pDocShell && pDocShell->IsEnableSetModified(); bool bResetESM = false;
if (bWasEnableSetModified
&& !officecfg::Office::Common::Print::PrintingModifiesDocument::get())
{
pDocShell->EnableSetModified(false); // don't let export mark document as modified
bResetESM = true;
}
if (bResetESM)
pDocShell->EnableSetModified(true);
}
OSL_ENSURE( aModelData.GetMediaDescr().find( u"Password"_ustr ) == aModelData.GetMediaDescr().end(), "The Password property of MediaDescriptor should not be used here!" );
// Fetch the current view early, saving may spin the main loop, which may change the current // view.
SfxViewShell* pViewShell = SfxViewShell::Current();
if ( officecfg::Office::Common::Save::Document::EditProperty::get()
&& ( !aModelData.GetStorable()->hasLocation()
|| INetURLObject( aModelData.GetStorable()->getLocation() ) != aURL ) )
{ // this is definitely not a Save operation // so the document info can be updated
// on export document info must be preserved
uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
aModelData.GetModel(), uno::UNO_QUERY_THROW);
uno::Reference<util::XCloneable> xCloneable(
xDPS->getDocumentProperties(), uno::UNO_QUERY_THROW);
uno::Reference<document::XDocumentProperties> xOldDocProps(
xCloneable->createClone(), uno::UNO_QUERY_THROW);
// use dispatch API to show document info dialog if ( aModelData.ShowDocumentInfoDialog() )
bDialogUsed = true; else
{
OSL_FAIL( "Can't execute document info dialog!" );
}
try { // Document properties can contain streams that should be freed before storing
aModelData.FreeDocumentProps(); if ( nStoreMode & EXPORT_REQUESTED )
aModelData.GetStorable()->storeToURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aArgsSequence ); else
aModelData.GetStorable()->storeAsURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aArgsSequence );
} catch( const uno::Exception& )
{ if ( nStoreMode & EXPORT_REQUESTED )
{
SetDocInfoState(aModelData.GetModel(), xOldDocProps);
} throw;
}
if ( nStoreMode & EXPORT_REQUESTED )
{
SetDocInfoState(aModelData.GetModel(), xOldDocProps);
}
} else
{ // Document properties can contain streams that should be freed before storing
aModelData.FreeDocumentProps();
// this is actually a save operation with different parameters // so storeTo or storeAs without DocInfo operations are used #ifdef IOS try
{ #endif // SaveAs in LoKit is unhelpful. It saves the document to a new path, which // breaks the link with the storage, so new modifications can't be uploaded. if ((nStoreMode & EXPORT_REQUESTED)
|| ((nStoreMode & SAVEAS_REQUESTED) && comphelper::LibreOfficeKit::isActive()))
aModelData.GetStorable()->storeToURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aArgsSequence ); else
aModelData.GetStorable()->storeAsURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aArgsSequence ); #ifdef IOS
} catch( const uno::Exception& )
{ // When using the iOS app (and maybe the Android app), the app // will remain blocked if we rethrow an exception.
} #endif
}
if (aModelData.IsSignWithDefaultSignature())
{ auto SignWithDefaultSignature = [&]()
{ #if HAVE_FEATURE_GPGME auto aSigningKey = SvtUserOptions().GetSigningKey(); if (aSigningKey.isEmpty()) return;
// couldn't find the specified default signing certificate! // alert the user the document won't be signed
std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
SfxStoringHelper::GetModelWindow(aModelData.GetModel()),
VclMessageType::Error, VclButtonsType::Ok,
SfxResId(STR_ERROR_NOMATCHINGDEFUALTCERT)));
xBox->run(); return; #endif
};
SignWithDefaultSignature();
}
try
{
uno::Reference< beans::XPropertySet > const xSet(
xDocPropsToFill->getUserDefinedProperties(), uno::UNO_QUERY);
uno::Reference< beans::XPropertyContainer > xContainer( xSet, uno::UNO_QUERY );
uno::Reference< beans::XPropertySetInfo > xSetInfo = xSet->getPropertySetInfo(); const uno::Sequence< beans::Property > lProps = xSetInfo->getProperties(); for (const beans::Property& rProp : lProps)
{
uno::Any aValue = xPropSet->getPropertyValue( rProp.Name ); if ( rProp.Attributes & css::beans::PropertyAttribute::REMOVABLE )
{ try
{ // QUESTION: DefaultValue?!
xContainer->addProperty( rProp.Name, rProp.Attributes, aValue );
} catch (beans::PropertyExistException const&) {} try
{ // it is possible that the propertysets from XML and binary files differ; we shouldn't break then
xSet->setPropertyValue( rProp.Name, aValue );
} catch ( const uno::Exception& ) {}
}
}
// sigh... have to set these manually I'm afraid... wonder why // SfxObjectShell doesn't handle this internally, should be easier
xDocPropsToFill->setAuthor(i_xOldDocProps->getAuthor());
xDocPropsToFill->setGenerator(i_xOldDocProps->getGenerator());
xDocPropsToFill->setCreationDate(i_xOldDocProps->getCreationDate());
xDocPropsToFill->setTitle(i_xOldDocProps->getTitle());
xDocPropsToFill->setSubject(i_xOldDocProps->getSubject());
xDocPropsToFill->setDescription(i_xOldDocProps->getDescription());
xDocPropsToFill->setKeywords(i_xOldDocProps->getKeywords());
xDocPropsToFill->setModifiedBy(i_xOldDocProps->getModifiedBy());
xDocPropsToFill->setModificationDate(i_xOldDocProps->getModificationDate());
xDocPropsToFill->setPrintedBy(i_xOldDocProps->getPrintedBy());
xDocPropsToFill->setPrintDate(i_xOldDocProps->getPrintDate());
xDocPropsToFill->setAutoloadURL(i_xOldDocProps->getAutoloadURL());
xDocPropsToFill->setAutoloadSecs(i_xOldDocProps->getAutoloadSecs());
xDocPropsToFill->setDefaultTarget(i_xOldDocProps->getDefaultTarget());
xDocPropsToFill->setEditingCycles(i_xOldDocProps->getEditingCycles());
xDocPropsToFill->setEditingDuration(i_xOldDocProps->getEditingDuration()); // other attributes e.g. DocumentStatistics are not editable from dialog
} catch (const uno::Exception&)
{
TOOLS_INFO_EXCEPTION("sfx.doc", "SetDocInfoState");
}
// set the modified flag back if required if ( bIsModified != bool(xModifiable->isModified()) )
xModifiable->setModified( bIsModified );
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.