Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / sfx2 / source / doc / guisaveas.cxx
blob736b7d229d4b2753049dd8001994f138caccad35
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
21 #include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
22 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
23 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
24 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
25 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
26 #include <com/sun/star/view/XSelectionSupplier.hpp>
27 #include <com/sun/star/beans/PropertyExistException.hpp>
28 #include <com/sun/star/beans/XPropertyAccess.hpp>
29 #include <com/sun/star/beans/XPropertySet.hpp>
30 #include <com/sun/star/beans/XPropertyContainer.hpp>
31 #include <com/sun/star/beans/PropertyAttribute.hpp>
32 #include <com/sun/star/document/XExporter.hpp>
33 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
34 #include <com/sun/star/document/XDocumentProperties.hpp>
35 #include <com/sun/star/task/ErrorCodeIOException.hpp>
36 #include <com/sun/star/task/InteractionHandler.hpp>
37 #include <com/sun/star/util/URLTransformer.hpp>
38 #include <com/sun/star/util/XURLTransformer.hpp>
39 #include <com/sun/star/frame/ModuleManager.hpp>
40 #include <com/sun/star/frame/XStorable.hpp>
41 #include <com/sun/star/frame/XStorable2.hpp>
42 #include <com/sun/star/frame/XDispatchProvider.hpp>
43 #include <com/sun/star/frame/XDispatch.hpp>
44 #include <com/sun/star/frame/XTitle.hpp>
45 #include <com/sun/star/util/XModifiable.hpp>
46 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
48 #include <com/sun/star/util/XCloneable.hpp>
50 #include <guisaveas.hxx>
52 #include <sal/log.hxx>
53 #include <unotools/pathoptions.hxx>
54 #include <svl/itemset.hxx>
55 #include <svl/eitem.hxx>
56 #include <unotools/saveopt.hxx>
57 #include <tools/debug.hxx>
58 #include <tools/diagnose_ex.h>
59 #include <tools/urlobj.hxx>
60 #include <comphelper/processfactory.hxx>
61 #include <comphelper/propertysequence.hxx>
62 #include <comphelper/sequenceashashmap.hxx>
63 #include <comphelper/mimeconfighelper.hxx>
64 #include <comphelper/lok.hxx>
65 #include <vcl/svapp.hxx>
66 #include <vcl/weld.hxx>
67 #include <o3tl/char16_t2wchar_t.hxx>
69 #include <sfx2/sfxsids.hrc>
70 #include <sfx2/strings.hrc>
71 #include <sfx2/sfxresid.hxx>
72 #include <sfx2/filedlghelper.hxx>
73 #include <asyncfunc.hxx>
74 #include <sfx2/app.hxx>
75 #include <sfx2/sfxuno.hxx>
76 #include <alienwarn.hxx>
78 #include <memory>
80 #include <officecfg/Office/Common.hxx>
82 #include <vcl/FilterConfigItem.hxx>
83 #include <com/sun/star/system/SystemShellExecute.hpp>
84 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
86 #include <osl/file.hxx>
88 #ifdef _WIN32
89 #include <Shlobj.h>
90 #ifdef GetTempPath
91 #undef GetTempPath
92 #endif
93 #endif
95 // flags that specify requested operation
96 #define EXPORT_REQUESTED 1
97 #define PDFEXPORT_REQUESTED 2
98 #define PDFDIRECTEXPORT_REQUESTED 4
99 #define WIDEEXPORT_REQUESTED 8
100 #define SAVE_REQUESTED 16
101 #define SAVEAS_REQUESTED 32
102 #define SAVEACOPY_REQUESTED 64
103 #define EPUBEXPORT_REQUESTED 128
104 #define EPUBDIRECTEXPORT_REQUESTED 256
105 #define SAVEASREMOTE_REQUESTED -1
107 // possible statuses of save operation
108 #define STATUS_NO_ACTION 0
109 #define STATUS_SAVE 1
110 #define STATUS_SAVEAS 2
111 #define STATUS_SAVEAS_STANDARDNAME 3
113 const char aFilterNameString[] = "FilterName";
114 const char aFilterOptionsString[] = "FilterOptions";
115 const char aFilterDataString[] = "FilterData";
117 using namespace ::com::sun::star;
118 using namespace css::system;
120 namespace {
122 sal_uInt16 getSlotIDFromMode( sal_Int16 nStoreMode )
124 // This is a temporary hardcoded solution must be removed when
125 // dialogs do not need parameters in SidSet representation any more
127 sal_uInt16 nResult = 0;
128 if ( nStoreMode == EXPORT_REQUESTED || nStoreMode == ( EXPORT_REQUESTED | SAVEACOPY_REQUESTED | WIDEEXPORT_REQUESTED ) )
129 nResult = SID_EXPORTDOC;
130 else if ( nStoreMode == ( EXPORT_REQUESTED | PDFEXPORT_REQUESTED ) )
131 nResult = SID_EXPORTDOCASPDF;
132 else if ( nStoreMode == ( EXPORT_REQUESTED | EPUBEXPORT_REQUESTED ) )
133 nResult = SID_EXPORTDOCASEPUB;
134 else if ( nStoreMode == ( EXPORT_REQUESTED | PDFEXPORT_REQUESTED | PDFDIRECTEXPORT_REQUESTED ) )
135 nResult = SID_DIRECTEXPORTDOCASPDF;
136 else if ( nStoreMode == ( EXPORT_REQUESTED | EPUBEXPORT_REQUESTED | EPUBDIRECTEXPORT_REQUESTED ) )
137 nResult = SID_DIRECTEXPORTDOCASEPUB;
138 else if ( nStoreMode == SAVEAS_REQUESTED || nStoreMode == ( EXPORT_REQUESTED | WIDEEXPORT_REQUESTED ) )
139 nResult = SID_SAVEASDOC;
140 else if ( nStoreMode == SAVEASREMOTE_REQUESTED )
141 nResult = SID_SAVEASREMOTE;
142 else {
143 SAL_WARN( "sfx.doc", "Unacceptable slot name is provided!" );
146 return nResult;
150 sal_Int16 getStoreModeFromSlotName( const OUString& aSlotName )
152 sal_Int16 nResult = 0;
153 if ( aSlotName == "ExportTo" )
154 nResult = EXPORT_REQUESTED;
155 else if ( aSlotName == "ExportToPDF" )
156 nResult = EXPORT_REQUESTED | PDFEXPORT_REQUESTED;
157 else if ( aSlotName == "ExportDirectToPDF" )
158 nResult = EXPORT_REQUESTED | PDFEXPORT_REQUESTED | PDFDIRECTEXPORT_REQUESTED;
159 else if ( aSlotName == "ExportToEPUB" )
160 nResult = EXPORT_REQUESTED | EPUBEXPORT_REQUESTED;
161 else if ( aSlotName == "ExportDirectToEPUB" )
162 nResult = EXPORT_REQUESTED | EPUBEXPORT_REQUESTED | EPUBDIRECTEXPORT_REQUESTED;
163 else if ( aSlotName == "Save" )
164 nResult = SAVE_REQUESTED;
165 else if ( aSlotName == "SaveAs" )
166 nResult = SAVEAS_REQUESTED;
167 else if ( aSlotName == "SaveAsRemote" )
168 nResult = SAVEASREMOTE_REQUESTED;
169 else
170 throw task::ErrorCodeIOException(
171 ("getStoreModeFromSlotName(\"" + aSlotName
172 + "): ERRCODE_IO_INVALIDPARAMETER"),
173 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER) );
175 return nResult;
179 SfxFilterFlags getMustFlags( sal_Int16 nStoreMode )
181 return ( SfxFilterFlags::EXPORT
182 | ( ( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) ) ? SfxFilterFlags::NONE : SfxFilterFlags::IMPORT ) );
186 SfxFilterFlags getDontFlags( sal_Int16 nStoreMode )
188 return ( SfxFilterFlags::INTERNAL
189 | SfxFilterFlags::NOTINFILEDLG
190 | ( ( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) ) ? SfxFilterFlags::IMPORT : SfxFilterFlags::NONE ) );
196 class DocumentSettingsGuard
198 uno::Reference< beans::XPropertySet > m_xDocumentSettings;
199 bool m_bPreserveReadOnly;
200 bool m_bReadOnlySupported;
202 bool m_bRestoreSettings;
203 public:
204 DocumentSettingsGuard( const uno::Reference< frame::XModel >& xModel, bool bReadOnly, bool bRestore )
205 : m_bPreserveReadOnly( false )
206 , m_bReadOnlySupported( false )
207 , m_bRestoreSettings( bRestore )
211 uno::Reference< lang::XMultiServiceFactory > xDocSettingsSupplier( xModel, uno::UNO_QUERY_THROW );
212 m_xDocumentSettings.set(
213 xDocSettingsSupplier->createInstance( "com.sun.star.document.Settings" ),
214 uno::UNO_QUERY_THROW );
218 OUString aLoadReadonlyString( "LoadReadonly" );
219 m_xDocumentSettings->getPropertyValue( aLoadReadonlyString ) >>= m_bPreserveReadOnly;
220 m_xDocumentSettings->setPropertyValue( aLoadReadonlyString, uno::makeAny( bReadOnly ) );
221 m_bReadOnlySupported = true;
223 catch( const uno::Exception& )
226 catch( const uno::Exception& )
229 if ( bReadOnly && !m_bReadOnlySupported )
230 throw uno::RuntimeException(); // the user could provide the data, so it must be stored
233 ~DocumentSettingsGuard()
235 if ( m_bRestoreSettings )
239 if ( m_bReadOnlySupported )
240 m_xDocumentSettings->setPropertyValue( "LoadReadonly", uno::makeAny( m_bPreserveReadOnly ) );
242 catch( const uno::Exception& )
244 OSL_FAIL( "Unexpected exception!" );
249 } // anonymous namespace
253 class ModelData_Impl
255 SfxStoringHelper* m_pOwner;
256 uno::Reference< frame::XModel > m_xModel;
257 uno::Reference< frame::XStorable > m_xStorable;
258 uno::Reference< frame::XStorable2 > m_xStorable2;
260 OUString m_aModuleName;
261 std::unique_ptr<::comphelper::SequenceAsHashMap> m_pDocumentPropsHM;
262 std::unique_ptr<::comphelper::SequenceAsHashMap> m_pModulePropsHM;
264 ::comphelper::SequenceAsHashMap m_aMediaDescrHM;
266 bool m_bRecommendReadOnly;
268 public:
269 ModelData_Impl( SfxStoringHelper& aOwner,
270 const uno::Reference< frame::XModel >& xModel,
271 const uno::Sequence< beans::PropertyValue >& aMediaDescr );
273 ~ModelData_Impl();
275 void FreeDocumentProps();
277 uno::Reference< frame::XModel > const & GetModel() const;
278 uno::Reference< frame::XStorable > const & GetStorable();
279 uno::Reference< frame::XStorable2 > const & GetStorable2();
281 ::comphelper::SequenceAsHashMap& GetMediaDescr() { return m_aMediaDescrHM; }
283 bool IsRecommendReadOnly() const { return m_bRecommendReadOnly; }
285 const ::comphelper::SequenceAsHashMap& GetDocProps();
287 OUString const & GetModuleName();
288 const ::comphelper::SequenceAsHashMap& GetModuleProps();
290 void CheckInteractionHandler();
293 OUString GetDocServiceName();
294 uno::Sequence< beans::PropertyValue > GetDocServiceDefaultFilterCheckFlags( SfxFilterFlags nMust, SfxFilterFlags nDont );
295 uno::Sequence< beans::PropertyValue > GetDocServiceAnyFilter( SfxFilterFlags nMust, SfxFilterFlags nDont );
296 uno::Sequence< beans::PropertyValue > GetPreselectedFilter_Impl( sal_Int16 nStoreMode );
297 uno::Sequence< beans::PropertyValue > GetDocServiceDefaultFilter();
299 bool ExecuteFilterDialog_Impl( const OUString& aFilterName );
301 sal_Int8 CheckSaveAcceptable( sal_Int8 nCurStatus );
302 sal_Int8 CheckStateForSave();
304 sal_Int8 CheckFilter( const OUString& );
306 bool CheckFilterOptionsDialogExistence();
308 bool OutputFileDialog( sal_Int16 nStoreMode,
309 const ::comphelper::SequenceAsHashMap& aPreselectedFilterPropsHM,
310 bool bSetStandardName,
311 OUString& aSuggestedName,
312 bool bPreselectPassword,
313 OUString& aSuggestedDir,
314 sal_Int16 nDialog,
315 const OUString& rStandardDir,
316 const css::uno::Sequence< OUString >& rDenyList
319 bool ShowDocumentInfoDialog(const std::function< void () >&);
321 static OUString GetRecommendedExtension( const OUString& aTypeName );
322 OUString GetRecommendedDir( const OUString& aSuggestedDir );
323 OUString GetRecommendedName( const OUString& aSuggestedName,
324 const OUString& aTypeName );
329 ModelData_Impl::ModelData_Impl( SfxStoringHelper& aOwner,
330 const uno::Reference< frame::XModel >& xModel,
331 const uno::Sequence< beans::PropertyValue >& aMediaDescr )
332 : m_pOwner( &aOwner )
333 , m_xModel( xModel )
334 , m_aMediaDescrHM( aMediaDescr )
335 , m_bRecommendReadOnly( false )
337 CheckInteractionHandler();
341 ModelData_Impl::~ModelData_Impl()
343 FreeDocumentProps();
344 m_pDocumentPropsHM.reset();
345 m_pModulePropsHM.reset();
349 void ModelData_Impl::FreeDocumentProps()
351 m_pDocumentPropsHM.reset();
355 uno::Reference< frame::XModel > const & ModelData_Impl::GetModel() const
357 if ( !m_xModel.is() )
358 throw uno::RuntimeException();
360 return m_xModel;
364 uno::Reference< frame::XStorable > const & ModelData_Impl::GetStorable()
366 if ( !m_xStorable.is() )
368 m_xStorable.set( m_xModel, uno::UNO_QUERY_THROW );
371 return m_xStorable;
375 uno::Reference< frame::XStorable2 > const & ModelData_Impl::GetStorable2()
377 if ( !m_xStorable2.is() )
379 m_xStorable2.set( m_xModel, uno::UNO_QUERY_THROW );
382 return m_xStorable2;
386 const ::comphelper::SequenceAsHashMap& ModelData_Impl::GetDocProps()
388 if ( !m_pDocumentPropsHM )
389 m_pDocumentPropsHM.reset( new ::comphelper::SequenceAsHashMap( GetModel()->getArgs() ) );
391 return *m_pDocumentPropsHM;
395 OUString const & ModelData_Impl::GetModuleName()
397 if ( m_aModuleName.isEmpty() )
399 m_aModuleName = m_pOwner->GetModuleManager()->identify(
400 uno::Reference< uno::XInterface >( m_xModel, uno::UNO_QUERY ) );
401 if ( m_aModuleName.isEmpty() )
402 throw uno::RuntimeException(); // TODO:
404 return m_aModuleName;
408 const ::comphelper::SequenceAsHashMap& ModelData_Impl::GetModuleProps()
410 if ( !m_pModulePropsHM )
412 uno::Sequence< beans::PropertyValue > aModuleProps;
413 m_pOwner->GetModuleManager()->getByName( GetModuleName() ) >>= aModuleProps;
414 if ( !aModuleProps.hasElements() )
415 throw uno::RuntimeException(); // TODO;
416 m_pModulePropsHM.reset( new ::comphelper::SequenceAsHashMap( aModuleProps ) );
419 return *m_pModulePropsHM;
423 OUString ModelData_Impl::GetDocServiceName()
425 return GetModuleProps().getUnpackedValueOrDefault("ooSetupFactoryDocumentService", OUString());
429 void ModelData_Impl::CheckInteractionHandler()
431 const OUString sInteractionHandler {"InteractionHandler"};
432 ::comphelper::SequenceAsHashMap::const_iterator aInteractIter =
433 m_aMediaDescrHM.find( sInteractionHandler );
435 if ( aInteractIter == m_aMediaDescrHM.end() )
437 try {
438 m_aMediaDescrHM[ sInteractionHandler ]
439 <<= task::InteractionHandler::createWithParent( comphelper::getProcessComponentContext(), nullptr);
441 catch( const uno::Exception& )
445 else
447 uno::Reference< task::XInteractionHandler > xInteract;
448 DBG_ASSERT( ( aInteractIter->second >>= xInteract ) && xInteract.is(), "Broken interaction handler is provided!\n" );
453 uno::Sequence< beans::PropertyValue > ModelData_Impl::GetDocServiceDefaultFilter()
455 uno::Sequence< beans::PropertyValue > aProps;
457 const OUString aFilterName = GetModuleProps().getUnpackedValueOrDefault( "ooSetupFactoryDefaultFilter", OUString() );
459 m_pOwner->GetFilterConfiguration()->getByName( aFilterName ) >>= aProps;
461 return aProps;
465 uno::Sequence< beans::PropertyValue > ModelData_Impl::GetDocServiceDefaultFilterCheckFlags( SfxFilterFlags nMust,
466 SfxFilterFlags nDont )
468 uno::Sequence< beans::PropertyValue > aFilterProps;
469 uno::Sequence< beans::PropertyValue > aProps = GetDocServiceDefaultFilter();
470 if ( aProps.hasElements() )
472 ::comphelper::SequenceAsHashMap aFiltHM( aProps );
473 SfxFilterFlags nFlags = static_cast<SfxFilterFlags>(aFiltHM.getUnpackedValueOrDefault("Flags",
474 sal_Int32(0) ));
475 if ( ( ( nFlags & nMust ) == nMust ) && !( nFlags & nDont ) )
476 aFilterProps = aProps;
479 return aFilterProps;
483 uno::Sequence< beans::PropertyValue > ModelData_Impl::GetDocServiceAnyFilter( SfxFilterFlags nMust, SfxFilterFlags nDont )
485 uno::Sequence< beans::NamedValue > aSearchRequest { { "DocumentService", css::uno::makeAny(GetDocServiceName()) } };
487 return ::comphelper::MimeConfigurationHelper::SearchForFilter( m_pOwner->GetFilterQuery(), aSearchRequest, nMust, nDont );
491 uno::Sequence< beans::PropertyValue > ModelData_Impl::GetPreselectedFilter_Impl( sal_Int16 nStoreMode )
493 if ( nStoreMode == SAVEASREMOTE_REQUESTED )
494 nStoreMode = SAVEAS_REQUESTED;
496 uno::Sequence< beans::PropertyValue > aFilterProps;
498 SfxFilterFlags nMust = getMustFlags( nStoreMode );
499 SfxFilterFlags nDont = getDontFlags( nStoreMode );
501 if ( ( nStoreMode != SAVEASREMOTE_REQUESTED ) && ( nStoreMode & PDFEXPORT_REQUESTED ) )
503 // Preselect PDF-Filter for EXPORT
504 uno::Sequence< beans::NamedValue > aSearchRequest
506 { "Type", css::uno::makeAny(OUString("pdf_Portable_Document_Format")) },
507 { "DocumentService", css::uno::makeAny(GetDocServiceName()) }
510 aFilterProps = ::comphelper::MimeConfigurationHelper::SearchForFilter( m_pOwner->GetFilterQuery(), aSearchRequest, nMust, nDont );
512 else if ( ( nStoreMode != SAVEASREMOTE_REQUESTED ) && ( nStoreMode & EPUBEXPORT_REQUESTED ) )
514 // Preselect EPUB filter for export.
515 uno::Sequence<beans::NamedValue> aSearchRequest
517 { "Type", css::uno::makeAny(OUString("writer_EPUB_Document")) },
518 { "DocumentService", css::uno::makeAny(GetDocServiceName()) }
521 aFilterProps = ::comphelper::MimeConfigurationHelper::SearchForFilter( m_pOwner->GetFilterQuery(), aSearchRequest, nMust, nDont );
523 else
525 aFilterProps = GetDocServiceDefaultFilterCheckFlags( nMust, nDont );
527 if ( !aFilterProps.hasElements() )
529 // the default filter was not found, use just the first acceptable one
530 aFilterProps = GetDocServiceAnyFilter( nMust, nDont );
534 return aFilterProps;
538 bool ModelData_Impl::ExecuteFilterDialog_Impl( const OUString& aFilterName )
540 bool bDialogUsed = false;
542 try {
543 uno::Sequence < beans::PropertyValue > aProps;
544 uno::Any aAny = m_pOwner->GetFilterConfiguration()->getByName( aFilterName );
545 if ( aAny >>= aProps )
547 auto pProp = std::find_if(aProps.begin(), aProps.end(),
548 [](const beans::PropertyValue& rProp) { return rProp.Name == "UIComponent"; });
549 if (pProp != aProps.end())
551 OUString aServiceName;
552 pProp->Value >>= aServiceName;
553 if( !aServiceName.isEmpty() )
555 uno::Sequence<uno::Any> aDialogArgs(comphelper::InitAnyPropertySequence(
557 {"ParentWindow", uno::Any(SfxStoringHelper::GetModelXWindow(m_xModel))},
558 }));
560 uno::Reference< ui::dialogs::XExecutableDialog > xFilterDialog(
561 comphelper::getProcessServiceFactory()->createInstanceWithArguments(aServiceName, aDialogArgs), uno::UNO_QUERY );
562 uno::Reference< beans::XPropertyAccess > xFilterProperties( xFilterDialog, uno::UNO_QUERY );
564 if( xFilterDialog.is() && xFilterProperties.is() )
566 bDialogUsed = true;
568 uno::Reference< document::XExporter > xExporter( xFilterDialog, uno::UNO_QUERY );
569 if( xExporter.is() )
570 xExporter->setSourceDocument( GetModel() );
572 uno::Sequence< beans::PropertyValue > aPropsForDialog;
573 GetMediaDescr() >> aPropsForDialog;
574 xFilterProperties->setPropertyValues( aPropsForDialog );
576 if( !xFilterDialog->execute() )
578 throw task::ErrorCodeIOException(
579 ("ModelData_Impl::ExecuteFilterDialog_Impl:"
580 " ERRCODE_IO_ABORT"),
581 uno::Reference< uno::XInterface >(),
582 sal_uInt32(ERRCODE_IO_ABORT));
585 const uno::Sequence< beans::PropertyValue > aPropsFromDialog =
586 xFilterProperties->getPropertyValues();
587 for ( const auto& rProp : aPropsFromDialog )
588 GetMediaDescr()[rProp.Name] = rProp.Value;
594 catch( const container::NoSuchElementException& e )
596 // the filter name is unknown
597 throw task::ErrorCodeIOException(
598 ("ModelData_Impl::ExecuteFilterDialog_Impl: NoSuchElementException"
599 " \"" + e.Message + "\": ERRCODE_IO_ABORT"),
600 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER));
602 catch( const task::ErrorCodeIOException& )
604 throw;
606 catch( const uno::Exception& )
608 TOOLS_WARN_EXCEPTION("sfx.doc", "ignoring");
611 return bDialogUsed;
615 sal_Int8 ModelData_Impl::CheckSaveAcceptable( sal_Int8 nCurStatus )
617 sal_Int8 nResult = nCurStatus;
619 if ( nResult != STATUS_NO_ACTION && GetStorable()->hasLocation() )
621 // the saving is acceptable
622 // in case the configuration entry is not set or set to false
623 // or in case of version creation
624 if ( officecfg::Office::Common::Save::Document::AlwaysSaveAs::get()
625 && GetMediaDescr().find( OUString("VersionComment") ) == GetMediaDescr().end() )
627 // notify the user that SaveAs is going to be done
628 std::unique_ptr<weld::MessageDialog> xMessageBox(Application::CreateMessageDialog(SfxStoringHelper::GetModelWindow(m_xModel),
629 VclMessageType::Question, VclButtonsType::OkCancel, SfxResId(STR_NEW_FILENAME_SAVE)));
630 if (xMessageBox->run() == RET_OK)
631 nResult = STATUS_SAVEAS;
632 else
633 nResult = STATUS_NO_ACTION;
637 return nResult;
641 sal_Int8 ModelData_Impl::CheckStateForSave()
643 // if the document is readonly or a new one a SaveAs operation must be used
644 if ( !GetStorable()->hasLocation() || GetStorable()->isReadonly() )
645 return STATUS_SAVEAS;
647 // check acceptable entries for media descriptor
648 ::comphelper::SequenceAsHashMap aAcceptedArgs;
650 const OUString aVersionCommentString("VersionComment");
651 const OUString aAuthorString("Author");
652 const OUString aDontTerminateEdit("DontTerminateEdit");
653 const OUString aInteractionHandlerString("InteractionHandler");
654 const OUString aStatusIndicatorString("StatusIndicator");
655 const OUString aFailOnWarningString("FailOnWarning");
656 const OUString aNoFileSync("NoFileSync");
658 if ( GetMediaDescr().find( aVersionCommentString ) != GetMediaDescr().end() )
659 aAcceptedArgs[ aVersionCommentString ] = GetMediaDescr()[ aVersionCommentString ];
660 if ( GetMediaDescr().find( aAuthorString ) != GetMediaDescr().end() )
661 aAcceptedArgs[ aAuthorString ] = GetMediaDescr()[ aAuthorString ];
662 if ( GetMediaDescr().find( aDontTerminateEdit ) != GetMediaDescr().end() )
663 aAcceptedArgs[ aDontTerminateEdit ] = GetMediaDescr()[ aDontTerminateEdit ];
664 if ( GetMediaDescr().find( aInteractionHandlerString ) != GetMediaDescr().end() )
665 aAcceptedArgs[ aInteractionHandlerString ] = GetMediaDescr()[ aInteractionHandlerString ];
666 if ( GetMediaDescr().find( aStatusIndicatorString ) != GetMediaDescr().end() )
667 aAcceptedArgs[ aStatusIndicatorString ] = GetMediaDescr()[ aStatusIndicatorString ];
668 if ( GetMediaDescr().find( aFailOnWarningString ) != GetMediaDescr().end() )
669 aAcceptedArgs[ aFailOnWarningString ] = GetMediaDescr()[ aFailOnWarningString ];
670 if (GetMediaDescr().find(aNoFileSync) != GetMediaDescr().end())
671 aAcceptedArgs[aNoFileSync] = GetMediaDescr()[aNoFileSync];
673 // remove unacceptable entry if there is any
674 DBG_ASSERT( GetMediaDescr().size() == aAcceptedArgs.size(),
675 "Unacceptable parameters are provided in Save request!\n" );
676 if ( GetMediaDescr().size() != aAcceptedArgs.size() )
677 GetMediaDescr() = aAcceptedArgs;
679 // check that the old filter is acceptable
680 return CheckFilter( GetDocProps().getUnpackedValueOrDefault(aFilterNameString, OUString()) );
683 sal_Int8 ModelData_Impl::CheckFilter( const OUString& aFilterName )
685 ::comphelper::SequenceAsHashMap aFiltPropsHM;
686 SfxFilterFlags nFiltFlags = SfxFilterFlags::NONE;
687 if ( !aFilterName.isEmpty() )
689 // get properties of filter
690 uno::Sequence< beans::PropertyValue > aFilterProps;
691 m_pOwner->GetFilterConfiguration()->getByName( aFilterName ) >>= aFilterProps;
693 aFiltPropsHM = ::comphelper::SequenceAsHashMap( aFilterProps );
694 nFiltFlags = static_cast<SfxFilterFlags>(aFiltPropsHM.getUnpackedValueOrDefault("Flags", sal_Int32(0) ));
697 // only a temporary solution until default filter retrieving feature is implemented
698 // then GetDocServiceDefaultFilter() must be used
699 ::comphelper::SequenceAsHashMap aDefFiltPropsHM = GetDocServiceDefaultFilterCheckFlags( SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT, SfxFilterFlags::NONE );
700 SfxFilterFlags nDefFiltFlags = static_cast<SfxFilterFlags>(aDefFiltPropsHM.getUnpackedValueOrDefault("Flags", sal_Int32(0) ));
702 bool bAsk = false;
704 // if the old filter is not acceptable
705 // and there is no default filter or it is not acceptable for requested parameters then proceed with saveAs
706 if ( ( aFiltPropsHM.empty() || !( nFiltFlags & SfxFilterFlags::EXPORT ) )
707 && ( aDefFiltPropsHM.empty() || !( nDefFiltFlags & SfxFilterFlags::EXPORT ) || nDefFiltFlags & SfxFilterFlags::INTERNAL ) )
708 return STATUS_SAVEAS;
710 // so at this point there is either an acceptable old filter or default one
711 if ( aFiltPropsHM.empty() || !( nFiltFlags & SfxFilterFlags::EXPORT ) )
713 // so the default filter must be acceptable
714 return STATUS_SAVEAS_STANDARDNAME;
716 else if ( ( !( nFiltFlags & SfxFilterFlags::OWN ) || ( nFiltFlags & SfxFilterFlags::ALIEN ) )
717 && !aDefFiltPropsHM.empty()
718 && ( nDefFiltFlags & SfxFilterFlags::EXPORT ) && !( nDefFiltFlags & SfxFilterFlags::INTERNAL ))
720 bAsk = true;
723 // check if EncryptionData supports this output format
725 OUString aSupportedFilters;
726 const ::comphelper::SequenceAsHashMap& rDocumentProperties = GetDocProps();
727 const css::uno::Sequence<css::beans::NamedValue> aEncryptionData = rDocumentProperties.getUnpackedValueOrDefault("EncryptionData", css::uno::Sequence<css::beans::NamedValue>());
728 if (aEncryptionData != css::uno::Sequence<css::beans::NamedValue>())
730 for (const css::beans::NamedValue& aNamedValue : aEncryptionData)
732 if (aNamedValue.Name == "SupportedFilters")
734 aNamedValue.Value >>= aSupportedFilters;
739 // if 'SupportedFilters' is empty assume that all filters are supported.
740 if (!aSupportedFilters.isEmpty())
742 const OUString aSelectedFilter = aFiltPropsHM.getUnpackedValueOrDefault("UIName", OUString());
744 aSupportedFilters = ";" + aSupportedFilters + ";";
745 const OUString aSearchToken = ";" + aSelectedFilter + ";";
746 bAsk = (aSupportedFilters.indexOf(aSearchToken) < 0);
750 if (bAsk)
752 // the default filter is acceptable and the old filter is alien one
753 // so ask to make a saveAs operation
754 const OUString aUIName = aFiltPropsHM.getUnpackedValueOrDefault("UIName", OUString() );
755 const OUString aDefUIName = aDefFiltPropsHM.getUnpackedValueOrDefault("UIName", OUString() );
756 const OUString aPreusedFilterName = GetDocProps().getUnpackedValueOrDefault("PreusedFilterName", OUString() );
757 const OUString aDefType = aDefFiltPropsHM.getUnpackedValueOrDefault( "Type", OUString() );
758 const OUString aDefExtension = GetRecommendedExtension( aDefType );
760 if ( aPreusedFilterName != aFilterName && aUIName != aDefUIName )
762 if ( !SfxStoringHelper::WarnUnacceptableFormat( GetModel(), aUIName, aDefExtension,
763 static_cast<bool>( nDefFiltFlags & SfxFilterFlags::ALIEN ) ) )
764 return STATUS_SAVEAS_STANDARDNAME;
768 return STATUS_SAVE;
772 bool ModelData_Impl::CheckFilterOptionsDialogExistence()
774 uno::Sequence< beans::NamedValue > aSearchRequest { { "DocumentService", css::uno::makeAny(GetDocServiceName()) } };
776 uno::Reference< container::XEnumeration > xFilterEnum =
777 m_pOwner->GetFilterQuery()->createSubSetEnumerationByProperties( aSearchRequest );
779 while ( xFilterEnum->hasMoreElements() )
781 uno::Sequence< beans::PropertyValue > aProps;
782 if ( xFilterEnum->nextElement() >>= aProps )
784 ::comphelper::SequenceAsHashMap aPropsHM( aProps );
785 if ( !aPropsHM.getUnpackedValueOrDefault("UIComponent", OUString()).isEmpty() )
786 return true;
790 return false;
794 bool ModelData_Impl::OutputFileDialog( sal_Int16 nStoreMode,
795 const ::comphelper::SequenceAsHashMap& aPreselectedFilterPropsHM,
796 bool bSetStandardName,
797 OUString& aSuggestedName,
798 bool bPreselectPassword,
799 OUString& aSuggestedDir,
800 sal_Int16 nDialog,
801 const OUString& rStandardDir,
802 const css::uno::Sequence< OUString >& rDenyList)
804 if ( nStoreMode == SAVEASREMOTE_REQUESTED )
805 nStoreMode = SAVEAS_REQUESTED;
807 bool bUseFilterOptions = false;
809 ::comphelper::SequenceAsHashMap::const_iterator aOverwriteIter =
810 GetMediaDescr().find( OUString("Overwrite") );
812 // the file name must be specified if overwrite option is set
813 if ( aOverwriteIter != GetMediaDescr().end() )
814 throw task::ErrorCodeIOException(
815 "ModelData_Impl::OutputFileDialog: ERRCODE_IO_INVALIDPARAMETER",
816 uno::Reference< uno::XInterface >(),
817 sal_uInt32(ERRCODE_IO_INVALIDPARAMETER));
819 // no target file name is specified
820 // we need to show the file dialog
822 // check if we have a filter which allows for filter options, so we need a corresponding checkbox in the dialog
823 bool bAllowOptions = false;
825 // in case of Export, filter options dialog is used if available
826 if( !( nStoreMode & EXPORT_REQUESTED ) || ( nStoreMode & WIDEEXPORT_REQUESTED ) )
827 bAllowOptions = CheckFilterOptionsDialogExistence();
829 // get the filename by dialog ...
830 // create the file dialog
831 sal_Int16 aDialogMode = bAllowOptions
832 ? css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS
833 : css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD;
834 FileDialogFlags aDialogFlags = FileDialogFlags::NONE;
836 if( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) )
838 if ( (nStoreMode & PDFEXPORT_REQUESTED) || (nStoreMode & EPUBEXPORT_REQUESTED) )
839 aDialogMode = css::ui::dialogs::TemplateDescription::
840 FILESAVE_AUTOEXTENSION;
841 else
842 aDialogMode = css::ui::dialogs::TemplateDescription::
843 FILESAVE_AUTOEXTENSION_SELECTION;
844 aDialogFlags = FileDialogFlags::Export;
847 if( ( nStoreMode & EXPORT_REQUESTED ) && ( nStoreMode & SAVEACOPY_REQUESTED ) && ( nStoreMode & WIDEEXPORT_REQUESTED ) )
849 aDialogFlags = FileDialogFlags::SaveACopy;
852 std::unique_ptr<sfx2::FileDialogHelper> pFileDlg;
854 const OUString aDocServiceName {GetDocServiceName()};
855 DBG_ASSERT( !aDocServiceName.isEmpty(), "No document service for this module set!" );
857 SfxFilterFlags nMust = getMustFlags( nStoreMode );
858 SfxFilterFlags nDont = getDontFlags( nStoreMode );
859 weld::Window* pFrameWin = SfxStoringHelper::GetModelWindow(m_xModel);
860 if ( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) )
862 if ( ( nStoreMode & PDFEXPORT_REQUESTED ) && !aPreselectedFilterPropsHM.empty() )
864 // this is a PDF export
865 // the filter options has been shown already
866 const OUString aFilterUIName = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( "UIName", OUString() );
867 pFileDlg.reset(new sfx2::FileDialogHelper( aDialogMode, aDialogFlags, aFilterUIName, "pdf", rStandardDir, rDenyList, pFrameWin ));
868 pFileDlg->SetCurrentFilter( aFilterUIName );
870 else if ((nStoreMode & EPUBEXPORT_REQUESTED) && !aPreselectedFilterPropsHM.empty())
872 // This is an EPUB export, the filter options has been shown already.
873 const OUString aFilterUIName = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( "UIName", OUString() );
874 pFileDlg.reset(new sfx2::FileDialogHelper(aDialogMode, aDialogFlags, aFilterUIName, "epub", rStandardDir, rDenyList, pFrameWin));
875 pFileDlg->SetCurrentFilter(aFilterUIName);
877 else
879 // This is the normal dialog
880 pFileDlg.reset(new sfx2::FileDialogHelper( aDialogMode, aDialogFlags, aDocServiceName, nDialog, nMust, nDont, rStandardDir, rDenyList, pFrameWin ));
883 sfx2::FileDialogHelper::Context eCtxt = sfx2::FileDialogHelper::UNKNOWN_CONTEXT;
884 if ( aDocServiceName == "com.sun.star.drawing.DrawingDocument" )
885 eCtxt = sfx2::FileDialogHelper::SD_EXPORT;
886 else if ( aDocServiceName == "com.sun.star.presentation.PresentationDocument" )
887 eCtxt = sfx2::FileDialogHelper::SI_EXPORT;
888 else if ( aDocServiceName == "com.sun.star.text.TextDocument" )
889 eCtxt = sfx2::FileDialogHelper::SW_EXPORT;
891 if ( eCtxt != sfx2::FileDialogHelper::UNKNOWN_CONTEXT )
892 pFileDlg->SetContext( eCtxt );
894 pFileDlg->CreateMatcher( aDocServiceName );
896 uno::Reference< ui::dialogs::XFilePicker3 > xFilePicker = pFileDlg->GetFilePicker();
897 uno::Reference< ui::dialogs::XFilePickerControlAccess > xControlAccess( xFilePicker, uno::UNO_QUERY );
899 if ( xControlAccess.is() )
901 xControlAccess->setLabel( ui::dialogs::CommonFilePickerElementIds::PUSHBUTTON_OK, SfxResId(STR_EXPORTBUTTON) );
902 xControlAccess->setLabel( ui::dialogs::CommonFilePickerElementIds::LISTBOX_FILTER_LABEL, SfxResId(STR_LABEL_FILEFORMAT) );
905 else
907 // This is the normal dialog
908 pFileDlg.reset(new sfx2::FileDialogHelper( aDialogMode, aDialogFlags, aDocServiceName, nDialog,
909 nMust, nDont, rStandardDir, rDenyList, pFrameWin ));
910 pFileDlg->CreateMatcher( aDocServiceName );
913 OUString aAdjustToType;
915 const OUString sFilterNameString(aFilterNameString);
917 if ( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) )
919 // it is export, set the preselected filter
920 pFileDlg->SetCurrentFilter( aPreselectedFilterPropsHM.getUnpackedValueOrDefault( "UIName", OUString() ) );
921 aAdjustToType = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( "Type", OUString() );
923 // it is no export, bSetStandardName == true means that user agreed to store document in the default (default default ;-)) format
924 else if ( bSetStandardName || GetStorable()->hasLocation() )
926 uno::Sequence< beans::PropertyValue > aOldFilterProps;
927 const OUString aOldFilterName = GetDocProps().getUnpackedValueOrDefault( sFilterNameString, OUString() );
929 if ( !aOldFilterName.isEmpty() )
930 m_pOwner->GetFilterConfiguration()->getByName( aOldFilterName ) >>= aOldFilterProps;
932 ::comphelper::SequenceAsHashMap aOldFiltPropsHM( aOldFilterProps );
933 SfxFilterFlags nOldFiltFlags = static_cast<SfxFilterFlags>(aOldFiltPropsHM.getUnpackedValueOrDefault("Flags", sal_Int32(0) ));
935 if ( bSetStandardName || ( nOldFiltFlags & nMust ) != nMust || bool(nOldFiltFlags & nDont) )
937 // the suggested type will be changed, the extension should be adjusted
938 aAdjustToType = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( "Type", OUString() );
939 pFileDlg->SetCurrentFilter( aPreselectedFilterPropsHM.getUnpackedValueOrDefault( "UIName", OUString() ) );
941 else
943 pFileDlg->SetCurrentFilter( aOldFiltPropsHM.getUnpackedValueOrDefault(
944 "UIName",
945 OUString() ) );
949 const OUString aRecommendedDir {GetRecommendedDir( aSuggestedDir )};
950 if ( !aRecommendedDir.isEmpty() )
951 pFileDlg->SetDisplayFolder( aRecommendedDir );
952 const OUString aRecommendedName {GetRecommendedName( aSuggestedName, aAdjustToType )};
953 if ( !aRecommendedName.isEmpty() )
954 pFileDlg->SetFileName( aRecommendedName );
956 uno::Reference < view::XSelectionSupplier > xSel( GetModel()->getCurrentController(), uno::UNO_QUERY );
957 if ( xSel.is() && xSel->getSelection().hasValue() )
958 GetMediaDescr()[OUString("SelectionOnly")] <<= true;
960 // This is a temporary hardcoded solution must be removed when
961 // dialogs do not need parameters in SidSet representation any more
962 sal_uInt16 nSlotID = getSlotIDFromMode( nStoreMode );
963 if ( !nSlotID )
964 throw lang::IllegalArgumentException(); // TODO:
966 // generate SidSet from MediaDescriptor and provide it into FileDialog
967 // than merge changed SidSet back
968 std::unique_ptr<SfxItemSet> pDialogParams(new SfxAllItemSet( SfxGetpApp()->GetPool() ));
969 TransformParameters( nSlotID,
970 GetMediaDescr().getAsConstPropertyValueList(),
971 static_cast<SfxAllItemSet&>(*pDialogParams) );
973 const SfxPoolItem* pItem = nullptr;
974 if ( bPreselectPassword && pDialogParams->GetItemState( SID_ENCRYPTIONDATA, true, &pItem ) != SfxItemState::SET )
976 // the file dialog preselects the password checkbox if the provided mediadescriptor has encryption data entry
977 // after dialog execution the password interaction flag will be either removed or not
978 pDialogParams->Put( SfxBoolItem( SID_PASSWORDINTERACTION, true ) );
981 // aFilterName is a pure output parameter, pDialogParams is an in/out parameter
982 OUString aFilterName;
983 if ( pFileDlg->Execute( pDialogParams, aFilterName ) != ERRCODE_NONE )
985 throw task::ErrorCodeIOException(
986 "ModelData_Impl::OutputFileDialog: ERRCODE_IO_ABORT",
987 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT));
990 // the following two arguments can not be converted in MediaDescriptor,
991 // so they should be removed from the ItemSet after retrieving
992 const SfxBoolItem* pRecommendReadOnly = SfxItemSet::GetItem<SfxBoolItem>(pDialogParams.get(), SID_RECOMMENDREADONLY, false);
993 m_bRecommendReadOnly = ( pRecommendReadOnly && pRecommendReadOnly->GetValue() );
994 pDialogParams->ClearItem( SID_RECOMMENDREADONLY );
996 uno::Sequence< beans::PropertyValue > aPropsFromDialog;
997 TransformItems( nSlotID, *pDialogParams, aPropsFromDialog );
998 GetMediaDescr() << aPropsFromDialog;
1000 // get the path from the dialog
1001 INetURLObject aURL( pFileDlg->GetPath() );
1002 // the path should be provided outside since it might be used for further calls to the dialog
1003 aSuggestedName = aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset);
1004 aSuggestedDir = pFileDlg->GetDisplayDirectory();
1006 // old filter options should be cleared in case different filter is used
1008 const OUString aFilterFromMediaDescr = GetMediaDescr().getUnpackedValueOrDefault( sFilterNameString, OUString() );
1009 const OUString aOldFilterName = GetDocProps().getUnpackedValueOrDefault( sFilterNameString, OUString() );
1011 const OUString sFilterOptionsString(aFilterOptionsString);
1012 const OUString sFilterDataString(aFilterDataString);
1014 if ( aFilterName == aFilterFromMediaDescr )
1016 // preserve current settings if any
1017 // if there no current settings and the name is the same
1018 // as old filter name use old filter settings
1020 if ( aFilterFromMediaDescr == aOldFilterName )
1022 ::comphelper::SequenceAsHashMap::const_iterator aIter =
1023 GetDocProps().find( sFilterOptionsString );
1024 if ( aIter != GetDocProps().end()
1025 && GetMediaDescr().find( sFilterOptionsString ) == GetMediaDescr().end() )
1026 GetMediaDescr()[aIter->first] = aIter->second;
1028 aIter = GetDocProps().find( sFilterDataString );
1029 if ( aIter != GetDocProps().end()
1030 && GetMediaDescr().find( sFilterDataString ) == GetMediaDescr().end() )
1031 GetMediaDescr()[aIter->first] = aIter->second;
1034 else
1036 GetMediaDescr().erase( sFilterDataString );
1037 GetMediaDescr().erase( sFilterOptionsString );
1039 if ( aFilterName == aOldFilterName )
1041 // merge filter option of the document filter
1043 ::comphelper::SequenceAsHashMap::const_iterator aIter =
1044 GetDocProps().find( sFilterOptionsString );
1045 if ( aIter != GetDocProps().end() )
1046 GetMediaDescr()[aIter->first] = aIter->second;
1048 aIter = GetDocProps().find( sFilterDataString );
1049 if ( aIter != GetDocProps().end() )
1050 GetMediaDescr()[aIter->first] = aIter->second;
1054 uno::Reference< ui::dialogs::XFilePickerControlAccess > xExtFileDlg( pFileDlg->GetFilePicker(), uno::UNO_QUERY );
1055 if ( xExtFileDlg.is() )
1057 if ( SfxStoringHelper::CheckFilterOptionsAppearance( m_pOwner->GetFilterConfiguration(), aFilterName ) )
1058 bUseFilterOptions = true;
1060 if ( ( !( nStoreMode & EXPORT_REQUESTED ) || ( nStoreMode & WIDEEXPORT_REQUESTED ) ) && bUseFilterOptions )
1064 // for exporters: always show dialog if format uses options
1065 // for save: show dialog if format uses options and no options given or if forced by user
1066 uno::Any aVal =
1067 xExtFileDlg->getValue( ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS, 0 );
1069 aVal >>= bUseFilterOptions;
1070 if ( !bUseFilterOptions )
1071 bUseFilterOptions =
1072 ( GetMediaDescr().find( sFilterDataString ) == GetMediaDescr().end()
1073 && GetMediaDescr().find( sFilterOptionsString ) == GetMediaDescr().end() );
1075 catch( const lang::IllegalArgumentException& )
1080 // merge in results of the dialog execution
1081 GetMediaDescr()[OUString("URL")] <<= aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1082 GetMediaDescr()[sFilterNameString] <<= aFilterName;
1084 return bUseFilterOptions;
1088 bool ModelData_Impl::ShowDocumentInfoDialog(const std::function< void () >& aFunc)
1090 bool bDialogUsed = false;
1092 try {
1093 uno::Reference< frame::XController > xController = GetModel()->getCurrentController();
1094 if ( xController.is() )
1096 uno::Reference< frame::XDispatchProvider > xFrameDispatch( xController->getFrame(), uno::UNO_QUERY );
1097 if ( xFrameDispatch.is() )
1099 util::URL aURL;
1100 aURL.Complete = ".uno:SetDocumentProperties";
1102 uno::Reference < util::XURLTransformer > xTransformer( util::URLTransformer::create( comphelper::getProcessComponentContext() ) );
1103 if ( xTransformer->parseStrict( aURL ) )
1105 uno::Reference< frame::XDispatch > xDispatch = xFrameDispatch->queryDispatch(
1106 aURL,
1107 "_self",
1108 0 );
1109 if ( xDispatch.is() )
1111 uno::Sequence< beans::PropertyValue > aProperties(1);
1112 uno::Reference< lang::XUnoTunnel > aAsyncFunc(new AsyncFunc(aFunc));
1113 aProperties[0].Name = "AsyncFunc";
1114 aProperties[0].Value <<= aAsyncFunc;
1115 xDispatch->dispatch( aURL, aProperties );
1116 bDialogUsed = true;
1122 catch ( const uno::Exception& )
1126 return bDialogUsed;
1130 OUString ModelData_Impl::GetRecommendedExtension( const OUString& aTypeName )
1132 if ( aTypeName.isEmpty() )
1133 return OUString();
1135 uno::Reference< container::XNameAccess > xTypeDetection(
1136 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"),
1137 uno::UNO_QUERY );
1138 if ( xTypeDetection.is() )
1140 uno::Sequence< beans::PropertyValue > aTypeNameProps;
1141 if ( ( xTypeDetection->getByName( aTypeName ) >>= aTypeNameProps ) && aTypeNameProps.hasElements() )
1143 ::comphelper::SequenceAsHashMap aTypeNamePropsHM( aTypeNameProps );
1144 uno::Sequence< OUString > aExtensions = aTypeNamePropsHM.getUnpackedValueOrDefault(
1145 "Extensions",
1146 ::uno::Sequence< OUString >() );
1147 if ( aExtensions.hasElements() )
1148 return aExtensions[0];
1152 return OUString();
1156 OUString ModelData_Impl::GetRecommendedDir( const OUString& aSuggestedDir )
1158 if ( ( !aSuggestedDir.isEmpty() || GetStorable()->hasLocation() )
1159 && !GetMediaDescr().getUnpackedValueOrDefault("RepairPackage", false ) )
1161 INetURLObject aLocation;
1162 if ( !aSuggestedDir.isEmpty() )
1163 aLocation = INetURLObject( aSuggestedDir );
1164 else
1166 const OUString aOldURL = GetStorable()->getLocation();
1167 if ( !aOldURL.isEmpty() )
1169 INetURLObject aTmp( aOldURL );
1170 if ( aTmp.removeSegment() )
1171 aLocation = aTmp;
1174 if ( aLocation.HasError() )
1175 aLocation = INetURLObject( SvtPathOptions().GetWorkPath() );
1178 OUString sLocationURL( aLocation.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1179 bool bIsInTempPath( false );
1180 OUString sSysTempPath;
1181 if( osl::FileBase::getTempDirURL( sSysTempPath ) == osl::FileBase::E_None )
1182 bIsInTempPath = !sSysTempPath.isEmpty() && sLocationURL.startsWith( sSysTempPath );
1183 #ifdef _WIN32
1184 if( !bIsInTempPath )
1186 wchar_t sPath[MAX_PATH+1];
1187 HRESULT hRes = SHGetFolderPathW( nullptr, CSIDL_INTERNET_CACHE, nullptr, SHGFP_TYPE_CURRENT, sPath );
1188 if( SUCCEEDED(hRes) )
1190 OUString sTempINetFiles;
1191 if( osl::FileBase::getFileURLFromSystemPath(OUString(o3tl::toU(sPath)), sTempINetFiles) == osl::FileBase::E_None )
1192 bIsInTempPath = !sTempINetFiles.isEmpty() && sLocationURL.startsWith( sTempINetFiles );
1195 #endif
1196 // Suggest somewhere other than the system's temp directory
1197 if( bIsInTempPath )
1198 aLocation = INetURLObject( SvtPathOptions().GetWorkPath() );
1200 aLocation.setFinalSlash();
1201 if ( !aLocation.HasError() )
1202 return aLocation.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1204 return OUString();
1207 return INetURLObject( SvtPathOptions().GetWorkPath() ).GetMainURL( INetURLObject::DecodeMechanism::NONE );
1211 OUString ModelData_Impl::GetRecommendedName( const OUString& aSuggestedName, const OUString& aTypeName )
1213 // the last used name might be provided by aSuggestedName from the old selection, or from the MediaDescriptor
1214 if ( !aSuggestedName.isEmpty() )
1215 return aSuggestedName;
1217 OUString aRecommendedName{ INetURLObject(GetStorable()->getLocation())
1218 .GetLastName(INetURLObject::DecodeMechanism::WithCharset) };
1219 if ( aRecommendedName.isEmpty() )
1221 try {
1222 uno::Reference< frame::XTitle > xTitle( GetModel(), uno::UNO_QUERY_THROW );
1223 aRecommendedName = xTitle->getTitle();
1224 } catch( const uno::Exception& ) {}
1227 if ( !aRecommendedName.isEmpty() && !aTypeName.isEmpty() )
1229 // adjust the extension to the type
1230 uno::Reference< container::XNameAccess > xTypeDetection(
1231 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"),
1232 uno::UNO_QUERY );
1233 if ( xTypeDetection.is() )
1235 INetURLObject aObj( "c:/" + aRecommendedName, INetProtocol::File,
1236 INetURLObject::EncodeMechanism::All, RTL_TEXTENCODING_UTF8, FSysStyle::Dos );
1238 const OUString aExtension = GetRecommendedExtension( aTypeName );
1239 if ( !aExtension.isEmpty() )
1240 aObj.SetExtension( aExtension );
1242 aRecommendedName = aObj.GetLastName(INetURLObject::DecodeMechanism::WithCharset);
1246 return aRecommendedName;
1252 SfxStoringHelper::SfxStoringHelper()
1257 uno::Reference< container::XNameAccess > const & SfxStoringHelper::GetFilterConfiguration()
1259 if ( !m_xFilterCFG.is() )
1261 m_xFilterCFG.set( comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.FilterFactory"),
1262 uno::UNO_QUERY_THROW );
1265 return m_xFilterCFG;
1269 uno::Reference< container::XContainerQuery > const & SfxStoringHelper::GetFilterQuery()
1271 if ( !m_xFilterQuery.is() )
1273 m_xFilterQuery.set( GetFilterConfiguration(), uno::UNO_QUERY_THROW );
1276 return m_xFilterQuery;
1280 uno::Reference< css::frame::XModuleManager2 > const & SfxStoringHelper::GetModuleManager()
1282 if ( !m_xModuleManager.is() )
1284 m_xModuleManager = frame::ModuleManager::create(
1285 comphelper::getProcessComponentContext() );
1288 return m_xModuleManager;
1291 namespace
1293 void LaunchPDFViewer(const INetURLObject& rURL)
1295 // Launch PDF viewer
1296 FilterConfigItem aItem( "Office.Common/Filter/PDF/Export/" );
1297 bool aViewPDF = aItem.ReadBool( "ViewPDFAfterExport", false );
1299 if ( aViewPDF )
1301 uno::Reference<XSystemShellExecute> xSystemShellExecute(SystemShellExecute::create(::comphelper::getProcessComponentContext()));
1302 xSystemShellExecute->execute(rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), "", SystemShellExecuteFlags::URIS_ONLY);
1307 bool SfxStoringHelper::GUIStoreModel( const uno::Reference< frame::XModel >& xModel,
1308 const OUString& aSlotName,
1309 uno::Sequence< beans::PropertyValue >& aArgsSequence,
1310 bool bPreselectPassword,
1311 SignatureState nDocumentSignatureState )
1313 ModelData_Impl aModelData( *this, xModel, aArgsSequence );
1315 bool bDialogUsed = false;
1317 INetURLObject aURL;
1319 bool bSetStandardName = false; // can be set only for SaveAs
1321 // parse the slot name
1322 bool bRemote = false;
1323 sal_Int16 nStoreMode = getStoreModeFromSlotName( aSlotName );
1325 if ( nStoreMode == SAVEASREMOTE_REQUESTED )
1327 nStoreMode = SAVEAS_REQUESTED;
1328 bRemote = true;
1331 sal_Int8 nStatusSave = STATUS_NO_ACTION;
1333 ::comphelper::SequenceAsHashMap::const_iterator aSaveACopyIter =
1334 aModelData.GetMediaDescr().find( OUString("SaveACopy") );
1335 if ( aSaveACopyIter != aModelData.GetMediaDescr().end() )
1337 bool bSaveACopy = false;
1338 aSaveACopyIter->second >>= bSaveACopy;
1339 if ( bSaveACopy )
1340 nStoreMode = EXPORT_REQUESTED | SAVEACOPY_REQUESTED | WIDEEXPORT_REQUESTED;
1342 // handle the special cases
1343 if ( nStoreMode & SAVEAS_REQUESTED )
1345 ::comphelper::SequenceAsHashMap::const_iterator aSaveToIter =
1346 aModelData.GetMediaDescr().find( OUString("SaveTo") );
1347 if ( aSaveToIter != aModelData.GetMediaDescr().end() )
1349 bool bWideExport = false;
1350 aSaveToIter->second >>= bWideExport;
1351 if ( bWideExport )
1352 nStoreMode = EXPORT_REQUESTED | WIDEEXPORT_REQUESTED;
1355 // if saving is not acceptable the warning must be shown even in case of SaveAs operation
1356 if ( ( nStoreMode & SAVEAS_REQUESTED ) && aModelData.CheckSaveAcceptable( STATUS_SAVEAS ) == STATUS_NO_ACTION )
1357 throw task::ErrorCodeIOException(
1358 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT",
1359 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT));
1361 else if ( nStoreMode & SAVE_REQUESTED )
1363 // if saving is not acceptable by the configuration the warning must be shown
1364 nStatusSave = aModelData.CheckSaveAcceptable( STATUS_SAVE );
1366 if ( nStatusSave == STATUS_NO_ACTION )
1367 throw task::ErrorCodeIOException(
1368 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT",
1369 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT));
1370 else if ( nStatusSave == STATUS_SAVE )
1372 // check whether it is possible to use save operation
1373 nStatusSave = aModelData.CheckStateForSave();
1376 if ( nStatusSave == STATUS_NO_ACTION )
1378 throw task::ErrorCodeIOException(
1379 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT",
1380 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT));
1382 else if ( nStatusSave != STATUS_SAVE )
1384 // this should be a usual SaveAs operation
1385 nStoreMode = SAVEAS_REQUESTED;
1386 if ( nStatusSave == STATUS_SAVEAS_STANDARDNAME )
1387 bSetStandardName = true;
1391 if (!comphelper::LibreOfficeKit::isActive() && !( nStoreMode & EXPORT_REQUESTED ) )
1393 // if it is no export, warn user that the signature will be removed
1394 if ( SignatureState::OK == nDocumentSignatureState
1395 || SignatureState::INVALID == nDocumentSignatureState
1396 || SignatureState::NOTVALIDATED == nDocumentSignatureState
1397 || SignatureState::PARTIAL_OK == nDocumentSignatureState)
1399 std::unique_ptr<weld::MessageDialog> xMessageBox(Application::CreateMessageDialog(SfxStoringHelper::GetModelWindow(xModel),
1400 VclMessageType::Question, VclButtonsType::YesNo, SfxResId(RID_SVXSTR_XMLSEC_QUERY_LOSINGSIGNATURE)));
1401 if (xMessageBox->run() != RET_YES)
1403 // the user has decided not to store the document
1404 throw task::ErrorCodeIOException(
1405 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT (Preserve Signature)",
1406 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT));
1411 if ( nStoreMode & SAVE_REQUESTED && nStatusSave == STATUS_SAVE )
1413 // Document properties can contain streams that should be freed before storing
1414 aModelData.FreeDocumentProps();
1416 if ( aModelData.GetStorable2().is() )
1420 aModelData.GetStorable2()->storeSelf( aModelData.GetMediaDescr().getAsConstPropertyValueList() );
1422 catch (const lang::IllegalArgumentException&)
1424 TOOLS_WARN_EXCEPTION("sfx.doc", "Ignoring parameters! ModelData considers this illegal");
1425 aModelData.GetStorable()->store();
1428 else
1430 OSL_FAIL( "XStorable2 is not supported by the model!" );
1431 aModelData.GetStorable()->store();
1434 return false;
1437 // preselect a filter for the storing process
1438 uno::Sequence< beans::PropertyValue > aFilterProps = aModelData.GetPreselectedFilter_Impl( nStoreMode );
1440 DBG_ASSERT( aFilterProps.hasElements(), "No filter for storing!\n" );
1441 if ( !aFilterProps.hasElements() )
1442 throw task::ErrorCodeIOException(
1443 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_INVALIDPARAMETER",
1444 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER));
1446 ::comphelper::SequenceAsHashMap aFilterPropsHM( aFilterProps );
1447 OUString aFilterName = aFilterPropsHM.getUnpackedValueOrDefault( "Name", OUString() );
1449 const OUString sFilterNameString(aFilterNameString);
1451 const OUString aFilterFromMediaDescr = aModelData.GetMediaDescr().getUnpackedValueOrDefault( sFilterNameString, OUString() );
1452 const OUString aOldFilterName = aModelData.GetDocProps().getUnpackedValueOrDefault( sFilterNameString, OUString() );
1454 bool bUseFilterOptions = false;
1455 ::comphelper::SequenceAsHashMap::const_iterator aFileNameIter = aModelData.GetMediaDescr().find( OUString("URL") );
1457 const OUString sFilterOptionsString(aFilterOptionsString);
1458 const OUString sFilterDataString(aFilterDataString);
1460 bool bPDFOptions = (nStoreMode & PDFEXPORT_REQUESTED) && !(nStoreMode & PDFDIRECTEXPORT_REQUESTED);
1461 bool bEPUBOptions = (nStoreMode & EPUBEXPORT_REQUESTED) && !(nStoreMode & EPUBDIRECTEXPORT_REQUESTED);
1462 if ( ( nStoreMode & EXPORT_REQUESTED ) && (bPDFOptions || bEPUBOptions) )
1464 // this is PDF or EPUB export, the filter options dialog should be shown before the export
1465 aModelData.GetMediaDescr()[sFilterNameString] <<= aFilterName;
1466 if ( aModelData.GetMediaDescr().find( "FilterFlags" ) == aModelData.GetMediaDescr().end()
1467 && aModelData.GetMediaDescr().find( sFilterOptionsString ) == aModelData.GetMediaDescr().end()
1468 && aModelData.GetMediaDescr().find( sFilterDataString ) == aModelData.GetMediaDescr().end() )
1470 // execute filter options dialog since no options are set in the media descriptor
1471 if ( aModelData.ExecuteFilterDialog_Impl( aFilterName ) )
1472 bDialogUsed = true;
1476 if ( aFileNameIter == aModelData.GetMediaDescr().end() )
1478 sal_Int16 nDialog = SFX2_IMPL_DIALOG_CONFIG;
1480 if( bRemote )
1482 nDialog = SFX2_IMPL_DIALOG_REMOTE;
1484 else
1486 ::comphelper::SequenceAsHashMap::const_iterator aDlgIter =
1487 aModelData.GetMediaDescr().find( OUString("UseSystemDialog") );
1488 if ( aDlgIter != aModelData.GetMediaDescr().end() )
1490 bool bUseSystemDialog = true;
1491 if ( aDlgIter->second >>= bUseSystemDialog )
1493 if ( bUseSystemDialog )
1494 nDialog = SFX2_IMPL_DIALOG_SYSTEM;
1495 else
1496 nDialog = SFX2_IMPL_DIALOG_OOO;
1501 // The Dispatch supports parameter FolderName that overwrites SuggestedSaveAsDir
1502 OUString aSuggestedDir = aModelData.GetMediaDescr().getUnpackedValueOrDefault("FolderName", OUString() );
1503 if ( aSuggestedDir.isEmpty() )
1505 aSuggestedDir = aModelData.GetMediaDescr().getUnpackedValueOrDefault("SuggestedSaveAsDir", OUString() );
1506 if ( aSuggestedDir.isEmpty() )
1507 aSuggestedDir = aModelData.GetDocProps().getUnpackedValueOrDefault("SuggestedSaveAsDir", OUString() );
1510 OUString aSuggestedName = aModelData.GetMediaDescr().getUnpackedValueOrDefault("SuggestedSaveAsName", OUString() );
1511 if ( aSuggestedName.isEmpty() )
1512 aSuggestedName = aModelData.GetDocProps().getUnpackedValueOrDefault("SuggestedSaveAsName", OUString() );
1514 OUString sStandardDir;
1515 ::comphelper::SequenceAsHashMap::const_iterator aStdDirIter =
1516 aModelData.GetMediaDescr().find( OUString("StandardDir") );
1517 if ( aStdDirIter != aModelData.GetMediaDescr().end() )
1518 aStdDirIter->second >>= sStandardDir;
1520 css::uno::Sequence< OUString > aDenyList;
1522 ::comphelper::SequenceAsHashMap::const_iterator aDenyListIter =
1523 aModelData.GetMediaDescr().find( OUString("DenyList") );
1524 if ( aDenyListIter != aModelData.GetMediaDescr().end() )
1525 aDenyListIter->second >>= aDenyList;
1527 for (;;)
1529 // 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
1530 bUseFilterOptions = aModelData.OutputFileDialog( nStoreMode, aFilterProps, bSetStandardName, aSuggestedName, bPreselectPassword, aSuggestedDir, nDialog, sStandardDir, aDenyList );
1531 if ( nStoreMode == SAVEAS_REQUESTED )
1533 // in case of saving check filter for possible alien warning
1534 const OUString aSelFilterName = aModelData.GetMediaDescr().getUnpackedValueOrDefault( sFilterNameString, OUString() );
1535 sal_Int8 nStatusFilterSave = aModelData.CheckFilter( aSelFilterName );
1536 if ( nStatusFilterSave == STATUS_SAVEAS_STANDARDNAME )
1538 // switch to best filter
1539 bSetStandardName = true;
1541 else if ( nStatusFilterSave == STATUS_SAVE )
1543 // user confirmed alien filter or "good" filter is used
1544 break;
1547 else
1548 break;
1551 bDialogUsed = true;
1552 aFileNameIter = aModelData.GetMediaDescr().find( OUString("URL") );
1554 else
1556 // the target file name is provided so check if new filter options
1557 // are provided or old options can be used
1558 if ( aFilterFromMediaDescr == aOldFilterName )
1560 ::comphelper::SequenceAsHashMap::const_iterator aIter =
1561 aModelData.GetDocProps().find( sFilterOptionsString );
1562 if ( aIter != aModelData.GetDocProps().end()
1563 && aModelData.GetMediaDescr().find( sFilterOptionsString ) == aModelData.GetMediaDescr().end() )
1564 aModelData.GetMediaDescr()[aIter->first] = aIter->second;
1566 aIter = aModelData.GetDocProps().find( sFilterDataString );
1567 if ( aIter != aModelData.GetDocProps().end()
1568 && aModelData.GetMediaDescr().find( sFilterDataString ) == aModelData.GetMediaDescr().end() )
1569 aModelData.GetMediaDescr()[aIter->first] = aIter->second;
1573 if ( aFileNameIter != aModelData.GetMediaDescr().end() )
1575 OUString aFileName;
1576 aFileNameIter->second >>= aFileName;
1577 aURL.SetURL( aFileName );
1578 DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "Illegal URL!" );
1580 ::comphelper::SequenceAsHashMap::const_iterator aIter =
1581 aModelData.GetMediaDescr().find( sFilterNameString );
1583 if ( aIter != aModelData.GetMediaDescr().end() )
1584 aIter->second >>= aFilterName;
1585 else
1586 aModelData.GetMediaDescr()[sFilterNameString] <<= aFilterName;
1588 DBG_ASSERT( !aFilterName.isEmpty(), "Illegal filter!" );
1590 else
1592 SAL_WARN( "sfx.doc", "This code must be unreachable!" );
1593 throw task::ErrorCodeIOException(
1594 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_INVALIDPARAMETER",
1595 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER));
1598 ::comphelper::SequenceAsHashMap::const_iterator aIter =
1599 aModelData.GetMediaDescr().find( OUString("FilterFlags") );
1600 bool bFilterFlagsSet = ( aIter != aModelData.GetMediaDescr().end() );
1602 // check if the filter Dialog has not been called before
1603 if( !( nStoreMode & PDFEXPORT_REQUESTED ) && !( nStoreMode & EPUBEXPORT_REQUESTED ) && !bFilterFlagsSet
1604 && ( ( nStoreMode & EXPORT_REQUESTED ) || bUseFilterOptions ) )
1606 // execute filter options dialog
1607 if ( aModelData.ExecuteFilterDialog_Impl( aFilterName ) )
1609 bDialogUsed = true;
1610 // check if the file is a pdf or not and change the storing mode at convenience
1611 if (aFilterName.endsWith("pdf_Export"))
1612 nStoreMode = EXPORT_REQUESTED | PDFEXPORT_REQUESTED;
1616 // so the arguments will not change any more and can be stored to the main location
1617 aArgsSequence = aModelData.GetMediaDescr().getAsConstPropertyValueList();
1619 // store the document and handle it's docinfo
1620 SvtSaveOptions aOptions;
1622 DocumentSettingsGuard aSettingsGuard( aModelData.GetModel(), aModelData.IsRecommendReadOnly(), nStoreMode & EXPORT_REQUESTED );
1624 OSL_ENSURE( aModelData.GetMediaDescr().find( OUString( "Password" ) ) == aModelData.GetMediaDescr().end(), "The Password property of MediaDescriptor should not be used here!" );
1625 if ( aOptions.IsDocInfoSave()
1626 && ( !aModelData.GetStorable()->hasLocation()
1627 || INetURLObject( aModelData.GetStorable()->getLocation() ) != aURL ) )
1629 // this is definitely not a Save operation
1630 // so the document info can be updated
1632 // on export document info must be preserved
1633 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1634 aModelData.GetModel(), uno::UNO_QUERY_THROW);
1635 uno::Reference<util::XCloneable> xCloneable(
1636 xDPS->getDocumentProperties(), uno::UNO_QUERY_THROW);
1637 uno::Reference<document::XDocumentProperties> xOldDocProps(
1638 xCloneable->createClone(), uno::UNO_QUERY_THROW);
1640 std::function< void () > aFunc = [xModel, xOldDocProps, nStoreMode, aURL, aArgsSequence]() {
1641 SfxStoringHelper aStoringHelper;
1642 ModelData_Impl aModel(aStoringHelper, xModel, aArgsSequence );
1646 if ( nStoreMode & EXPORT_REQUESTED )
1647 aModel.GetStorable()->storeToURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aArgsSequence );
1648 else
1649 aModel.GetStorable()->storeAsURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aArgsSequence );
1651 catch( const uno::Exception& )
1655 if ( nStoreMode & EXPORT_REQUESTED )
1657 SfxStoringHelper::SetDocInfoState(aModel.GetModel(), xOldDocProps);
1660 // Launch PDF viewer
1661 if (nStoreMode & PDFEXPORT_REQUESTED)
1662 LaunchPDFViewer(aURL);
1666 // use dispatch API to show document info dialog
1667 if ( aModelData.ShowDocumentInfoDialog(aFunc) )
1668 bDialogUsed = true;
1669 else
1671 OSL_FAIL( "Can't execute document info dialog!" );
1674 else
1676 // Document properties can contain streams that should be freed before storing
1677 aModelData.FreeDocumentProps();
1679 // this is actually a save operation with different parameters
1680 // so storeTo or storeAs without DocInfo operations are used
1681 if ( nStoreMode & EXPORT_REQUESTED )
1682 aModelData.GetStorable()->storeToURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aArgsSequence );
1683 else
1684 aModelData.GetStorable()->storeAsURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aArgsSequence );
1686 // Launch PDF viewer
1687 if (nStoreMode & PDFEXPORT_REQUESTED)
1688 LaunchPDFViewer(aURL);
1691 return bDialogUsed;
1695 // static
1696 bool SfxStoringHelper::CheckFilterOptionsAppearance(
1697 const uno::Reference< container::XNameAccess >& xFilterCFG,
1698 const OUString& aFilterName )
1700 bool bUseFilterOptions = false;
1702 DBG_ASSERT( xFilterCFG.is(), "No filter configuration!\n" );
1703 if( xFilterCFG.is() )
1705 try {
1706 uno::Sequence < beans::PropertyValue > aProps;
1707 uno::Any aAny = xFilterCFG->getByName( aFilterName );
1708 if ( aAny >>= aProps )
1710 ::comphelper::SequenceAsHashMap aPropsHM( aProps );
1711 if( !aPropsHM.getUnpackedValueOrDefault( "UIComponent", OUString() ).isEmpty() )
1712 bUseFilterOptions = true;
1715 catch( const uno::Exception& )
1720 return bUseFilterOptions;
1724 // static
1725 void SfxStoringHelper::SetDocInfoState(
1726 const uno::Reference< frame::XModel >& xModel,
1727 const uno::Reference< document::XDocumentProperties>& i_xOldDocProps )
1729 uno::Reference<document::XDocumentPropertiesSupplier> const
1730 xModelDocPropsSupplier(xModel, uno::UNO_QUERY_THROW);
1731 uno::Reference<document::XDocumentProperties> const xDocPropsToFill =
1732 xModelDocPropsSupplier->getDocumentProperties();
1733 uno::Reference< beans::XPropertySet > const xPropSet(
1734 i_xOldDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW);
1736 uno::Reference< util::XModifiable > xModifiable( xModel, uno::UNO_QUERY );
1737 if ( !xModifiable.is() )
1738 throw uno::RuntimeException();
1740 bool bIsModified = xModifiable->isModified();
1744 uno::Reference< beans::XPropertySet > const xSet(
1745 xDocPropsToFill->getUserDefinedProperties(), uno::UNO_QUERY);
1746 uno::Reference< beans::XPropertyContainer > xContainer( xSet, uno::UNO_QUERY );
1747 uno::Reference< beans::XPropertySetInfo > xSetInfo = xSet->getPropertySetInfo();
1748 const uno::Sequence< beans::Property > lProps = xSetInfo->getProperties();
1749 for (const beans::Property& rProp : lProps)
1751 uno::Any aValue = xPropSet->getPropertyValue( rProp.Name );
1752 if ( rProp.Attributes & css::beans::PropertyAttribute::REMOVABLE )
1756 // QUESTION: DefaultValue?!
1757 xContainer->addProperty( rProp.Name, rProp.Attributes, aValue );
1759 catch (beans::PropertyExistException const&) {}
1762 // it is possible that the propertysets from XML and binary files differ; we shouldn't break then
1763 xSet->setPropertyValue( rProp.Name, aValue );
1765 catch ( const uno::Exception& ) {}
1769 // sigh... have to set these manually I'm afraid... wonder why
1770 // SfxObjectShell doesn't handle this internally, should be easier
1771 xDocPropsToFill->setAuthor(i_xOldDocProps->getAuthor());
1772 xDocPropsToFill->setGenerator(i_xOldDocProps->getGenerator());
1773 xDocPropsToFill->setCreationDate(i_xOldDocProps->getCreationDate());
1774 xDocPropsToFill->setTitle(i_xOldDocProps->getTitle());
1775 xDocPropsToFill->setSubject(i_xOldDocProps->getSubject());
1776 xDocPropsToFill->setDescription(i_xOldDocProps->getDescription());
1777 xDocPropsToFill->setKeywords(i_xOldDocProps->getKeywords());
1778 xDocPropsToFill->setModifiedBy(i_xOldDocProps->getModifiedBy());
1779 xDocPropsToFill->setModificationDate(i_xOldDocProps->getModificationDate());
1780 xDocPropsToFill->setPrintedBy(i_xOldDocProps->getPrintedBy());
1781 xDocPropsToFill->setPrintDate(i_xOldDocProps->getPrintDate());
1782 xDocPropsToFill->setAutoloadURL(i_xOldDocProps->getAutoloadURL());
1783 xDocPropsToFill->setAutoloadSecs(i_xOldDocProps->getAutoloadSecs());
1784 xDocPropsToFill->setDefaultTarget(i_xOldDocProps->getDefaultTarget());
1785 xDocPropsToFill->setEditingCycles(i_xOldDocProps->getEditingCycles());
1786 xDocPropsToFill->setEditingDuration(i_xOldDocProps->getEditingDuration());
1787 // other attributes e.g. DocumentStatistics are not editable from dialog
1789 catch (const uno::Exception&)
1791 TOOLS_INFO_EXCEPTION("sfx.doc", "SetDocInfoState");
1794 // set the modified flag back if required
1795 if ( bIsModified != bool(xModifiable->isModified()) )
1796 xModifiable->setModified( bIsModified );
1800 // static
1801 bool SfxStoringHelper::WarnUnacceptableFormat( const uno::Reference< frame::XModel >& xModel,
1802 std::u16string_view aOldUIName,
1803 const OUString& aDefExtension,
1804 bool bDefIsAlien )
1806 if ( !SvtSaveOptions().IsWarnAlienFormat() )
1807 return true;
1809 weld::Window* pWin = SfxStoringHelper::GetModelWindow(xModel);
1810 SfxAlienWarningDialog aDlg(pWin, aOldUIName, aDefExtension, bDefIsAlien);
1812 return aDlg.run() == RET_OK;
1815 uno::Reference<awt::XWindow> SfxStoringHelper::GetModelXWindow(const uno::Reference<frame::XModel>& xModel)
1817 try {
1818 if ( xModel.is() )
1820 uno::Reference< frame::XController > xController = xModel->getCurrentController();
1821 if ( xController.is() )
1823 uno::Reference< frame::XFrame > xFrame = xController->getFrame();
1824 if ( xFrame.is() )
1826 return xFrame->getContainerWindow();
1831 catch ( const uno::Exception& )
1835 return uno::Reference<awt::XWindow>();
1838 weld::Window* SfxStoringHelper::GetModelWindow( const uno::Reference< frame::XModel >& xModel )
1840 weld::Window* pWin = nullptr;
1844 pWin = Application::GetFrameWeld(GetModelXWindow(xModel));
1846 catch (const uno::Exception&)
1850 return pWin;
1853 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */