1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/XAsynchronousExecutableDialog.hpp>
22 #include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
23 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
24 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
25 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
26 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
27 #include <com/sun/star/view/XSelectionSupplier.hpp>
28 #include <com/sun/star/beans/PropertyExistException.hpp>
29 #include <com/sun/star/beans/XPropertyAccess.hpp>
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <com/sun/star/beans/XPropertyContainer.hpp>
32 #include <com/sun/star/beans/PropertyAttribute.hpp>
33 #include <com/sun/star/document/XExporter.hpp>
34 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
35 #include <com/sun/star/document/XDocumentProperties.hpp>
36 #include <com/sun/star/task/ErrorCodeIOException.hpp>
37 #include <com/sun/star/task/InteractionHandler.hpp>
38 #include <com/sun/star/util/URLTransformer.hpp>
39 #include <com/sun/star/util/XURLTransformer.hpp>
40 #include <com/sun/star/frame/ModuleManager.hpp>
41 #include <com/sun/star/frame/XStorable.hpp>
42 #include <com/sun/star/frame/XStorable2.hpp>
43 #include <com/sun/star/frame/XDispatchProvider.hpp>
44 #include <com/sun/star/frame/XDispatch.hpp>
45 #include <com/sun/star/frame/XTitle.hpp>
46 #include <com/sun/star/util/XModifiable.hpp>
47 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
49 #include <com/sun/star/util/XCloneable.hpp>
51 #include <guisaveas.hxx>
53 #include <sal/log.hxx>
54 #include <unotools/pathoptions.hxx>
55 #include <svl/itemset.hxx>
56 #include <svl/eitem.hxx>
57 #include <unotools/saveopt.hxx>
58 #include <tools/debug.hxx>
59 #include <tools/diagnose_ex.h>
60 #include <tools/urlobj.hxx>
61 #include <tools/json_writer.hxx>
62 #include <tools/urlobj.hxx>
63 #include <comphelper/processfactory.hxx>
64 #include <comphelper/propertysequence.hxx>
65 #include <comphelper/propertyvalue.hxx>
66 #include <comphelper/sequenceashashmap.hxx>
67 #include <comphelper/mimeconfighelper.hxx>
68 #include <comphelper/lok.hxx>
69 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
70 #include <vcl/svapp.hxx>
71 #include <vcl/weld.hxx>
72 #include <o3tl/char16_t2wchar_t.hxx>
73 #include <unotools/tempfile.hxx>
75 #include <sfx2/sfxsids.hrc>
76 #include <sfx2/strings.hrc>
77 #include <sfx2/sfxresid.hxx>
78 #include <sfx2/filedlghelper.hxx>
79 #include <sfx2/app.hxx>
80 #include <sfx2/sfxuno.hxx>
81 #include <sfx2/viewsh.hxx>
82 #include <sfx2/bindings.hxx>
83 #include <alienwarn.hxx>
86 #include <string_view>
88 #include <officecfg/Office/Common.hxx>
90 #include <vcl/FilterConfigItem.hxx>
91 #include <com/sun/star/system/SystemShellExecute.hpp>
92 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
94 #include <osl/file.hxx>
103 // flags that specify requested operation
104 #define EXPORT_REQUESTED 1
105 #define PDFEXPORT_REQUESTED 2
106 #define PDFDIRECTEXPORT_REQUESTED 4
107 #define WIDEEXPORT_REQUESTED 8
108 #define SAVE_REQUESTED 16
109 #define SAVEAS_REQUESTED 32
110 #define SAVEACOPY_REQUESTED 64
111 #define EPUBEXPORT_REQUESTED 128
112 #define EPUBDIRECTEXPORT_REQUESTED 256
113 #define SAVEASREMOTE_REQUESTED -1
115 // possible statuses of save operation
116 #define STATUS_NO_ACTION 0
117 #define STATUS_SAVE 1
118 #define STATUS_SAVEAS 2
119 #define STATUS_SAVEAS_STANDARDNAME 3
121 constexpr OUStringLiteral aFilterNameString
= u
"FilterName";
122 constexpr OUStringLiteral aFilterOptionsString
= u
"FilterOptions";
123 constexpr OUStringLiteral aFilterDataString
= u
"FilterData";
125 using namespace ::com::sun::star
;
126 using namespace css::system
;
130 sal_uInt16
getSlotIDFromMode( sal_Int16 nStoreMode
)
132 // This is a temporary hardcoded solution must be removed when
133 // dialogs do not need parameters in SidSet representation any more
135 sal_uInt16 nResult
= 0;
136 if ( nStoreMode
== EXPORT_REQUESTED
|| nStoreMode
== ( EXPORT_REQUESTED
| SAVEACOPY_REQUESTED
| WIDEEXPORT_REQUESTED
) )
137 nResult
= SID_EXPORTDOC
;
138 else if ( nStoreMode
== ( EXPORT_REQUESTED
| PDFEXPORT_REQUESTED
) )
139 nResult
= SID_EXPORTDOCASPDF
;
140 else if ( nStoreMode
== ( EXPORT_REQUESTED
| EPUBEXPORT_REQUESTED
) )
141 nResult
= SID_EXPORTDOCASEPUB
;
142 else if ( nStoreMode
== ( EXPORT_REQUESTED
| PDFEXPORT_REQUESTED
| PDFDIRECTEXPORT_REQUESTED
) )
143 nResult
= SID_DIRECTEXPORTDOCASPDF
;
144 else if ( nStoreMode
== ( EXPORT_REQUESTED
| EPUBEXPORT_REQUESTED
| EPUBDIRECTEXPORT_REQUESTED
) )
145 nResult
= SID_DIRECTEXPORTDOCASEPUB
;
146 else if ( nStoreMode
== SAVEAS_REQUESTED
|| nStoreMode
== ( EXPORT_REQUESTED
| WIDEEXPORT_REQUESTED
) )
147 nResult
= SID_SAVEASDOC
;
148 else if ( nStoreMode
== SAVEASREMOTE_REQUESTED
)
149 nResult
= SID_SAVEASREMOTE
;
151 SAL_WARN( "sfx.doc", "Unacceptable slot name is provided!" );
158 sal_Int16
getStoreModeFromSlotName( std::u16string_view aSlotName
)
160 sal_Int16 nResult
= 0;
161 if ( aSlotName
== u
"ExportTo" )
162 nResult
= EXPORT_REQUESTED
;
163 else if ( aSlotName
== u
"ExportToPDF" )
164 nResult
= EXPORT_REQUESTED
| PDFEXPORT_REQUESTED
;
165 else if ( aSlotName
== u
"ExportDirectToPDF" )
166 nResult
= EXPORT_REQUESTED
| PDFEXPORT_REQUESTED
| PDFDIRECTEXPORT_REQUESTED
;
167 else if ( aSlotName
== u
"ExportToEPUB" )
168 nResult
= EXPORT_REQUESTED
| EPUBEXPORT_REQUESTED
;
169 else if ( aSlotName
== u
"ExportDirectToEPUB" )
170 nResult
= EXPORT_REQUESTED
| EPUBEXPORT_REQUESTED
| EPUBDIRECTEXPORT_REQUESTED
;
171 else if ( aSlotName
== u
"Save" )
172 nResult
= SAVE_REQUESTED
;
173 else if ( aSlotName
== u
"SaveAs" )
174 nResult
= SAVEAS_REQUESTED
;
175 else if ( aSlotName
== u
"SaveAsRemote" )
176 nResult
= SAVEASREMOTE_REQUESTED
;
178 throw task::ErrorCodeIOException(
179 (OUString::Concat("getStoreModeFromSlotName(\"") + aSlotName
180 + "): ERRCODE_IO_INVALIDPARAMETER"),
181 uno::Reference
< uno::XInterface
>(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER
) );
187 SfxFilterFlags
getMustFlags( sal_Int16 nStoreMode
)
189 return ( SfxFilterFlags::EXPORT
190 | ( ( ( nStoreMode
& EXPORT_REQUESTED
) && !( nStoreMode
& WIDEEXPORT_REQUESTED
) ) ? SfxFilterFlags::NONE
: SfxFilterFlags::IMPORT
) );
194 SfxFilterFlags
getDontFlags( sal_Int16 nStoreMode
)
196 return ( SfxFilterFlags::INTERNAL
197 | SfxFilterFlags::NOTINFILEDLG
198 | ( ( ( nStoreMode
& EXPORT_REQUESTED
) && !( nStoreMode
& WIDEEXPORT_REQUESTED
) ) ? SfxFilterFlags::IMPORT
: SfxFilterFlags::NONE
) );
204 class DocumentSettingsGuard
206 uno::Reference
< beans::XPropertySet
> m_xDocumentSettings
;
207 bool m_bPreserveReadOnly
;
208 bool m_bReadOnlySupported
;
210 bool m_bRestoreSettings
;
212 DocumentSettingsGuard( const uno::Reference
< frame::XModel
>& xModel
, bool bReadOnly
, bool bRestore
)
213 : m_bPreserveReadOnly( false )
214 , m_bReadOnlySupported( false )
215 , m_bRestoreSettings( bRestore
)
219 uno::Reference
< lang::XMultiServiceFactory
> xDocSettingsSupplier( xModel
, uno::UNO_QUERY_THROW
);
220 m_xDocumentSettings
.set(
221 xDocSettingsSupplier
->createInstance( "com.sun.star.document.Settings" ),
222 uno::UNO_QUERY_THROW
);
226 OUString
aLoadReadonlyString( "LoadReadonly" );
227 m_xDocumentSettings
->getPropertyValue( aLoadReadonlyString
) >>= m_bPreserveReadOnly
;
228 m_xDocumentSettings
->setPropertyValue( aLoadReadonlyString
, uno::makeAny( bReadOnly
) );
229 m_bReadOnlySupported
= true;
231 catch( const uno::Exception
& )
234 catch( const uno::Exception
& )
237 if ( bReadOnly
&& !m_bReadOnlySupported
)
238 throw uno::RuntimeException(); // the user could provide the data, so it must be stored
241 ~DocumentSettingsGuard()
243 if ( m_bRestoreSettings
)
247 if ( m_bReadOnlySupported
)
248 m_xDocumentSettings
->setPropertyValue( "LoadReadonly", uno::makeAny( m_bPreserveReadOnly
) );
250 catch( const uno::Exception
& )
252 TOOLS_WARN_EXCEPTION( "sfx.doc", "" );
257 } // anonymous namespace
263 SfxStoringHelper
* m_pOwner
;
264 uno::Reference
< frame::XModel
> m_xModel
;
265 uno::Reference
< frame::XStorable
> m_xStorable
;
266 uno::Reference
< frame::XStorable2
> m_xStorable2
;
268 OUString m_aModuleName
;
269 std::unique_ptr
<::comphelper::SequenceAsHashMap
> m_pDocumentPropsHM
;
270 std::unique_ptr
<::comphelper::SequenceAsHashMap
> m_pModulePropsHM
;
272 uno::Reference
<beans::XPropertyAccess
> m_xFilterProperties
;
273 uno::Reference
<ui::dialogs::XAsynchronousExecutableDialog
> m_xFilterDialog
;
275 ::comphelper::SequenceAsHashMap m_aMediaDescrHM
;
277 bool m_bRecommendReadOnly
;
279 DECL_LINK(OptionsDialogClosedHdl
, css::ui::dialogs::DialogClosedEvent
*, void);
282 ModelData_Impl( SfxStoringHelper
& aOwner
,
283 const uno::Reference
< frame::XModel
>& xModel
,
284 const uno::Sequence
< beans::PropertyValue
>& aMediaDescr
);
288 void FreeDocumentProps();
290 uno::Reference
< frame::XModel
> const & GetModel() const;
291 uno::Reference
< frame::XStorable
> const & GetStorable();
292 uno::Reference
< frame::XStorable2
> const & GetStorable2();
294 ::comphelper::SequenceAsHashMap
& GetMediaDescr() { return m_aMediaDescrHM
; }
296 bool IsRecommendReadOnly() const { return m_bRecommendReadOnly
; }
298 const ::comphelper::SequenceAsHashMap
& GetDocProps();
300 OUString
const & GetModuleName();
301 const ::comphelper::SequenceAsHashMap
& GetModuleProps();
303 void CheckInteractionHandler();
306 OUString
GetDocServiceName();
307 uno::Sequence
< beans::PropertyValue
> GetDocServiceDefaultFilterCheckFlags( SfxFilterFlags nMust
, SfxFilterFlags nDont
);
308 uno::Sequence
< beans::PropertyValue
> GetDocServiceAnyFilter( SfxFilterFlags nMust
, SfxFilterFlags nDont
);
309 uno::Sequence
< beans::PropertyValue
> GetPreselectedFilter_Impl( sal_Int16 nStoreMode
);
310 uno::Sequence
< beans::PropertyValue
> GetDocServiceDefaultFilter();
312 bool ExecuteFilterDialog_Impl( const OUString
& aFilterName
, bool bAsync
);
314 sal_Int8
CheckSaveAcceptable( sal_Int8 nCurStatus
);
315 sal_Int8
CheckStateForSave();
317 sal_Int8
CheckFilter( const OUString
& );
319 bool CheckFilterOptionsDialogExistence();
321 bool OutputFileDialog( sal_Int16 nStoreMode
,
322 const ::comphelper::SequenceAsHashMap
& aPreselectedFilterPropsHM
,
323 bool bSetStandardName
,
324 OUString
& aSuggestedName
,
325 bool bPreselectPassword
,
326 OUString
& aSuggestedDir
,
328 const OUString
& rStandardDir
,
329 const css::uno::Sequence
< OUString
>& rDenyList
332 bool ShowDocumentInfoDialog();
334 static OUString
GetRecommendedExtension( const OUString
& aTypeName
);
335 OUString
GetRecommendedDir( const OUString
& aSuggestedDir
);
336 OUString
GetRecommendedName( const OUString
& aSuggestedName
,
337 const OUString
& aTypeName
);
341 ModelData_Impl::ModelData_Impl( SfxStoringHelper
& aOwner
,
342 const uno::Reference
< frame::XModel
>& xModel
,
343 const uno::Sequence
< beans::PropertyValue
>& aMediaDescr
)
344 : m_pOwner( &aOwner
)
346 , m_aMediaDescrHM( aMediaDescr
)
347 , m_bRecommendReadOnly( false )
349 CheckInteractionHandler();
353 ModelData_Impl::~ModelData_Impl()
356 m_pDocumentPropsHM
.reset();
357 m_pModulePropsHM
.reset();
358 if (m_xFilterProperties
)
359 m_xFilterProperties
.clear();
363 void ModelData_Impl::FreeDocumentProps()
365 m_pDocumentPropsHM
.reset();
369 uno::Reference
< frame::XModel
> const & ModelData_Impl::GetModel() const
371 if ( !m_xModel
.is() )
372 throw uno::RuntimeException();
378 uno::Reference
< frame::XStorable
> const & ModelData_Impl::GetStorable()
380 if ( !m_xStorable
.is() )
382 m_xStorable
.set( m_xModel
, uno::UNO_QUERY_THROW
);
389 uno::Reference
< frame::XStorable2
> const & ModelData_Impl::GetStorable2()
391 if ( !m_xStorable2
.is() )
393 m_xStorable2
.set( m_xModel
, uno::UNO_QUERY_THROW
);
400 const ::comphelper::SequenceAsHashMap
& ModelData_Impl::GetDocProps()
402 if ( !m_pDocumentPropsHM
)
403 m_pDocumentPropsHM
.reset( new ::comphelper::SequenceAsHashMap( GetModel()->getArgs() ) );
405 return *m_pDocumentPropsHM
;
409 OUString
const & ModelData_Impl::GetModuleName()
411 if ( m_aModuleName
.isEmpty() )
413 m_aModuleName
= m_pOwner
->GetModuleManager()->identify(
414 uno::Reference
< uno::XInterface
>( m_xModel
, uno::UNO_QUERY
) );
415 if ( m_aModuleName
.isEmpty() )
416 throw uno::RuntimeException(); // TODO:
418 return m_aModuleName
;
422 const ::comphelper::SequenceAsHashMap
& ModelData_Impl::GetModuleProps()
424 if ( !m_pModulePropsHM
)
426 uno::Sequence
< beans::PropertyValue
> aModuleProps
;
427 m_pOwner
->GetModuleManager()->getByName( GetModuleName() ) >>= aModuleProps
;
428 if ( !aModuleProps
.hasElements() )
429 throw uno::RuntimeException(); // TODO;
430 m_pModulePropsHM
.reset( new ::comphelper::SequenceAsHashMap( aModuleProps
) );
433 return *m_pModulePropsHM
;
437 OUString
ModelData_Impl::GetDocServiceName()
439 return GetModuleProps().getUnpackedValueOrDefault("ooSetupFactoryDocumentService", OUString());
443 void ModelData_Impl::CheckInteractionHandler()
445 const OUString sInteractionHandler
{"InteractionHandler"};
446 ::comphelper::SequenceAsHashMap::const_iterator aInteractIter
=
447 m_aMediaDescrHM
.find( sInteractionHandler
);
449 if ( aInteractIter
== m_aMediaDescrHM
.end() )
452 m_aMediaDescrHM
[ sInteractionHandler
]
453 <<= task::InteractionHandler::createWithParent( comphelper::getProcessComponentContext(), nullptr);
455 catch( const uno::Exception
& )
461 uno::Reference
< task::XInteractionHandler
> xInteract
;
462 DBG_ASSERT( ( aInteractIter
->second
>>= xInteract
) && xInteract
.is(), "Broken interaction handler is provided!\n" );
467 uno::Sequence
< beans::PropertyValue
> ModelData_Impl::GetDocServiceDefaultFilter()
469 uno::Sequence
< beans::PropertyValue
> aProps
;
471 const OUString aFilterName
= GetModuleProps().getUnpackedValueOrDefault( "ooSetupFactoryDefaultFilter", OUString() );
473 m_pOwner
->GetFilterConfiguration()->getByName( aFilterName
) >>= aProps
;
479 uno::Sequence
< beans::PropertyValue
> ModelData_Impl::GetDocServiceDefaultFilterCheckFlags( SfxFilterFlags nMust
,
480 SfxFilterFlags nDont
)
482 uno::Sequence
< beans::PropertyValue
> aFilterProps
;
483 uno::Sequence
< beans::PropertyValue
> aProps
= GetDocServiceDefaultFilter();
484 if ( aProps
.hasElements() )
486 ::comphelper::SequenceAsHashMap
aFiltHM( aProps
);
487 SfxFilterFlags nFlags
= static_cast<SfxFilterFlags
>(aFiltHM
.getUnpackedValueOrDefault("Flags",
489 if ( ( ( nFlags
& nMust
) == nMust
) && !( nFlags
& nDont
) )
490 aFilterProps
= aProps
;
497 uno::Sequence
< beans::PropertyValue
> ModelData_Impl::GetDocServiceAnyFilter( SfxFilterFlags nMust
, SfxFilterFlags nDont
)
499 uno::Sequence
< beans::NamedValue
> aSearchRequest
{ { "DocumentService", css::uno::makeAny(GetDocServiceName()) } };
501 return ::comphelper::MimeConfigurationHelper::SearchForFilter( m_pOwner
->GetFilterQuery(), aSearchRequest
, nMust
, nDont
);
505 uno::Sequence
< beans::PropertyValue
> ModelData_Impl::GetPreselectedFilter_Impl( sal_Int16 nStoreMode
)
507 if ( nStoreMode
== SAVEASREMOTE_REQUESTED
)
508 nStoreMode
= SAVEAS_REQUESTED
;
510 uno::Sequence
< beans::PropertyValue
> aFilterProps
;
512 SfxFilterFlags nMust
= getMustFlags( nStoreMode
);
513 SfxFilterFlags nDont
= getDontFlags( nStoreMode
);
515 if ( ( nStoreMode
!= SAVEASREMOTE_REQUESTED
) && ( nStoreMode
& PDFEXPORT_REQUESTED
) )
517 // Preselect PDF-Filter for EXPORT
518 uno::Sequence
< beans::NamedValue
> aSearchRequest
520 { "Type", css::uno::makeAny(OUString("pdf_Portable_Document_Format")) },
521 { "DocumentService", css::uno::makeAny(GetDocServiceName()) }
524 aFilterProps
= ::comphelper::MimeConfigurationHelper::SearchForFilter( m_pOwner
->GetFilterQuery(), aSearchRequest
, nMust
, nDont
);
526 else if ( ( nStoreMode
!= SAVEASREMOTE_REQUESTED
) && ( nStoreMode
& EPUBEXPORT_REQUESTED
) )
528 // Preselect EPUB filter for export.
529 uno::Sequence
<beans::NamedValue
> aSearchRequest
531 { "Type", css::uno::makeAny(OUString("writer_EPUB_Document")) },
532 { "DocumentService", css::uno::makeAny(GetDocServiceName()) }
535 aFilterProps
= ::comphelper::MimeConfigurationHelper::SearchForFilter( m_pOwner
->GetFilterQuery(), aSearchRequest
, nMust
, nDont
);
539 aFilterProps
= GetDocServiceDefaultFilterCheckFlags( nMust
, nDont
);
541 if ( !aFilterProps
.hasElements() )
543 // the default filter was not found, use just the first acceptable one
544 aFilterProps
= GetDocServiceAnyFilter( nMust
, nDont
);
552 bool ModelData_Impl::ExecuteFilterDialog_Impl( const OUString
& aFilterName
, bool bIsAsync
)
554 bool bDialogUsed
= false;
557 uno::Sequence
< beans::PropertyValue
> aProps
;
558 uno::Any aAny
= m_pOwner
->GetFilterConfiguration()->getByName( aFilterName
);
559 if ( aAny
>>= aProps
)
561 auto pProp
= std::find_if(std::cbegin(aProps
), std::cend(aProps
),
562 [](const beans::PropertyValue
& rProp
) { return rProp
.Name
== "UIComponent"; });
563 if (pProp
!= std::cend(aProps
))
565 OUString aServiceName
;
566 pProp
->Value
>>= aServiceName
;
567 if( !aServiceName
.isEmpty() )
569 uno::Sequence
<uno::Any
> aDialogArgs(comphelper::InitAnyPropertySequence(
571 {"ParentWindow", uno::Any(SfxStoringHelper::GetModelXWindow(m_xModel
))},
574 uno::Reference
< beans::XPropertyAccess
> xFilterProperties
;
575 uno::Reference
< ui::dialogs::XExecutableDialog
> xFilterDialog
;
576 uno::Reference
< ui::dialogs::XAsynchronousExecutableDialog
> xAsyncFilterDialog
;
577 uno::Reference
< document::XExporter
> xExporter
;
581 xAsyncFilterDialog
= uno::Reference
< ui::dialogs::XAsynchronousExecutableDialog
>(
582 comphelper::getProcessServiceFactory()->createInstanceWithArguments( aServiceName
, aDialogArgs
), uno::UNO_QUERY
);
583 OSL_ENSURE(xAsyncFilterDialog
.is(), "ModelData_Impl::ExecuteFilterDialog_Impl: Dialog is not async!");
584 xFilterProperties
= uno::Reference
< beans::XPropertyAccess
>( xAsyncFilterDialog
, uno::UNO_QUERY
);
585 xExporter
= uno::Reference
< document::XExporter
>( xAsyncFilterDialog
, uno::UNO_QUERY
);
589 xFilterDialog
= uno::Reference
< ui::dialogs::XExecutableDialog
>(
590 comphelper::getProcessServiceFactory()->createInstanceWithArguments( aServiceName
, aDialogArgs
), uno::UNO_QUERY
);
591 xFilterProperties
= uno::Reference
< beans::XPropertyAccess
>( xFilterDialog
, uno::UNO_QUERY
);
592 xExporter
= uno::Reference
< document::XExporter
>( xFilterDialog
, uno::UNO_QUERY
);
595 if ( xFilterProperties
.is() && ( xFilterDialog
.is() || xAsyncFilterDialog
.is() ) )
600 xExporter
->setSourceDocument( GetModel() );
602 uno::Sequence
< beans::PropertyValue
> aPropsForDialog
;
603 GetMediaDescr() >> aPropsForDialog
;
604 xFilterProperties
->setPropertyValues( aPropsForDialog
);
608 m_xFilterProperties
= xFilterProperties
;
609 m_xFilterDialog
= xAsyncFilterDialog
;
611 auto aDialogClosedListener
= rtl::Reference(new svt::DialogClosedListener());
612 aDialogClosedListener
->SetDialogClosedLink( LINK( this, ModelData_Impl
, OptionsDialogClosedHdl
) );
614 m_xFilterDialog
->startExecuteModal( aDialogClosedListener
);
618 if( !xFilterDialog
->execute() )
620 throw task::ErrorCodeIOException(
621 ("ModelData_Impl::ExecuteFilterDialog_Impl:"
622 " ERRCODE_IO_ABORT"),
623 uno::Reference
< uno::XInterface
>(),
624 sal_uInt32(ERRCODE_IO_ABORT
));
627 const uno::Sequence
< beans::PropertyValue
> aPropsFromDialog
=
628 xFilterProperties
->getPropertyValues();
629 for ( const auto& rProp
: aPropsFromDialog
)
630 GetMediaDescr()[rProp
.Name
] = rProp
.Value
;
637 catch( const container::NoSuchElementException
& e
)
639 // the filter name is unknown
640 throw task::ErrorCodeIOException(
641 ("ModelData_Impl::ExecuteFilterDialog_Impl: NoSuchElementException"
642 " \"" + e
.Message
+ "\": ERRCODE_IO_ABORT"),
643 uno::Reference
< uno::XInterface
>(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER
));
645 catch( const task::ErrorCodeIOException
& )
649 catch( const uno::Exception
& )
651 TOOLS_WARN_EXCEPTION("sfx.doc", "ignoring");
657 void SfxStoringHelper::CallFinishGUIStoreModel()
659 ::comphelper::SequenceAsHashMap::const_iterator aFileNameIter
= m_xModelData
->GetMediaDescr().find( OUString("URL") );
660 uno::Sequence
< beans::PropertyValue
> aFilterProps
= m_xModelData
->GetPreselectedFilter_Impl( m_nStoreMode
);
661 const OUString aFilterFromMediaDescr
= m_xModelData
->GetMediaDescr().getUnpackedValueOrDefault( aFilterNameString
, OUString() );
662 const OUString aOldFilterName
= m_xModelData
->GetDocProps().getUnpackedValueOrDefault( aFilterNameString
, OUString() );
663 ::comphelper::SequenceAsHashMap
aFilterPropsHM( aFilterProps
);
664 OUString aFilterName
= aFilterPropsHM
.getUnpackedValueOrDefault( "Name", OUString() );
666 SfxStoringHelper::FinishGUIStoreModel(aFileNameIter
, *m_xModelData
, m_bRemote
, m_nStoreMode
, aFilterProps
,
667 m_bSetStandardName
, m_bPreselectPassword
, m_bDialogUsed
,
668 aFilterFromMediaDescr
, aOldFilterName
, m_aArgsSequence
, aFilterName
);
670 if (SfxViewShell::Current())
671 SfxViewShell::Current()->SetStoringHelper(nullptr);
674 IMPL_LINK( ModelData_Impl
, OptionsDialogClosedHdl
, css::ui::dialogs::DialogClosedEvent
*, pEvt
, void )
676 if (pEvt
->DialogResult
== RET_OK
&& m_xFilterProperties
)
678 const uno::Sequence
< beans::PropertyValue
> aPropsFromDialog
= m_xFilterProperties
->getPropertyValues();
679 for ( const auto& rProp
: aPropsFromDialog
)
680 GetMediaDescr()[rProp
.Name
] = rProp
.Value
;
682 m_pOwner
->CallFinishGUIStoreModel();
686 sal_Int8
ModelData_Impl::CheckSaveAcceptable( sal_Int8 nCurStatus
)
688 sal_Int8 nResult
= nCurStatus
;
690 if ( nResult
!= STATUS_NO_ACTION
&& GetStorable()->hasLocation() )
692 // the saving is acceptable
693 // in case the configuration entry is not set or set to false
694 // or in case of version creation
695 if ( officecfg::Office::Common::Save::Document::AlwaysSaveAs::get()
696 && GetMediaDescr().find( OUString("VersionComment") ) == GetMediaDescr().end() )
698 // notify the user that SaveAs is going to be done
699 std::unique_ptr
<weld::MessageDialog
> xMessageBox(Application::CreateMessageDialog(SfxStoringHelper::GetModelWindow(m_xModel
),
700 VclMessageType::Question
, VclButtonsType::OkCancel
, SfxResId(STR_NEW_FILENAME_SAVE
)));
701 if (xMessageBox
->run() == RET_OK
)
702 nResult
= STATUS_SAVEAS
;
704 nResult
= STATUS_NO_ACTION
;
712 sal_Int8
ModelData_Impl::CheckStateForSave()
714 // if the document is readonly or a new one a SaveAs operation must be used
715 if ( !GetStorable()->hasLocation() || GetStorable()->isReadonly() )
716 return STATUS_SAVEAS
;
718 // check acceptable entries for media descriptor
719 ::comphelper::SequenceAsHashMap aAcceptedArgs
;
721 static const OUStringLiteral
aVersionCommentString(u
"VersionComment");
722 static const OUStringLiteral
aAuthorString(u
"Author");
723 static const OUStringLiteral
aDontTerminateEdit(u
"DontTerminateEdit");
724 static const OUStringLiteral
aInteractionHandlerString(u
"InteractionHandler");
725 static const OUStringLiteral
aStatusIndicatorString(u
"StatusIndicator");
726 static const OUStringLiteral
aFailOnWarningString(u
"FailOnWarning");
727 static const OUStringLiteral
aNoFileSync(u
"NoFileSync");
729 if ( GetMediaDescr().find( aVersionCommentString
) != GetMediaDescr().end() )
730 aAcceptedArgs
[ aVersionCommentString
] = GetMediaDescr()[ aVersionCommentString
];
731 if ( GetMediaDescr().find( aAuthorString
) != GetMediaDescr().end() )
732 aAcceptedArgs
[ aAuthorString
] = GetMediaDescr()[ aAuthorString
];
733 if ( GetMediaDescr().find( aDontTerminateEdit
) != GetMediaDescr().end() )
734 aAcceptedArgs
[ aDontTerminateEdit
] = GetMediaDescr()[ aDontTerminateEdit
];
735 if ( GetMediaDescr().find( aInteractionHandlerString
) != GetMediaDescr().end() )
736 aAcceptedArgs
[ aInteractionHandlerString
] = GetMediaDescr()[ aInteractionHandlerString
];
737 if ( GetMediaDescr().find( aStatusIndicatorString
) != GetMediaDescr().end() )
738 aAcceptedArgs
[ aStatusIndicatorString
] = GetMediaDescr()[ aStatusIndicatorString
];
739 if ( GetMediaDescr().find( aFailOnWarningString
) != GetMediaDescr().end() )
740 aAcceptedArgs
[ aFailOnWarningString
] = GetMediaDescr()[ aFailOnWarningString
];
741 if (GetMediaDescr().find(aNoFileSync
) != GetMediaDescr().end())
742 aAcceptedArgs
[aNoFileSync
] = GetMediaDescr()[aNoFileSync
];
744 // remove unacceptable entry if there is any
745 DBG_ASSERT( GetMediaDescr().size() == aAcceptedArgs
.size(),
746 "Unacceptable parameters are provided in Save request!\n" );
747 if ( GetMediaDescr().size() != aAcceptedArgs
.size() )
748 GetMediaDescr() = aAcceptedArgs
;
750 // check that the old filter is acceptable
751 return CheckFilter( GetDocProps().getUnpackedValueOrDefault(aFilterNameString
, OUString()) );
754 sal_Int8
ModelData_Impl::CheckFilter( const OUString
& aFilterName
)
756 ::comphelper::SequenceAsHashMap aFiltPropsHM
;
757 SfxFilterFlags nFiltFlags
= SfxFilterFlags::NONE
;
758 if ( !aFilterName
.isEmpty() )
760 // get properties of filter
761 uno::Sequence
< beans::PropertyValue
> aFilterProps
;
762 m_pOwner
->GetFilterConfiguration()->getByName( aFilterName
) >>= aFilterProps
;
764 aFiltPropsHM
= ::comphelper::SequenceAsHashMap( aFilterProps
);
765 nFiltFlags
= static_cast<SfxFilterFlags
>(aFiltPropsHM
.getUnpackedValueOrDefault("Flags", sal_Int32(0) ));
768 // only a temporary solution until default filter retrieving feature is implemented
769 // then GetDocServiceDefaultFilter() must be used
770 ::comphelper::SequenceAsHashMap aDefFiltPropsHM
= GetDocServiceDefaultFilterCheckFlags( SfxFilterFlags::IMPORT
| SfxFilterFlags::EXPORT
, SfxFilterFlags::NONE
);
771 SfxFilterFlags nDefFiltFlags
= static_cast<SfxFilterFlags
>(aDefFiltPropsHM
.getUnpackedValueOrDefault("Flags", sal_Int32(0) ));
775 // if the old filter is not acceptable
776 // and there is no default filter or it is not acceptable for requested parameters then proceed with saveAs
777 if ( ( aFiltPropsHM
.empty() || !( nFiltFlags
& SfxFilterFlags::EXPORT
) )
778 && ( aDefFiltPropsHM
.empty() || !( nDefFiltFlags
& SfxFilterFlags::EXPORT
) || nDefFiltFlags
& SfxFilterFlags::INTERNAL
) )
779 return STATUS_SAVEAS
;
781 // so at this point there is either an acceptable old filter or default one
782 if ( aFiltPropsHM
.empty() || !( nFiltFlags
& SfxFilterFlags::EXPORT
) )
784 // so the default filter must be acceptable
785 return STATUS_SAVEAS_STANDARDNAME
;
787 else if ( ( !( nFiltFlags
& SfxFilterFlags::OWN
) || ( nFiltFlags
& SfxFilterFlags::ALIEN
) )
788 && !aDefFiltPropsHM
.empty()
789 && ( nDefFiltFlags
& SfxFilterFlags::EXPORT
) && !( nDefFiltFlags
& SfxFilterFlags::INTERNAL
))
794 // check if EncryptionData supports this output format
796 OUString aSupportedFilters
;
797 const ::comphelper::SequenceAsHashMap
& rDocumentProperties
= GetDocProps();
798 const css::uno::Sequence
<css::beans::NamedValue
> aEncryptionData
= rDocumentProperties
.getUnpackedValueOrDefault("EncryptionData", css::uno::Sequence
<css::beans::NamedValue
>());
799 if (aEncryptionData
!= css::uno::Sequence
<css::beans::NamedValue
>())
801 for (const css::beans::NamedValue
& aNamedValue
: aEncryptionData
)
803 if (aNamedValue
.Name
== "SupportedFilters")
805 aNamedValue
.Value
>>= aSupportedFilters
;
810 // if 'SupportedFilters' is empty assume that all filters are supported.
811 if (!aSupportedFilters
.isEmpty())
813 const OUString aSelectedFilter
= aFiltPropsHM
.getUnpackedValueOrDefault("UIName", OUString());
815 aSupportedFilters
= ";" + aSupportedFilters
+ ";";
816 const OUString aSearchToken
= ";" + aSelectedFilter
+ ";";
817 bAsk
= (aSupportedFilters
.indexOf(aSearchToken
) < 0);
823 // the default filter is acceptable and the old filter is alien one
824 // so ask to make a saveAs operation
825 const OUString aUIName
= aFiltPropsHM
.getUnpackedValueOrDefault("UIName", OUString() );
826 const OUString aDefUIName
= aDefFiltPropsHM
.getUnpackedValueOrDefault("UIName", OUString() );
827 const OUString aPreusedFilterName
= GetDocProps().getUnpackedValueOrDefault("PreusedFilterName", OUString() );
828 const OUString aDefType
= aDefFiltPropsHM
.getUnpackedValueOrDefault( "Type", OUString() );
829 const OUString aDefExtension
= GetRecommendedExtension( aDefType
);
831 if ( aPreusedFilterName
!= aFilterName
&& aUIName
!= aDefUIName
)
833 if ( !SfxStoringHelper::WarnUnacceptableFormat( GetModel(), aUIName
, aDefExtension
,
834 static_cast<bool>( nDefFiltFlags
& SfxFilterFlags::ALIEN
) ) )
835 return STATUS_SAVEAS_STANDARDNAME
;
843 bool ModelData_Impl::CheckFilterOptionsDialogExistence()
845 uno::Sequence
< beans::NamedValue
> aSearchRequest
{ { "DocumentService", css::uno::makeAny(GetDocServiceName()) } };
847 uno::Reference
< container::XEnumeration
> xFilterEnum
=
848 m_pOwner
->GetFilterQuery()->createSubSetEnumerationByProperties( aSearchRequest
);
850 while ( xFilterEnum
->hasMoreElements() )
852 uno::Sequence
< beans::PropertyValue
> aProps
;
853 if ( xFilterEnum
->nextElement() >>= aProps
)
855 ::comphelper::SequenceAsHashMap
aPropsHM( aProps
);
856 if ( !aPropsHM
.getUnpackedValueOrDefault("UIComponent", OUString()).isEmpty() )
865 bool ModelData_Impl::OutputFileDialog( sal_Int16 nStoreMode
,
866 const ::comphelper::SequenceAsHashMap
& aPreselectedFilterPropsHM
,
867 bool bSetStandardName
,
868 OUString
& aSuggestedName
,
869 bool bPreselectPassword
,
870 OUString
& aSuggestedDir
,
872 const OUString
& rStandardDir
,
873 const css::uno::Sequence
< OUString
>& rDenyList
)
875 if ( nStoreMode
== SAVEASREMOTE_REQUESTED
)
876 nStoreMode
= SAVEAS_REQUESTED
;
878 bool bUseFilterOptions
= false;
880 ::comphelper::SequenceAsHashMap::const_iterator aOverwriteIter
=
881 GetMediaDescr().find( OUString("Overwrite") );
883 // the file name must be specified if overwrite option is set
884 if ( aOverwriteIter
!= GetMediaDescr().end() )
885 throw task::ErrorCodeIOException(
886 "ModelData_Impl::OutputFileDialog: ERRCODE_IO_INVALIDPARAMETER",
887 uno::Reference
< uno::XInterface
>(),
888 sal_uInt32(ERRCODE_IO_INVALIDPARAMETER
));
890 // no target file name is specified
891 // we need to show the file dialog
893 // check if we have a filter which allows for filter options, so we need a corresponding checkbox in the dialog
894 bool bAllowOptions
= false;
896 // in case of Export, filter options dialog is used if available
897 if( !( nStoreMode
& EXPORT_REQUESTED
) || ( nStoreMode
& WIDEEXPORT_REQUESTED
) )
898 bAllowOptions
= CheckFilterOptionsDialogExistence();
900 // get the filename by dialog ...
901 // create the file dialog
902 sal_Int16 aDialogMode
= bAllowOptions
903 ? css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS
904 : css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD
;
905 FileDialogFlags aDialogFlags
= FileDialogFlags::NONE
;
907 if( ( nStoreMode
& EXPORT_REQUESTED
) && !( nStoreMode
& WIDEEXPORT_REQUESTED
) )
909 if ( (nStoreMode
& PDFEXPORT_REQUESTED
) || (nStoreMode
& EPUBEXPORT_REQUESTED
) )
910 aDialogMode
= css::ui::dialogs::TemplateDescription::
911 FILESAVE_AUTOEXTENSION
;
913 aDialogMode
= css::ui::dialogs::TemplateDescription::
914 FILESAVE_AUTOEXTENSION_SELECTION
;
915 aDialogFlags
= FileDialogFlags::Export
;
918 if( ( nStoreMode
& EXPORT_REQUESTED
) && ( nStoreMode
& SAVEACOPY_REQUESTED
) && ( nStoreMode
& WIDEEXPORT_REQUESTED
) )
920 aDialogFlags
= FileDialogFlags::SaveACopy
;
923 std::unique_ptr
<sfx2::FileDialogHelper
> pFileDlg
;
925 const OUString aDocServiceName
{GetDocServiceName()};
926 DBG_ASSERT( !aDocServiceName
.isEmpty(), "No document service for this module set!" );
928 SfxFilterFlags nMust
= getMustFlags( nStoreMode
);
929 SfxFilterFlags nDont
= getDontFlags( nStoreMode
);
930 weld::Window
* pFrameWin
= SfxStoringHelper::GetModelWindow(m_xModel
);
931 if ( ( nStoreMode
& EXPORT_REQUESTED
) && !( nStoreMode
& WIDEEXPORT_REQUESTED
) )
933 if ( ( nStoreMode
& PDFEXPORT_REQUESTED
) && !aPreselectedFilterPropsHM
.empty() )
935 // this is a PDF export
936 // the filter options has been shown already
937 const OUString aFilterUIName
= aPreselectedFilterPropsHM
.getUnpackedValueOrDefault( "UIName", OUString() );
938 pFileDlg
.reset(new sfx2::FileDialogHelper( aDialogMode
, aDialogFlags
, aFilterUIName
, "pdf", rStandardDir
, rDenyList
, pFrameWin
));
939 pFileDlg
->SetCurrentFilter( aFilterUIName
);
941 else if ((nStoreMode
& EPUBEXPORT_REQUESTED
) && !aPreselectedFilterPropsHM
.empty())
943 // This is an EPUB export, the filter options has been shown already.
944 const OUString aFilterUIName
= aPreselectedFilterPropsHM
.getUnpackedValueOrDefault( "UIName", OUString() );
945 pFileDlg
.reset(new sfx2::FileDialogHelper(aDialogMode
, aDialogFlags
, aFilterUIName
, "epub", rStandardDir
, rDenyList
, pFrameWin
));
946 pFileDlg
->SetCurrentFilter(aFilterUIName
);
950 // This is the normal dialog
951 pFileDlg
.reset(new sfx2::FileDialogHelper( aDialogMode
, aDialogFlags
, aDocServiceName
, nDialog
, nMust
, nDont
, rStandardDir
, rDenyList
, pFrameWin
));
954 sfx2::FileDialogHelper::Context eCtxt
= sfx2::FileDialogHelper::UnknownContext
;
955 if ( aDocServiceName
== "com.sun.star.drawing.DrawingDocument" )
956 eCtxt
= sfx2::FileDialogHelper::DrawExport
;
957 else if ( aDocServiceName
== "com.sun.star.presentation.PresentationDocument" )
958 eCtxt
= sfx2::FileDialogHelper::ImpressExport
;
959 else if ( aDocServiceName
== "com.sun.star.text.TextDocument" )
960 eCtxt
= sfx2::FileDialogHelper::WriterExport
;
961 else if ( aDocServiceName
== "com.sun.star.sheet.SpreadsheetDocument" )
962 eCtxt
= sfx2::FileDialogHelper::CalcExport
;
964 if ( eCtxt
!= sfx2::FileDialogHelper::UnknownContext
)
965 pFileDlg
->SetContext( eCtxt
);
967 pFileDlg
->CreateMatcher( aDocServiceName
);
969 uno::Reference
< ui::dialogs::XFilePicker3
> xFilePicker
= pFileDlg
->GetFilePicker();
970 uno::Reference
< ui::dialogs::XFilePickerControlAccess
> xControlAccess( xFilePicker
, uno::UNO_QUERY
);
972 if ( xControlAccess
.is() )
974 xControlAccess
->setLabel( ui::dialogs::CommonFilePickerElementIds::PUSHBUTTON_OK
, SfxResId(STR_EXPORTBUTTON
) );
975 xControlAccess
->setLabel( ui::dialogs::CommonFilePickerElementIds::LISTBOX_FILTER_LABEL
, SfxResId(STR_LABEL_FILEFORMAT
) );
980 // This is the normal save as dialog
981 pFileDlg
.reset(new sfx2::FileDialogHelper( aDialogMode
, aDialogFlags
, aDocServiceName
, nDialog
,
982 nMust
, nDont
, rStandardDir
, rDenyList
, pFrameWin
));
983 pFileDlg
->CreateMatcher( aDocServiceName
);
985 sfx2::FileDialogHelper::Context eCtxt
= sfx2::FileDialogHelper::UnknownContext
;
986 if ( aDocServiceName
== "com.sun.star.drawing.DrawingDocument" )
987 eCtxt
= sfx2::FileDialogHelper::DrawSaveAs
;
988 else if ( aDocServiceName
== "com.sun.star.presentation.PresentationDocument" )
989 eCtxt
= sfx2::FileDialogHelper::ImpressSaveAs
;
990 else if ( aDocServiceName
== "com.sun.star.text.TextDocument" )
991 eCtxt
= sfx2::FileDialogHelper::WriterSaveAs
;
992 else if ( aDocServiceName
== "com.sun.star.sheet.SpreadsheetDocument" )
993 eCtxt
= sfx2::FileDialogHelper::CalcSaveAs
;
995 if ( eCtxt
!= sfx2::FileDialogHelper::UnknownContext
)
996 pFileDlg
->SetContext( eCtxt
);
999 OUString aAdjustToType
;
1001 const OUString
sFilterNameString(aFilterNameString
);
1003 if ( ( nStoreMode
& EXPORT_REQUESTED
) && !( nStoreMode
& WIDEEXPORT_REQUESTED
) )
1005 // it is export, set the preselected filter
1006 pFileDlg
->SetCurrentFilter( aPreselectedFilterPropsHM
.getUnpackedValueOrDefault( "UIName", OUString() ) );
1007 aAdjustToType
= aPreselectedFilterPropsHM
.getUnpackedValueOrDefault( "Type", OUString() );
1009 // it is no export, bSetStandardName == true means that user agreed to store document in the default (default default ;-)) format
1010 else if ( bSetStandardName
|| GetStorable()->hasLocation() )
1012 uno::Sequence
< beans::PropertyValue
> aOldFilterProps
;
1013 const OUString aOldFilterName
= GetDocProps().getUnpackedValueOrDefault( sFilterNameString
, OUString() );
1015 if ( !aOldFilterName
.isEmpty() )
1016 m_pOwner
->GetFilterConfiguration()->getByName( aOldFilterName
) >>= aOldFilterProps
;
1018 ::comphelper::SequenceAsHashMap
aOldFiltPropsHM( aOldFilterProps
);
1019 SfxFilterFlags nOldFiltFlags
= static_cast<SfxFilterFlags
>(aOldFiltPropsHM
.getUnpackedValueOrDefault("Flags", sal_Int32(0) ));
1021 if ( bSetStandardName
|| ( nOldFiltFlags
& nMust
) != nMust
|| bool(nOldFiltFlags
& nDont
) )
1023 // the suggested type will be changed, the extension should be adjusted
1024 aAdjustToType
= aPreselectedFilterPropsHM
.getUnpackedValueOrDefault( "Type", OUString() );
1025 pFileDlg
->SetCurrentFilter( aPreselectedFilterPropsHM
.getUnpackedValueOrDefault( "UIName", OUString() ) );
1029 pFileDlg
->SetCurrentFilter( aOldFiltPropsHM
.getUnpackedValueOrDefault(
1035 const OUString aRecommendedDir
{GetRecommendedDir( aSuggestedDir
)};
1036 if ( !aRecommendedDir
.isEmpty() )
1037 pFileDlg
->SetDisplayFolder( aRecommendedDir
);
1038 const OUString aRecommendedName
{GetRecommendedName( aSuggestedName
, aAdjustToType
)};
1039 if ( !aRecommendedName
.isEmpty() )
1040 pFileDlg
->SetFileName( aRecommendedName
);
1042 uno::Reference
< view::XSelectionSupplier
> xSel( GetModel()->getCurrentController(), uno::UNO_QUERY
);
1043 if ( xSel
.is() && xSel
->getSelection().hasValue() )
1044 GetMediaDescr()[OUString("SelectionOnly")] <<= true;
1046 // This is a temporary hardcoded solution must be removed when
1047 // dialogs do not need parameters in SidSet representation any more
1048 sal_uInt16 nSlotID
= getSlotIDFromMode( nStoreMode
);
1050 throw lang::IllegalArgumentException(); // TODO:
1052 // generate SidSet from MediaDescriptor and provide it into FileDialog
1053 // than merge changed SidSet back
1054 std::optional
<SfxAllItemSet
> pDialogParams( SfxGetpApp()->GetPool() );
1055 TransformParameters( nSlotID
,
1056 GetMediaDescr().getAsConstPropertyValueList(),
1059 const SfxPoolItem
* pItem
= nullptr;
1060 if ( bPreselectPassword
&& pDialogParams
->GetItemState( SID_ENCRYPTIONDATA
, true, &pItem
) != SfxItemState::SET
)
1062 // the file dialog preselects the password checkbox if the provided mediadescriptor has encryption data entry
1063 // after dialog execution the password interaction flag will be either removed or not
1064 pDialogParams
->Put( SfxBoolItem( SID_PASSWORDINTERACTION
, true ) );
1067 // aFilterName is a pure output parameter, pDialogParams is an in/out parameter
1068 OUString aFilterName
;
1069 // in LOK case we don't show File Picker so it will fail, but execute to do other preparations
1070 if ( pFileDlg
->Execute( pDialogParams
, aFilterName
) != ERRCODE_NONE
1071 && !comphelper::LibreOfficeKit::isActive() )
1073 throw task::ErrorCodeIOException(
1074 "ModelData_Impl::OutputFileDialog: ERRCODE_IO_ABORT",
1075 uno::Reference
< uno::XInterface
>(), sal_uInt32(ERRCODE_IO_ABORT
));
1077 else if (comphelper::LibreOfficeKit::isActive())
1079 aFilterName
= aPreselectedFilterPropsHM
.getUnpackedValueOrDefault( "Name", OUString() );
1082 // the following two arguments can not be converted in MediaDescriptor,
1083 // so they should be removed from the ItemSet after retrieving
1084 const SfxBoolItem
* pRecommendReadOnly
= SfxItemSet::GetItem
<SfxBoolItem
>(&*pDialogParams
, SID_RECOMMENDREADONLY
, false);
1085 m_bRecommendReadOnly
= ( pRecommendReadOnly
&& pRecommendReadOnly
->GetValue() );
1086 pDialogParams
->ClearItem( SID_RECOMMENDREADONLY
);
1088 uno::Sequence
< beans::PropertyValue
> aPropsFromDialog
;
1089 TransformItems( nSlotID
, *pDialogParams
, aPropsFromDialog
);
1090 GetMediaDescr() << aPropsFromDialog
;
1092 // get the path from the dialog
1093 INetURLObject
aURL( pFileDlg
->GetPath() );
1095 if (comphelper::LibreOfficeKit::isActive())
1097 // keep name with extension
1098 aSuggestedName
= aRecommendedName
;
1099 OUString aExtension
;
1100 if (size_t nPos
= aSuggestedName
.lastIndexOf('.') + 1)
1101 aExtension
= aSuggestedName
.copy(nPos
, aSuggestedName
.getLength() - nPos
);
1102 aURL
.SetExtension(aExtension
);
1106 // the path should be provided outside since it might be used for further calls to the dialog
1107 aSuggestedName
= aURL
.GetLastName(INetURLObject::DecodeMechanism::WithCharset
);
1109 aSuggestedDir
= pFileDlg
->GetDisplayDirectory();
1111 // old filter options should be cleared in case different filter is used
1113 const OUString aFilterFromMediaDescr
= GetMediaDescr().getUnpackedValueOrDefault( sFilterNameString
, OUString() );
1114 const OUString aOldFilterName
= GetDocProps().getUnpackedValueOrDefault( sFilterNameString
, OUString() );
1116 if ( aFilterName
== aFilterFromMediaDescr
)
1118 // preserve current settings if any
1119 // if there no current settings and the name is the same
1120 // as old filter name use old filter settings
1122 if ( aFilterFromMediaDescr
== aOldFilterName
)
1124 ::comphelper::SequenceAsHashMap::const_iterator aIter
=
1125 GetDocProps().find( aFilterOptionsString
);
1126 if ( aIter
!= GetDocProps().end()
1127 && GetMediaDescr().find( aFilterOptionsString
) == GetMediaDescr().end() )
1128 GetMediaDescr()[aIter
->first
] = aIter
->second
;
1130 aIter
= GetDocProps().find( aFilterDataString
);
1131 if ( aIter
!= GetDocProps().end()
1132 && GetMediaDescr().find( aFilterDataString
) == GetMediaDescr().end() )
1133 GetMediaDescr()[aIter
->first
] = aIter
->second
;
1138 GetMediaDescr().erase( aFilterDataString
);
1139 GetMediaDescr().erase( aFilterOptionsString
);
1141 if ( aFilterName
== aOldFilterName
)
1143 // merge filter option of the document filter
1145 ::comphelper::SequenceAsHashMap::const_iterator aIter
=
1146 GetDocProps().find( aFilterOptionsString
);
1147 if ( aIter
!= GetDocProps().end() )
1148 GetMediaDescr()[aIter
->first
] = aIter
->second
;
1150 aIter
= GetDocProps().find( aFilterDataString
);
1151 if ( aIter
!= GetDocProps().end() )
1152 GetMediaDescr()[aIter
->first
] = aIter
->second
;
1156 uno::Reference
< ui::dialogs::XFilePickerControlAccess
> xExtFileDlg( pFileDlg
->GetFilePicker(), uno::UNO_QUERY
);
1157 if ( xExtFileDlg
.is() )
1159 if ( SfxStoringHelper::CheckFilterOptionsAppearance( m_pOwner
->GetFilterConfiguration(), aFilterName
) )
1160 bUseFilterOptions
= true;
1162 if ( ( !( nStoreMode
& EXPORT_REQUESTED
) || ( nStoreMode
& WIDEEXPORT_REQUESTED
) ) && bUseFilterOptions
)
1166 // for exporters: always show dialog if format uses options
1167 // for save: show dialog if format uses options and no options given or if forced by user
1169 xExtFileDlg
->getValue( ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS
, 0 );
1171 aVal
>>= bUseFilterOptions
;
1172 if ( !bUseFilterOptions
)
1174 ( GetMediaDescr().find( aFilterDataString
) == GetMediaDescr().end()
1175 && GetMediaDescr().find( aFilterOptionsString
) == GetMediaDescr().end() );
1177 catch( const lang::IllegalArgumentException
& )
1182 // merge in results of the dialog execution
1183 GetMediaDescr()[OUString("URL")] <<= aURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
1184 GetMediaDescr()[sFilterNameString
] <<= aFilterName
;
1186 return bUseFilterOptions
;
1190 bool ModelData_Impl::ShowDocumentInfoDialog()
1192 bool bDialogUsed
= false;
1195 uno::Reference
< frame::XController
> xController
= GetModel()->getCurrentController();
1196 if ( xController
.is() )
1198 uno::Reference
< frame::XDispatchProvider
> xFrameDispatch( xController
->getFrame(), uno::UNO_QUERY
);
1199 if ( xFrameDispatch
.is() )
1202 aURL
.Complete
= ".uno:SetDocumentProperties";
1204 uno::Reference
< util::XURLTransformer
> xTransformer( util::URLTransformer::create( comphelper::getProcessComponentContext() ) );
1205 if ( xTransformer
->parseStrict( aURL
) )
1207 uno::Reference
< frame::XDispatch
> xDispatch
= xFrameDispatch
->queryDispatch(
1211 if ( xDispatch
.is() )
1213 // tdf#119206 use (abuse?) a SynchronMode of true,
1214 // which will become SfxRequest::IsSynchronCall of true
1215 // in SfxObjectShell::ExecFile_Impl to request that we
1216 // do not want the properties dialog to be run async
1217 uno::Sequence
< beans::PropertyValue
> aProperties
{
1218 comphelper::makePropertyValue("SynchronMode", true)
1220 xDispatch
->dispatch(aURL
, aProperties
);
1227 catch ( const uno::Exception
& )
1235 OUString
ModelData_Impl::GetRecommendedExtension( const OUString
& aTypeName
)
1237 if ( aTypeName
.isEmpty() )
1240 uno::Reference
< container::XNameAccess
> xTypeDetection(
1241 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"),
1243 if ( xTypeDetection
.is() )
1245 uno::Sequence
< beans::PropertyValue
> aTypeNameProps
;
1246 if ( ( xTypeDetection
->getByName( aTypeName
) >>= aTypeNameProps
) && aTypeNameProps
.hasElements() )
1248 ::comphelper::SequenceAsHashMap
aTypeNamePropsHM( aTypeNameProps
);
1249 uno::Sequence
< OUString
> aExtensions
= aTypeNamePropsHM
.getUnpackedValueOrDefault(
1251 ::uno::Sequence
< OUString
>() );
1252 if ( aExtensions
.hasElements() )
1253 return aExtensions
[0];
1261 OUString
ModelData_Impl::GetRecommendedDir( const OUString
& aSuggestedDir
)
1263 if ( ( !aSuggestedDir
.isEmpty() || GetStorable()->hasLocation() )
1264 && !GetMediaDescr().getUnpackedValueOrDefault("RepairPackage", false ) )
1266 INetURLObject aLocation
;
1267 if ( !aSuggestedDir
.isEmpty() )
1268 aLocation
= INetURLObject( aSuggestedDir
);
1271 const OUString aOldURL
= GetStorable()->getLocation();
1272 if ( !aOldURL
.isEmpty() )
1274 INetURLObject
aTmp( aOldURL
);
1275 if ( aTmp
.removeSegment() )
1279 if ( aLocation
.HasError() )
1280 aLocation
= INetURLObject();
1283 OUString
sLocationURL( aLocation
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
1284 bool bIsInTempPath( false );
1285 OUString sSysTempPath
;
1286 if( osl::FileBase::getTempDirURL( sSysTempPath
) == osl::FileBase::E_None
)
1287 bIsInTempPath
= !sSysTempPath
.isEmpty() && sLocationURL
.startsWith( sSysTempPath
);
1289 if( !bIsInTempPath
)
1291 wchar_t sPath
[MAX_PATH
+1];
1292 HRESULT hRes
= SHGetFolderPathW( nullptr, CSIDL_INTERNET_CACHE
, nullptr, SHGFP_TYPE_CURRENT
, sPath
);
1293 if( SUCCEEDED(hRes
) )
1295 OUString sTempINetFiles
;
1296 if( osl::FileBase::getFileURLFromSystemPath(OUString(o3tl::toU(sPath
)), sTempINetFiles
) == osl::FileBase::E_None
)
1297 bIsInTempPath
= !sTempINetFiles
.isEmpty() && sLocationURL
.startsWith( sTempINetFiles
);
1301 // Suggest somewhere other than the system's temp directory
1303 aLocation
= INetURLObject();
1305 aLocation
.setFinalSlash();
1306 if ( !aLocation
.HasError() )
1307 return aLocation
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
1316 OUString
ModelData_Impl::GetRecommendedName( const OUString
& aSuggestedName
, const OUString
& aTypeName
)
1318 // the last used name might be provided by aSuggestedName from the old selection, or from the MediaDescriptor
1319 if ( !aSuggestedName
.isEmpty() )
1320 return aSuggestedName
;
1322 OUString aRecommendedName
{ INetURLObject(GetStorable()->getLocation())
1323 .GetLastName(INetURLObject::DecodeMechanism::WithCharset
) };
1324 if ( aRecommendedName
.isEmpty() )
1327 uno::Reference
< frame::XTitle
> xTitle( GetModel(), uno::UNO_QUERY_THROW
);
1328 aRecommendedName
= xTitle
->getTitle();
1329 } catch( const uno::Exception
& ) {}
1332 if ( !aRecommendedName
.isEmpty() && !aTypeName
.isEmpty() )
1334 // adjust the extension to the type
1335 uno::Reference
< container::XNameAccess
> xTypeDetection(
1336 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"),
1338 if ( xTypeDetection
.is() )
1340 INetURLObject
aObj( "c:/" + aRecommendedName
, INetProtocol::File
,
1341 INetURLObject::EncodeMechanism::All
, RTL_TEXTENCODING_UTF8
, FSysStyle::Dos
);
1343 const OUString aExtension
= GetRecommendedExtension( aTypeName
);
1344 if ( !aExtension
.isEmpty() )
1345 aObj
.SetExtension( aExtension
);
1347 aRecommendedName
= aObj
.GetLastName(INetURLObject::DecodeMechanism::WithCharset
);
1351 return aRecommendedName
;
1357 SfxStoringHelper::SfxStoringHelper()
1362 uno::Reference
< container::XNameAccess
> const & SfxStoringHelper::GetFilterConfiguration()
1364 if ( !m_xFilterCFG
.is() )
1366 m_xFilterCFG
.set( comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.FilterFactory"),
1367 uno::UNO_QUERY_THROW
);
1370 return m_xFilterCFG
;
1374 uno::Reference
< container::XContainerQuery
> const & SfxStoringHelper::GetFilterQuery()
1376 if ( !m_xFilterQuery
.is() )
1378 m_xFilterQuery
.set( GetFilterConfiguration(), uno::UNO_QUERY_THROW
);
1381 return m_xFilterQuery
;
1385 uno::Reference
< css::frame::XModuleManager2
> const & SfxStoringHelper::GetModuleManager()
1387 if ( !m_xModuleManager
.is() )
1389 m_xModuleManager
= frame::ModuleManager::create(
1390 comphelper::getProcessComponentContext() );
1393 return m_xModuleManager
;
1396 bool SfxStoringHelper::GUIStoreModel( const uno::Reference
< frame::XModel
>& xModel
,
1397 std::u16string_view aSlotName
,
1398 uno::Sequence
< beans::PropertyValue
>& aArgsSequence
,
1399 bool bPreselectPassword
,
1400 SignatureState nDocumentSignatureState
,
1403 m_xModelData
= std::make_shared
<ModelData_Impl
>( *this, xModel
, aArgsSequence
);
1404 m_aArgsSequence
= aArgsSequence
;
1405 ModelData_Impl
& aModelData
= *m_xModelData
;
1407 m_bDialogUsed
= false;
1409 m_bSetStandardName
= false; // can be set only for SaveAs
1410 m_bPreselectPassword
= bPreselectPassword
;
1412 // parse the slot name
1414 m_nStoreMode
= getStoreModeFromSlotName( aSlotName
);
1416 if ( m_nStoreMode
== SAVEASREMOTE_REQUESTED
)
1418 m_nStoreMode
= SAVEAS_REQUESTED
;
1422 sal_Int8 nStatusSave
= STATUS_NO_ACTION
;
1424 ::comphelper::SequenceAsHashMap::const_iterator aSaveACopyIter
=
1425 aModelData
.GetMediaDescr().find( OUString("SaveACopy") );
1426 if ( aSaveACopyIter
!= aModelData
.GetMediaDescr().end() )
1428 bool bSaveACopy
= false;
1429 aSaveACopyIter
->second
>>= bSaveACopy
;
1431 m_nStoreMode
= EXPORT_REQUESTED
| SAVEACOPY_REQUESTED
| WIDEEXPORT_REQUESTED
;
1433 // handle the special cases
1434 if ( m_nStoreMode
& SAVEAS_REQUESTED
)
1436 ::comphelper::SequenceAsHashMap::const_iterator aSaveToIter
=
1437 aModelData
.GetMediaDescr().find( OUString("SaveTo") );
1438 if ( aSaveToIter
!= aModelData
.GetMediaDescr().end() )
1440 bool bWideExport
= false;
1441 aSaveToIter
->second
>>= bWideExport
;
1443 m_nStoreMode
= EXPORT_REQUESTED
| WIDEEXPORT_REQUESTED
;
1446 // if saving is not acceptable the warning must be shown even in case of SaveAs operation
1447 if ( ( m_nStoreMode
& SAVEAS_REQUESTED
) && aModelData
.CheckSaveAcceptable( STATUS_SAVEAS
) == STATUS_NO_ACTION
)
1448 throw task::ErrorCodeIOException(
1449 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT",
1450 uno::Reference
< uno::XInterface
>(), sal_uInt32(ERRCODE_IO_ABORT
));
1452 else if ( m_nStoreMode
& SAVE_REQUESTED
)
1454 // if saving is not acceptable by the configuration the warning must be shown
1455 nStatusSave
= aModelData
.CheckSaveAcceptable( STATUS_SAVE
);
1457 if ( nStatusSave
== STATUS_NO_ACTION
)
1458 throw task::ErrorCodeIOException(
1459 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT",
1460 uno::Reference
< uno::XInterface
>(), sal_uInt32(ERRCODE_IO_ABORT
));
1461 else if ( nStatusSave
== STATUS_SAVE
)
1463 // check whether it is possible to use save operation
1464 nStatusSave
= aModelData
.CheckStateForSave();
1467 if ( nStatusSave
== STATUS_NO_ACTION
)
1469 throw task::ErrorCodeIOException(
1470 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT",
1471 uno::Reference
< uno::XInterface
>(), sal_uInt32(ERRCODE_IO_ABORT
));
1473 else if ( nStatusSave
!= STATUS_SAVE
)
1475 // this should be a usual SaveAs operation
1476 m_nStoreMode
= SAVEAS_REQUESTED
;
1477 if ( nStatusSave
== STATUS_SAVEAS_STANDARDNAME
)
1478 m_bSetStandardName
= true;
1482 if (!comphelper::LibreOfficeKit::isActive() && !( m_nStoreMode
& EXPORT_REQUESTED
) )
1484 // if it is no export, warn user that the signature will be removed
1485 if ( SignatureState::OK
== nDocumentSignatureState
1486 || SignatureState::INVALID
== nDocumentSignatureState
1487 || SignatureState::NOTVALIDATED
== nDocumentSignatureState
1488 || SignatureState::PARTIAL_OK
== nDocumentSignatureState
)
1490 std::unique_ptr
<weld::MessageDialog
> xMessageBox(Application::CreateMessageDialog(SfxStoringHelper::GetModelWindow(xModel
),
1491 VclMessageType::Question
, VclButtonsType::YesNo
, SfxResId(RID_SVXSTR_XMLSEC_QUERY_LOSINGSIGNATURE
)));
1492 if (xMessageBox
->run() != RET_YES
)
1494 // the user has decided not to store the document
1495 throw task::ErrorCodeIOException(
1496 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT (Preserve Signature)",
1497 uno::Reference
< uno::XInterface
>(), sal_uInt32(ERRCODE_IO_ABORT
));
1502 if ( m_nStoreMode
& SAVE_REQUESTED
&& nStatusSave
== STATUS_SAVE
)
1504 // Document properties can contain streams that should be freed before storing
1505 aModelData
.FreeDocumentProps();
1507 if ( aModelData
.GetStorable2().is() )
1511 aModelData
.GetStorable2()->storeSelf( aModelData
.GetMediaDescr().getAsConstPropertyValueList() );
1513 catch (const lang::IllegalArgumentException
&)
1515 TOOLS_WARN_EXCEPTION("sfx.doc", "Ignoring parameters! ModelData considers this illegal");
1516 aModelData
.GetStorable()->store();
1521 OSL_FAIL( "XStorable2 is not supported by the model!" );
1522 aModelData
.GetStorable()->store();
1528 // preselect a filter for the storing process
1529 uno::Sequence
< beans::PropertyValue
> aFilterProps
= aModelData
.GetPreselectedFilter_Impl( m_nStoreMode
);
1531 DBG_ASSERT( aFilterProps
.hasElements(), "No filter for storing!\n" );
1532 if ( !aFilterProps
.hasElements() )
1533 throw task::ErrorCodeIOException(
1534 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_INVALIDPARAMETER",
1535 uno::Reference
< uno::XInterface
>(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER
));
1537 ::comphelper::SequenceAsHashMap
aFilterPropsHM( aFilterProps
);
1538 OUString aFilterName
= aFilterPropsHM
.getUnpackedValueOrDefault( "Name", OUString() );
1540 const OUString aFilterFromMediaDescr
= aModelData
.GetMediaDescr().getUnpackedValueOrDefault( aFilterNameString
, OUString() );
1541 const OUString aOldFilterName
= aModelData
.GetDocProps().getUnpackedValueOrDefault( aFilterNameString
, OUString() );
1543 ::comphelper::SequenceAsHashMap::const_iterator aFileNameIter
= aModelData
.GetMediaDescr().find( OUString("URL") );
1545 bool bPDFOptions
= (m_nStoreMode
& PDFEXPORT_REQUESTED
) && !(m_nStoreMode
& PDFDIRECTEXPORT_REQUESTED
);
1546 bool bEPUBOptions
= (m_nStoreMode
& EPUBEXPORT_REQUESTED
) && !(m_nStoreMode
& EPUBDIRECTEXPORT_REQUESTED
);
1547 if ( ( m_nStoreMode
& EXPORT_REQUESTED
) && (bPDFOptions
|| bEPUBOptions
) )
1549 // this is PDF or EPUB export, the filter options dialog should be shown before the export
1550 aModelData
.GetMediaDescr()[aFilterNameString
] <<= aFilterName
;
1551 if ( aModelData
.GetMediaDescr().find( "FilterFlags" ) == aModelData
.GetMediaDescr().end()
1552 && aModelData
.GetMediaDescr().find( aFilterOptionsString
) == aModelData
.GetMediaDescr().end()
1553 && aModelData
.GetMediaDescr().find( aFilterDataString
) == aModelData
.GetMediaDescr().end() )
1555 // execute filter options dialog since no options are set in the media descriptor
1556 if ( aModelData
.ExecuteFilterDialog_Impl( aFilterName
, bIsAsync
) )
1557 m_bDialogUsed
= true;
1564 return SfxStoringHelper::FinishGUIStoreModel(aFileNameIter
, aModelData
, m_bRemote
, m_nStoreMode
, aFilterProps
,
1565 m_bSetStandardName
, m_bPreselectPassword
, m_bDialogUsed
,
1566 aFilterFromMediaDescr
, aOldFilterName
, aArgsSequence
, aFilterName
);
1569 bool SfxStoringHelper::FinishGUIStoreModel(::comphelper::SequenceAsHashMap::const_iterator
& aFileNameIter
,
1570 ModelData_Impl
& aModelData
, bool bRemote
, sal_Int16 nStoreMode
,
1571 uno::Sequence
< beans::PropertyValue
>& aFilterProps
,
1572 bool bSetStandardName
, bool bPreselectPassword
, bool bDialogUsed
,
1573 std::u16string_view aFilterFromMediaDescr
,
1574 std::u16string_view aOldFilterName
,
1575 uno::Sequence
< beans::PropertyValue
>& aArgsSequence
,
1576 OUString aFilterName
)
1578 const OUString
sFilterNameString(aFilterNameString
);
1579 const OUString
sFilterOptionsString(aFilterOptionsString
);
1580 const OUString
sFilterDataString(aFilterDataString
);
1581 bool bUseFilterOptions
= false;
1584 if ( aFileNameIter
== aModelData
.GetMediaDescr().end() )
1586 sal_Int16 nDialog
= SFX2_IMPL_DIALOG_CONFIG
;
1590 nDialog
= SFX2_IMPL_DIALOG_REMOTE
;
1594 ::comphelper::SequenceAsHashMap::const_iterator aDlgIter
=
1595 aModelData
.GetMediaDescr().find( OUString("UseSystemDialog") );
1596 if ( aDlgIter
!= aModelData
.GetMediaDescr().end() )
1598 bool bUseSystemDialog
= true;
1599 if ( aDlgIter
->second
>>= bUseSystemDialog
)
1601 if ( bUseSystemDialog
)
1602 nDialog
= SFX2_IMPL_DIALOG_SYSTEM
;
1604 nDialog
= SFX2_IMPL_DIALOG_OOO
;
1609 // The Dispatch supports parameter FolderName that overwrites SuggestedSaveAsDir
1610 OUString aSuggestedDir
= aModelData
.GetMediaDescr().getUnpackedValueOrDefault("FolderName", OUString() );
1611 if ( aSuggestedDir
.isEmpty() )
1613 aSuggestedDir
= aModelData
.GetMediaDescr().getUnpackedValueOrDefault("SuggestedSaveAsDir", OUString() );
1614 if ( aSuggestedDir
.isEmpty() )
1615 aSuggestedDir
= aModelData
.GetDocProps().getUnpackedValueOrDefault("SuggestedSaveAsDir", OUString() );
1618 OUString aSuggestedName
= aModelData
.GetMediaDescr().getUnpackedValueOrDefault("SuggestedSaveAsName", OUString() );
1619 if ( aSuggestedName
.isEmpty() )
1620 aSuggestedName
= aModelData
.GetDocProps().getUnpackedValueOrDefault("SuggestedSaveAsName", OUString() );
1622 OUString sStandardDir
;
1623 ::comphelper::SequenceAsHashMap::const_iterator aStdDirIter
=
1624 aModelData
.GetMediaDescr().find( OUString("StandardDir") );
1625 if ( aStdDirIter
!= aModelData
.GetMediaDescr().end() )
1626 aStdDirIter
->second
>>= sStandardDir
;
1628 css::uno::Sequence
< OUString
> aDenyList
;
1630 ::comphelper::SequenceAsHashMap::const_iterator aDenyListIter
=
1631 aModelData
.GetMediaDescr().find( OUString("DenyList") );
1632 if ( aDenyListIter
!= aModelData
.GetMediaDescr().end() )
1633 aDenyListIter
->second
>>= aDenyList
;
1637 // 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
1638 bUseFilterOptions
= aModelData
.OutputFileDialog( nStoreMode
, aFilterProps
, bSetStandardName
, aSuggestedName
, bPreselectPassword
, aSuggestedDir
, nDialog
, sStandardDir
, aDenyList
);
1639 if ( nStoreMode
== SAVEAS_REQUESTED
)
1641 // in case of saving check filter for possible alien warning
1642 const OUString aSelFilterName
= aModelData
.GetMediaDescr().getUnpackedValueOrDefault( sFilterNameString
, OUString() );
1643 sal_Int8 nStatusFilterSave
= aModelData
.CheckFilter( aSelFilterName
);
1644 if ( nStatusFilterSave
== STATUS_SAVEAS_STANDARDNAME
)
1646 // switch to best filter
1647 bSetStandardName
= true;
1649 else if ( nStatusFilterSave
== STATUS_SAVE
)
1651 // user confirmed alien filter or "good" filter is used
1660 aFileNameIter
= aModelData
.GetMediaDescr().find( OUString("URL") );
1664 // the target file name is provided so check if new filter options
1665 // are provided or old options can be used
1666 if ( aFilterFromMediaDescr
== aOldFilterName
)
1668 ::comphelper::SequenceAsHashMap::const_iterator aIter
=
1669 aModelData
.GetDocProps().find( sFilterOptionsString
);
1670 if ( aIter
!= aModelData
.GetDocProps().end()
1671 && aModelData
.GetMediaDescr().find( sFilterOptionsString
) == aModelData
.GetMediaDescr().end() )
1672 aModelData
.GetMediaDescr()[aIter
->first
] = aIter
->second
;
1674 aIter
= aModelData
.GetDocProps().find( sFilterDataString
);
1675 if ( aIter
!= aModelData
.GetDocProps().end()
1676 && aModelData
.GetMediaDescr().find( sFilterDataString
) == aModelData
.GetMediaDescr().end() )
1677 aModelData
.GetMediaDescr()[aIter
->first
] = aIter
->second
;
1681 if ( aFileNameIter
!= aModelData
.GetMediaDescr().end() )
1684 aFileNameIter
->second
>>= aFileName
;
1685 aURL
.SetURL( aFileName
);
1686 DBG_ASSERT( aURL
.GetProtocol() != INetProtocol::NotValid
, "Illegal URL!" );
1688 ::comphelper::SequenceAsHashMap::const_iterator aIter
=
1689 aModelData
.GetMediaDescr().find( sFilterNameString
);
1691 if ( aIter
!= aModelData
.GetMediaDescr().end() )
1692 aIter
->second
>>= aFilterName
;
1694 aModelData
.GetMediaDescr()[sFilterNameString
] <<= aFilterName
;
1696 DBG_ASSERT( !aFilterName
.isEmpty(), "Illegal filter!" );
1700 SAL_WARN( "sfx.doc", "This code must be unreachable!" );
1701 throw task::ErrorCodeIOException(
1702 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_INVALIDPARAMETER",
1703 uno::Reference
< uno::XInterface
>(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER
));
1706 ::comphelper::SequenceAsHashMap::const_iterator aIter
=
1707 aModelData
.GetMediaDescr().find( OUString("FilterFlags") );
1708 bool bFilterFlagsSet
= ( aIter
!= aModelData
.GetMediaDescr().end() );
1710 // check if the filter Dialog has not been called before
1711 if( !( nStoreMode
& PDFEXPORT_REQUESTED
) && !( nStoreMode
& EPUBEXPORT_REQUESTED
) && !bFilterFlagsSet
1712 && ( ( nStoreMode
& EXPORT_REQUESTED
) || bUseFilterOptions
) )
1714 // execute filter options dialog
1715 if ( aModelData
.ExecuteFilterDialog_Impl( aFilterName
, false ) )
1718 // check if the file is a pdf or not and change the storing mode at convenience
1719 if (aFilterName
.endsWith("pdf_Export"))
1720 nStoreMode
= EXPORT_REQUESTED
| PDFEXPORT_REQUESTED
;
1724 // so the arguments will not change any more and can be stored to the main location
1725 aArgsSequence
= aModelData
.GetMediaDescr().getAsConstPropertyValueList();
1727 // store the document and handle it's docinfo
1729 DocumentSettingsGuard
aSettingsGuard( aModelData
.GetModel(), aModelData
.IsRecommendReadOnly(), nStoreMode
& EXPORT_REQUESTED
);
1731 OSL_ENSURE( aModelData
.GetMediaDescr().find( OUString( "Password" ) ) == aModelData
.GetMediaDescr().end(), "The Password property of MediaDescriptor should not be used here!" );
1732 if ( officecfg::Office::Common::Save::Document::EditProperty::get()
1733 && ( !aModelData
.GetStorable()->hasLocation()
1734 || INetURLObject( aModelData
.GetStorable()->getLocation() ) != aURL
) )
1736 // this is definitely not a Save operation
1737 // so the document info can be updated
1739 // on export document info must be preserved
1740 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
1741 aModelData
.GetModel(), uno::UNO_QUERY_THROW
);
1742 uno::Reference
<util::XCloneable
> xCloneable(
1743 xDPS
->getDocumentProperties(), uno::UNO_QUERY_THROW
);
1744 uno::Reference
<document::XDocumentProperties
> xOldDocProps(
1745 xCloneable
->createClone(), uno::UNO_QUERY_THROW
);
1747 // use dispatch API to show document info dialog
1748 if ( aModelData
.ShowDocumentInfoDialog() )
1752 OSL_FAIL( "Can't execute document info dialog!" );
1756 // Document properties can contain streams that should be freed before storing
1757 aModelData
.FreeDocumentProps();
1758 if ( nStoreMode
& EXPORT_REQUESTED
)
1759 aModelData
.GetStorable()->storeToURL( aURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), aArgsSequence
);
1761 aModelData
.GetStorable()->storeAsURL( aURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), aArgsSequence
);
1763 catch( const uno::Exception
& )
1765 if ( nStoreMode
& EXPORT_REQUESTED
)
1767 SetDocInfoState(aModelData
.GetModel(), xOldDocProps
);
1772 if ( nStoreMode
& EXPORT_REQUESTED
)
1774 SetDocInfoState(aModelData
.GetModel(), xOldDocProps
);
1779 // Document properties can contain streams that should be freed before storing
1780 aModelData
.FreeDocumentProps();
1782 // this is actually a save operation with different parameters
1783 // so storeTo or storeAs without DocInfo operations are used
1784 if ( nStoreMode
& EXPORT_REQUESTED
)
1785 aModelData
.GetStorable()->storeToURL( aURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), aArgsSequence
);
1787 aModelData
.GetStorable()->storeAsURL( aURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), aArgsSequence
);
1790 // Launch PDF viewer
1791 if ( nStoreMode
& PDFEXPORT_REQUESTED
&& !comphelper::LibreOfficeKit::isActive() )
1793 FilterConfigItem
aItem(u
"Office.Common/Filter/PDF/Export/");
1794 bool aViewPDF
= aItem
.ReadBool( "ViewPDFAfterExport", false );
1798 uno::Reference
<XSystemShellExecute
> xSystemShellExecute(SystemShellExecute::create( ::comphelper::getProcessComponentContext() ) );
1799 xSystemShellExecute
->execute( aURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), "", SystemShellExecuteFlags::URIS_ONLY
);
1803 if ( comphelper::LibreOfficeKit::isActive() )
1805 if ( SfxViewShell
* pShell
= SfxViewShell::Current() )
1807 OUString sURL
= aURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
1808 pShell
->libreOfficeKitViewCallback( LOK_CALLBACK_EXPORT_FILE
,
1809 OUStringToOString(sURL
, RTL_TEXTENCODING_UTF8
).getStr() );
1818 bool SfxStoringHelper::CheckFilterOptionsAppearance(
1819 const uno::Reference
< container::XNameAccess
>& xFilterCFG
,
1820 const OUString
& aFilterName
)
1822 bool bUseFilterOptions
= false;
1824 DBG_ASSERT( xFilterCFG
.is(), "No filter configuration!\n" );
1825 if( xFilterCFG
.is() )
1828 uno::Sequence
< beans::PropertyValue
> aProps
;
1829 uno::Any aAny
= xFilterCFG
->getByName( aFilterName
);
1830 if ( aAny
>>= aProps
)
1832 ::comphelper::SequenceAsHashMap
aPropsHM( aProps
);
1833 if( !aPropsHM
.getUnpackedValueOrDefault( "UIComponent", OUString() ).isEmpty() )
1834 bUseFilterOptions
= true;
1837 catch( const uno::Exception
& )
1842 return bUseFilterOptions
;
1847 void SfxStoringHelper::SetDocInfoState(
1848 const uno::Reference
< frame::XModel
>& xModel
,
1849 const uno::Reference
< document::XDocumentProperties
>& i_xOldDocProps
)
1851 uno::Reference
<document::XDocumentPropertiesSupplier
> const
1852 xModelDocPropsSupplier(xModel
, uno::UNO_QUERY_THROW
);
1853 uno::Reference
<document::XDocumentProperties
> const xDocPropsToFill
=
1854 xModelDocPropsSupplier
->getDocumentProperties();
1855 uno::Reference
< beans::XPropertySet
> const xPropSet(
1856 i_xOldDocProps
->getUserDefinedProperties(), uno::UNO_QUERY_THROW
);
1858 uno::Reference
< util::XModifiable
> xModifiable( xModel
, uno::UNO_QUERY
);
1859 if ( !xModifiable
.is() )
1860 throw uno::RuntimeException();
1862 bool bIsModified
= xModifiable
->isModified();
1866 uno::Reference
< beans::XPropertySet
> const xSet(
1867 xDocPropsToFill
->getUserDefinedProperties(), uno::UNO_QUERY
);
1868 uno::Reference
< beans::XPropertyContainer
> xContainer( xSet
, uno::UNO_QUERY
);
1869 uno::Reference
< beans::XPropertySetInfo
> xSetInfo
= xSet
->getPropertySetInfo();
1870 const uno::Sequence
< beans::Property
> lProps
= xSetInfo
->getProperties();
1871 for (const beans::Property
& rProp
: lProps
)
1873 uno::Any aValue
= xPropSet
->getPropertyValue( rProp
.Name
);
1874 if ( rProp
.Attributes
& css::beans::PropertyAttribute::REMOVABLE
)
1878 // QUESTION: DefaultValue?!
1879 xContainer
->addProperty( rProp
.Name
, rProp
.Attributes
, aValue
);
1881 catch (beans::PropertyExistException
const&) {}
1884 // it is possible that the propertysets from XML and binary files differ; we shouldn't break then
1885 xSet
->setPropertyValue( rProp
.Name
, aValue
);
1887 catch ( const uno::Exception
& ) {}
1891 // sigh... have to set these manually I'm afraid... wonder why
1892 // SfxObjectShell doesn't handle this internally, should be easier
1893 xDocPropsToFill
->setAuthor(i_xOldDocProps
->getAuthor());
1894 xDocPropsToFill
->setGenerator(i_xOldDocProps
->getGenerator());
1895 xDocPropsToFill
->setCreationDate(i_xOldDocProps
->getCreationDate());
1896 xDocPropsToFill
->setTitle(i_xOldDocProps
->getTitle());
1897 xDocPropsToFill
->setSubject(i_xOldDocProps
->getSubject());
1898 xDocPropsToFill
->setDescription(i_xOldDocProps
->getDescription());
1899 xDocPropsToFill
->setKeywords(i_xOldDocProps
->getKeywords());
1900 xDocPropsToFill
->setModifiedBy(i_xOldDocProps
->getModifiedBy());
1901 xDocPropsToFill
->setModificationDate(i_xOldDocProps
->getModificationDate());
1902 xDocPropsToFill
->setPrintedBy(i_xOldDocProps
->getPrintedBy());
1903 xDocPropsToFill
->setPrintDate(i_xOldDocProps
->getPrintDate());
1904 xDocPropsToFill
->setAutoloadURL(i_xOldDocProps
->getAutoloadURL());
1905 xDocPropsToFill
->setAutoloadSecs(i_xOldDocProps
->getAutoloadSecs());
1906 xDocPropsToFill
->setDefaultTarget(i_xOldDocProps
->getDefaultTarget());
1907 xDocPropsToFill
->setEditingCycles(i_xOldDocProps
->getEditingCycles());
1908 xDocPropsToFill
->setEditingDuration(i_xOldDocProps
->getEditingDuration());
1909 // other attributes e.g. DocumentStatistics are not editable from dialog
1911 catch (const uno::Exception
&)
1913 TOOLS_INFO_EXCEPTION("sfx.doc", "SetDocInfoState");
1916 // set the modified flag back if required
1917 if ( bIsModified
!= bool(xModifiable
->isModified()) )
1918 xModifiable
->setModified( bIsModified
);
1923 bool SfxStoringHelper::WarnUnacceptableFormat( const uno::Reference
< frame::XModel
>& xModel
,
1924 std::u16string_view aOldUIName
,
1925 const OUString
& aDefExtension
,
1928 if ( !officecfg::Office::Common::Save::Document::WarnAlienFormat::get() )
1931 weld::Window
* pWin
= SfxStoringHelper::GetModelWindow(xModel
);
1932 SfxAlienWarningDialog
aDlg(pWin
, aOldUIName
, aDefExtension
, bDefIsAlien
);
1934 return aDlg
.run() == RET_OK
;
1937 uno::Reference
<awt::XWindow
> SfxStoringHelper::GetModelXWindow(const uno::Reference
<frame::XModel
>& xModel
)
1942 uno::Reference
< frame::XController
> xController
= xModel
->getCurrentController();
1943 if ( xController
.is() )
1945 uno::Reference
< frame::XFrame
> xFrame
= xController
->getFrame();
1948 return xFrame
->getContainerWindow();
1953 catch ( const uno::Exception
& )
1957 return uno::Reference
<awt::XWindow
>();
1960 weld::Window
* SfxStoringHelper::GetModelWindow( const uno::Reference
< frame::XModel
>& xModel
)
1962 weld::Window
* pWin
= nullptr;
1966 pWin
= Application::GetFrameWeld(GetModelXWindow(xModel
));
1968 catch (const uno::Exception
&)
1975 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */