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 .
21 #include <string_view>
23 #include <sfx2/filedlghelper.hxx>
24 #include <sal/types.h>
25 #include <com/sun/star/lang/XInitialization.hpp>
26 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
27 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
28 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
29 #include <com/sun/star/ui/dialogs/FilePreviewImageFormats.hpp>
30 #include <com/sun/star/ui/dialogs/ControlActions.hpp>
31 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
32 #include <com/sun/star/ui/dialogs/XControlInformation.hpp>
33 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
34 #include <com/sun/star/ui/dialogs/XFilePreview.hpp>
35 #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
36 #include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
37 #include <com/sun/star/ui/dialogs/XAsynchronousExecutableDialog.hpp>
38 #include <com/sun/star/lang/XServiceInfo.hpp>
39 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
40 #include <com/sun/star/beans/PropertyValue.hpp>
41 #include <com/sun/star/beans/NamedValue.hpp>
42 #include <com/sun/star/embed/ElementModes.hpp>
43 #include <com/sun/star/container/XEnumeration.hpp>
44 #include <com/sun/star/container/XContainerQuery.hpp>
45 #include <com/sun/star/task/InteractionHandler.hpp>
46 #include <com/sun/star/task/XInteractionRequest.hpp>
47 #include <com/sun/star/util/RevisionTag.hpp>
48 #include <comphelper/fileurl.hxx>
49 #include <comphelper/processfactory.hxx>
50 #include <comphelper/sequenceashashmap.hxx>
51 #include <comphelper/string.hxx>
52 #include <comphelper/types.hxx>
53 #include <tools/urlobj.hxx>
54 #include <vcl/help.hxx>
55 #include <vcl/weld.hxx>
56 #include <unotools/ucbstreamhelper.hxx>
57 #include <unotools/ucbhelper.hxx>
58 #include <osl/file.hxx>
59 #include <osl/security.hxx>
60 #include <vcl/mnemonic.hxx>
61 #include <vcl/svapp.hxx>
62 #include <unotools/pathoptions.hxx>
63 #include <unotools/saveopt.hxx>
64 #include <unotools/securityoptions.hxx>
65 #include <svl/itemset.hxx>
66 #include <svl/eitem.hxx>
67 #include <svl/intitem.hxx>
68 #include <vcl/dibtools.hxx>
69 #include <vcl/graphicfilter.hxx>
70 #include <unotools/viewoptions.hxx>
71 #include <svtools/helpids.h>
72 #include <comphelper/docpasswordrequest.hxx>
73 #include <comphelper/docpasswordhelper.hxx>
74 #include <ucbhelper/content.hxx>
75 #include <comphelper/storagehelper.hxx>
76 #include <sfx2/app.hxx>
77 #include <sfx2/frame.hxx>
78 #include <sfx2/docfile.hxx>
79 #include <sfx2/docfilt.hxx>
80 #include <sfx2/objsh.hxx>
81 #include <sfx2/sfxresid.hxx>
82 #include <sfx2/sfxsids.hrc>
83 #include "filtergrouping.hxx"
84 #include "filedlgimpl.hxx"
85 #include <sfx2/strings.hrc>
86 #include <sal/log.hxx>
87 #include <comphelper/sequence.hxx>
88 #include <tools/diagnose_ex.h>
95 using namespace ::com::sun::star
;
96 using namespace ::com::sun::star::container
;
97 using namespace ::com::sun::star::lang
;
98 using namespace ::com::sun::star::ui::dialogs
;
99 using namespace ::com::sun::star::ui::dialogs::TemplateDescription
;
100 using namespace ::com::sun::star::uno
;
101 using namespace ::com::sun::star::beans
;
102 using namespace ::cppu
;
104 #define IODLG_CONFIGNAME "FilePicker_Save"
105 #define IMPGRF_CONFIGNAME "FilePicker_Graph"
106 #define USERITEM_NAME "UserItem"
113 bool lclSupportsOOXMLEncryption(const OUString
& aFilterName
)
115 return aFilterName
== "Calc MS Excel 2007 XML"
116 || aFilterName
== "MS Word 2007 XML"
117 || aFilterName
== "Impress MS PowerPoint 2007 XML"
118 || aFilterName
== "Impress MS PowerPoint 2007 XML AutoPlay"
119 || aFilterName
== "Calc Office Open XML"
120 || aFilterName
== "Impress Office Open XML"
121 || aFilterName
== "Impress Office Open XML AutoPlay"
122 || aFilterName
== "Office Open XML Text";
126 static const std::u16string_view
* GetLastFilterConfigId( FileDialogHelper::Context _eContext
)
128 static const std::u16string_view
aSD_EXPORT_IDENTIFIER(u
"SdExportLastFilter");
129 static const std::u16string_view
aSI_EXPORT_IDENTIFIER(u
"SiExportLastFilter");
130 static const std::u16string_view
aSW_EXPORT_IDENTIFIER(u
"SwExportLastFilter");
132 const std::u16string_view
* pRet
= nullptr;
136 case FileDialogHelper::SD_EXPORT
: pRet
= &aSD_EXPORT_IDENTIFIER
; break;
137 case FileDialogHelper::SI_EXPORT
: pRet
= &aSI_EXPORT_IDENTIFIER
; break;
138 case FileDialogHelper::SW_EXPORT
: pRet
= &aSW_EXPORT_IDENTIFIER
; break;
145 static OUString
EncodeSpaces_Impl( const OUString
& rSource
);
146 static OUString
DecodeSpaces_Impl( const OUString
& rSource
);
148 // FileDialogHelper_Impl
150 // XFilePickerListener Methods
151 void SAL_CALL
FileDialogHelper_Impl::fileSelectionChanged( const FilePickerEvent
& )
153 SolarMutexGuard aGuard
;
154 mpAntiImpl
->FileSelectionChanged();
157 void SAL_CALL
FileDialogHelper_Impl::directoryChanged( const FilePickerEvent
& )
159 SolarMutexGuard aGuard
;
160 mpAntiImpl
->DirectoryChanged();
163 OUString SAL_CALL
FileDialogHelper_Impl::helpRequested( const FilePickerEvent
& aEvent
)
165 SolarMutexGuard aGuard
;
166 return sfx2::FileDialogHelper::HelpRequested( aEvent
);
169 void SAL_CALL
FileDialogHelper_Impl::controlStateChanged( const FilePickerEvent
& aEvent
)
171 SolarMutexGuard aGuard
;
172 mpAntiImpl
->ControlStateChanged( aEvent
);
175 void SAL_CALL
FileDialogHelper_Impl::dialogSizeChanged()
177 SolarMutexGuard aGuard
;
178 mpAntiImpl
->DialogSizeChanged();
181 // XDialogClosedListener Methods
182 void SAL_CALL
FileDialogHelper_Impl::dialogClosed( const DialogClosedEvent
& _rEvent
)
184 SolarMutexGuard aGuard
;
185 mpAntiImpl
->DialogClosed( _rEvent
);
186 postExecute( _rEvent
.DialogResult
);
189 // handle XFilePickerListener events
190 void FileDialogHelper_Impl::handleFileSelectionChanged()
196 maPreviewIdle
.Start();
199 void FileDialogHelper_Impl::handleDirectoryChanged()
202 TimeOutHdl_Impl( nullptr );
205 OUString
FileDialogHelper_Impl::handleHelpRequested( const FilePickerEvent
& aEvent
)
207 //!!! todo: cache the help strings (here or TRA)
210 // mapping from element id -> help id
211 switch ( aEvent
.ElementId
)
213 case ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION
:
214 sHelpId
= HID_FILESAVE_AUTOEXTENSION
;
217 case ExtendedFilePickerElementIds::CHECKBOX_PASSWORD
:
218 sHelpId
= HID_FILESAVE_SAVEWITHPASSWORD
;
221 case ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS
:
222 sHelpId
= HID_FILESAVE_CUSTOMIZEFILTER
;
225 case ExtendedFilePickerElementIds::CHECKBOX_READONLY
:
226 sHelpId
= HID_FILEOPEN_READONLY
;
229 case ExtendedFilePickerElementIds::CHECKBOX_LINK
:
230 sHelpId
= HID_FILEDLG_LINK_CB
;
233 case ExtendedFilePickerElementIds::CHECKBOX_PREVIEW
:
234 sHelpId
= HID_FILEDLG_PREVIEW_CB
;
237 case ExtendedFilePickerElementIds::PUSHBUTTON_PLAY
:
238 sHelpId
= HID_FILESAVE_DOPLAY
;
241 case ExtendedFilePickerElementIds::LISTBOX_VERSION_LABEL
:
242 case ExtendedFilePickerElementIds::LISTBOX_VERSION
:
243 sHelpId
= HID_FILEOPEN_VERSION
;
246 case ExtendedFilePickerElementIds::LISTBOX_TEMPLATE_LABEL
:
247 case ExtendedFilePickerElementIds::LISTBOX_TEMPLATE
:
248 sHelpId
= HID_FILESAVE_TEMPLATE
;
251 case ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE_LABEL
:
252 case ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE
:
253 sHelpId
= HID_FILEOPEN_IMAGE_TEMPLATE
;
256 case ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR_LABEL
:
257 case ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR
:
258 sHelpId
= HID_FILEOPEN_IMAGE_ANCHOR
;
261 case ExtendedFilePickerElementIds::CHECKBOX_SELECTION
:
262 sHelpId
= HID_FILESAVE_SELECTION
;
266 SAL_WARN( "sfx.dialog", "invalid element id" );
270 Help
* pHelp
= Application::GetHelp();
272 aHelpText
= pHelp
->GetHelpText(OStringToOUString(sHelpId
, RTL_TEXTENCODING_UTF8
), static_cast<weld::Widget
*>(nullptr));
276 void FileDialogHelper_Impl::handleControlStateChanged( const FilePickerEvent
& aEvent
)
278 switch ( aEvent
.ElementId
)
280 case CommonFilePickerElementIds::LISTBOX_FILTER
:
281 updateFilterOptionsBox();
282 enablePasswordBox( false );
283 updateSelectionBox();
284 // only use it for export and with our own dialog
285 if ( mbExport
&& !mbSystemPicker
)
286 updateExportButton();
289 case ExtendedFilePickerElementIds::CHECKBOX_PREVIEW
:
290 updatePreviewState(true);
295 void FileDialogHelper_Impl::handleDialogSizeChanged()
298 TimeOutHdl_Impl( nullptr );
301 // XEventListener Methods
302 void SAL_CALL
FileDialogHelper_Impl::disposing( const EventObject
& )
304 SolarMutexGuard aGuard
;
308 void FileDialogHelper_Impl::dispose()
310 if ( mxFileDlg
.is() )
312 // remove the event listener
313 mxFileDlg
->removeFilePickerListener( this );
315 ::comphelper::disposeComponent( mxFileDlg
);
320 OUString
FileDialogHelper_Impl::getCurrentFilterUIName() const
322 OUString aFilterName
;
326 aFilterName
= mxFileDlg
->getCurrentFilter();
328 if ( !aFilterName
.isEmpty() && isShowFilterExtensionEnabled() )
329 aFilterName
= getFilterName( aFilterName
);
335 void FileDialogHelper_Impl::LoadLastUsedFilter( const OUString
& _rContextIdentifier
)
337 SvtViewOptions
aDlgOpt( EViewType::Dialog
, IODLG_CONFIGNAME
);
339 if( aDlgOpt
.Exists() )
341 OUString aLastFilter
;
342 if( aDlgOpt
.GetUserItem( _rContextIdentifier
) >>= aLastFilter
)
343 setFilter( aLastFilter
);
347 void FileDialogHelper_Impl::SaveLastUsedFilter()
349 const std::u16string_view
* pConfigId
= GetLastFilterConfigId( meContext
);
351 SvtViewOptions( EViewType::Dialog
, IODLG_CONFIGNAME
).SetUserItem( *pConfigId
,
352 makeAny( getFilterWithExtension( getFilter() ) ) );
355 std::shared_ptr
<const SfxFilter
> FileDialogHelper_Impl::getCurentSfxFilter()
357 OUString aFilterName
= getCurrentFilterUIName();
359 if ( mpMatcher
&& !aFilterName
.isEmpty() )
360 return mpMatcher
->GetFilter4UIName( aFilterName
, m_nMustFlags
, m_nDontFlags
);
365 bool FileDialogHelper_Impl::updateExtendedControl( sal_Int16 _nExtendedControlId
, bool _bEnable
)
367 bool bIsEnabled
= false;
369 uno::Reference
< XFilePickerControlAccess
> xCtrlAccess( mxFileDlg
, UNO_QUERY
);
370 if ( xCtrlAccess
.is() )
374 xCtrlAccess
->enableControl( _nExtendedControlId
, _bEnable
);
375 bIsEnabled
= _bEnable
;
377 catch( const IllegalArgumentException
& )
379 TOOLS_WARN_EXCEPTION( "sfx", "FileDialogHelper_Impl::updateExtendedControl" );
385 bool FileDialogHelper_Impl::CheckFilterOptionsCapability( const std::shared_ptr
<const SfxFilter
>& _pFilter
)
387 bool bResult
= false;
389 if( mxFilterCFG
.is() && _pFilter
)
393 Sequence
< PropertyValue
> aProps
;
394 Any aAny
= mxFilterCFG
->getByName( _pFilter
->GetName() );
395 if ( aAny
>>= aProps
)
397 OUString aServiceName
;
398 for( const auto& rProp
: std::as_const(aProps
) )
400 if( rProp
.Name
== "UIComponent" )
402 rProp
.Value
>>= aServiceName
;
403 if( !aServiceName
.isEmpty() )
409 catch( const Exception
& )
417 bool FileDialogHelper_Impl::isInOpenMode() const
421 switch ( m_nDialogType
)
423 case FILEOPEN_SIMPLE
:
424 case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE
:
426 case FILEOPEN_LINK_PLAY
:
427 case FILEOPEN_READONLY_VERSION
:
428 case FILEOPEN_LINK_PREVIEW
:
429 case FILEOPEN_PREVIEW
:
436 void FileDialogHelper_Impl::updateFilterOptionsBox()
438 if ( !m_bHaveFilterOptions
)
441 updateExtendedControl(
442 ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS
,
443 CheckFilterOptionsCapability( getCurentSfxFilter() )
447 void FileDialogHelper_Impl::updateExportButton()
449 uno::Reference
< XFilePickerControlAccess
> xCtrlAccess( mxFileDlg
, UNO_QUERY
);
450 if ( !xCtrlAccess
.is() )
453 OUString
sOldLabel( xCtrlAccess
->getLabel( CommonFilePickerElementIds::PUSHBUTTON_OK
) );
455 // initialize button label; we need the label with the mnemonic char
456 if ( maButtonLabel
.isEmpty() || maButtonLabel
.indexOf( MNEMONIC_CHAR
) == -1 )
458 // cut the ellipses, if necessary
459 sal_Int32 nIndex
= sOldLabel
.indexOf( "..." );
461 nIndex
= sOldLabel
.getLength();
462 maButtonLabel
= sOldLabel
.copy( 0, nIndex
);
465 OUString sLabel
= maButtonLabel
;
466 // filter with options -> append ellipses on export button label
467 if ( CheckFilterOptionsCapability( getCurentSfxFilter() ) )
470 if ( sOldLabel
!= sLabel
)
474 xCtrlAccess
->setLabel( CommonFilePickerElementIds::PUSHBUTTON_OK
, sLabel
);
476 catch( const IllegalArgumentException
& )
478 TOOLS_WARN_EXCEPTION( "sfx.dialog", "FileDialogHelper_Impl::updateExportButton" );
483 void FileDialogHelper_Impl::updateSelectionBox()
485 if ( !mbHasSelectionBox
)
488 // Does the selection box exist?
489 bool bSelectionBoxFound
= false;
490 uno::Reference
< XControlInformation
> xCtrlInfo( mxFileDlg
, UNO_QUERY
);
491 if ( xCtrlInfo
.is() )
493 Sequence
< OUString
> aCtrlList
= xCtrlInfo
->getSupportedControls();
494 bSelectionBoxFound
= comphelper::findValue(aCtrlList
, "SelectionBox") != -1;
497 if ( bSelectionBoxFound
)
499 std::shared_ptr
<const SfxFilter
> pFilter
= getCurentSfxFilter();
500 mbSelectionFltrEnabled
= updateExtendedControl(
501 ExtendedFilePickerElementIds::CHECKBOX_SELECTION
,
502 ( mbSelectionEnabled
&& pFilter
&& ( pFilter
->GetFilterFlags() & SfxFilterFlags::SUPPORTSSELECTION
) ) );
503 uno::Reference
< XFilePickerControlAccess
> xCtrlAccess( mxFileDlg
, UNO_QUERY
);
504 xCtrlAccess
->setValue( ExtendedFilePickerElementIds::CHECKBOX_SELECTION
, 0, makeAny( mbSelection
) );
508 void FileDialogHelper_Impl::enablePasswordBox( bool bInit
)
510 if ( ! mbHasPassword
)
513 bool bWasEnabled
= mbIsPwdEnabled
;
515 std::shared_ptr
<const SfxFilter
> pCurrentFilter
= getCurentSfxFilter();
516 mbIsPwdEnabled
= updateExtendedControl(
517 ExtendedFilePickerElementIds::CHECKBOX_PASSWORD
,
518 pCurrentFilter
&& ( pCurrentFilter
->GetFilterFlags() & SfxFilterFlags::ENCRYPTION
)
523 // in case of initialization previous state is not interesting
526 uno::Reference
< XFilePickerControlAccess
> xCtrlAccess( mxFileDlg
, UNO_QUERY
);
527 if( mbPwdCheckBoxState
)
528 xCtrlAccess
->setValue( ExtendedFilePickerElementIds::CHECKBOX_PASSWORD
, 0, makeAny( true ) );
531 else if( !bWasEnabled
&& mbIsPwdEnabled
)
533 uno::Reference
< XFilePickerControlAccess
> xCtrlAccess( mxFileDlg
, UNO_QUERY
);
534 if( mbPwdCheckBoxState
)
535 xCtrlAccess
->setValue( ExtendedFilePickerElementIds::CHECKBOX_PASSWORD
, 0, makeAny( true ) );
537 else if( bWasEnabled
&& !mbIsPwdEnabled
)
539 // remember user settings until checkbox is enabled
540 uno::Reference
< XFilePickerControlAccess
> xCtrlAccess( mxFileDlg
, UNO_QUERY
);
541 Any aValue
= xCtrlAccess
->getValue( ExtendedFilePickerElementIds::CHECKBOX_PASSWORD
, 0 );
542 bool bPassWord
= false;
543 mbPwdCheckBoxState
= ( aValue
>>= bPassWord
) && bPassWord
;
544 xCtrlAccess
->setValue( ExtendedFilePickerElementIds::CHECKBOX_PASSWORD
, 0, makeAny( false ) );
548 void FileDialogHelper_Impl::updatePreviewState( bool _bUpdatePreviewWindow
)
553 uno::Reference
< XFilePickerControlAccess
> xCtrlAccess( mxFileDlg
, UNO_QUERY
);
555 // check, whether or not we have to display a preview
556 if ( !xCtrlAccess
.is() )
561 Any aValue
= xCtrlAccess
->getValue( ExtendedFilePickerElementIds::CHECKBOX_PREVIEW
, 0 );
562 bool bShowPreview
= false;
564 if ( aValue
>>= bShowPreview
)
566 mbShowPreview
= bShowPreview
;
568 // setShowState has currently no effect for the
569 // OpenOffice FilePicker (see svtools/source/filepicker/iodlg.cxx)
570 uno::Reference
< XFilePreview
> xFilePreview( mxFileDlg
, UNO_QUERY
);
571 if ( xFilePreview
.is() )
572 xFilePreview
->setShowState( mbShowPreview
);
574 if ( _bUpdatePreviewWindow
)
575 TimeOutHdl_Impl( nullptr );
578 catch( const Exception
& )
580 TOOLS_WARN_EXCEPTION( "sfx.dialog", "FileDialogHelper_Impl::updatePreviewState" );
584 void FileDialogHelper_Impl::updateVersions()
586 Sequence
< OUString
> aEntries
;
587 Sequence
< OUString
> aPathSeq
= mxFileDlg
->getFiles();
589 if ( aPathSeq
.getLength() == 1 )
591 INetURLObject
aObj( aPathSeq
[0] );
593 if ( ( aObj
.GetProtocol() == INetProtocol::File
) &&
594 ( utl::UCBContentHelper::IsDocument( aObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) ) ) )
598 uno::Reference
< embed::XStorage
> xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL(
599 aObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
),
600 embed::ElementModes::READ
);
602 DBG_ASSERT( xStorage
.is(), "The method must return the storage or throw exception!" );
603 if ( !xStorage
.is() )
604 throw uno::RuntimeException();
606 uno::Sequence
< util::RevisionTag
> xVersions
= SfxMedium::GetVersionList( xStorage
);
608 aEntries
.realloc( xVersions
.getLength() + 1 );
609 aEntries
[0] = SfxResId( STR_SFX_FILEDLG_ACTUALVERSION
);
611 std::transform(xVersions
.begin(), xVersions
.end(), std::next(aEntries
.begin()),
612 [](const util::RevisionTag
& rVersion
) -> OUString
{ return rVersion
.Identifier
; });
614 catch( const uno::Exception
& )
620 uno::Reference
< XFilePickerControlAccess
> xDlg( mxFileDlg
, UNO_QUERY
);
625 xDlg
->setValue( ExtendedFilePickerElementIds::LISTBOX_VERSION
,
626 ControlActions::DELETE_ITEMS
, aValue
);
628 catch( const IllegalArgumentException
& ){}
630 if ( !aEntries
.hasElements() )
636 xDlg
->setValue( ExtendedFilePickerElementIds::LISTBOX_VERSION
,
637 ControlActions::ADD_ITEMS
, aValue
);
640 aPos
<<= sal_Int32(0);
641 xDlg
->setValue( ExtendedFilePickerElementIds::LISTBOX_VERSION
,
642 ControlActions::SET_SELECT_ITEM
, aPos
);
644 catch( const IllegalArgumentException
& ){}
647 IMPL_LINK_NOARG(FileDialogHelper_Impl
, TimeOutHdl_Impl
, Timer
*, void)
655 uno::Reference
< XFilePreview
> xFilePicker( mxFileDlg
, UNO_QUERY
);
657 if ( ! xFilePicker
.is() )
660 Sequence
< OUString
> aPathSeq
= mxFileDlg
->getFiles();
662 if ( mbShowPreview
&& ( aPathSeq
.getLength() == 1 ) )
664 OUString aURL
= aPathSeq
[0];
666 if ( ERRCODE_NONE
== getGraphic( aURL
, maGraphic
) )
668 // changed the code slightly;
669 // before: the bitmap was scaled and
670 // surrounded a white frame
671 // now: the bitmap will only be scaled
672 // and the filepicker implementation
673 // is responsible for placing it at its
674 // proper position and painting a frame
676 BitmapEx aBmp
= maGraphic
.GetBitmapEx();
677 if ( !aBmp
.IsEmpty() )
679 // scale the bitmap to the correct size
680 sal_Int32 nOutWidth
= xFilePicker
->getAvailableWidth();
681 sal_Int32 nOutHeight
= xFilePicker
->getAvailableHeight();
682 sal_Int32 nBmpWidth
= aBmp
.GetSizePixel().Width();
683 sal_Int32 nBmpHeight
= aBmp
.GetSizePixel().Height();
685 double nXRatio
= static_cast<double>(nOutWidth
) / nBmpWidth
;
686 double nYRatio
= static_cast<double>(nOutHeight
) / nBmpHeight
;
688 if ( nXRatio
< nYRatio
)
689 aBmp
.Scale( nXRatio
, nXRatio
);
691 aBmp
.Scale( nYRatio
, nYRatio
);
693 // Convert to true color, to allow CopyPixel
694 aBmp
.Convert( BmpConversion::N24Bit
);
696 // and copy it into the Any
697 SvMemoryStream aData
;
699 WriteDIB(aBmp
, aData
, false);
701 const Sequence
< sal_Int8
> aBuffer(
702 static_cast< const sal_Int8
* >(aData
.GetData()),
703 aData
.GetEndOfData() );
712 SolarMutexReleaser aReleaseForCallback
;
713 // clear the preview window
714 xFilePicker
->setImage( FilePreviewImageFormats::BITMAP
, aAny
);
716 catch( const IllegalArgumentException
& )
721 ErrCode
FileDialogHelper_Impl::getGraphic( const OUString
& rURL
,
722 Graphic
& rGraphic
) const
724 if ( utl::UCBContentHelper::IsFolder( rURL
) )
725 return ERRCODE_IO_NOTAFILE
;
727 if ( !mpGraphicFilter
)
728 return ERRCODE_IO_NOTSUPPORTED
;
730 // select graphic filter from dialog filter selection
731 OUString
aCurFilter( getFilter() );
733 sal_uInt16 nFilter
= !aCurFilter
.isEmpty() && mpGraphicFilter
->GetImportFormatCount()
734 ? mpGraphicFilter
->GetImportFormatNumber( aCurFilter
)
735 : GRFILTER_FORMAT_DONTKNOW
;
737 INetURLObject
aURLObj( rURL
);
739 if ( aURLObj
.HasError() || INetProtocol::NotValid
== aURLObj
.GetProtocol() )
741 aURLObj
.SetSmartProtocol( INetProtocol::File
);
742 aURLObj
.SetSmartURL( rURL
);
745 ErrCode nRet
= ERRCODE_NONE
;
747 GraphicFilterImportFlags nFilterImportFlags
= GraphicFilterImportFlags::SetLogsizeForJpeg
;
749 if ( INetProtocol::File
!= aURLObj
.GetProtocol() )
751 std::unique_ptr
<SvStream
> pStream
= ::utl::UcbStreamHelper::CreateStream( rURL
, StreamMode::READ
);
754 nRet
= mpGraphicFilter
->ImportGraphic( rGraphic
, rURL
, *pStream
, nFilter
, nullptr, nFilterImportFlags
);
756 nRet
= mpGraphicFilter
->ImportGraphic( rGraphic
, aURLObj
, nFilter
, nullptr, nFilterImportFlags
);
760 nRet
= mpGraphicFilter
->ImportGraphic( rGraphic
, aURLObj
, nFilter
, nullptr, nFilterImportFlags
);
766 ErrCode
FileDialogHelper_Impl::getGraphic( Graphic
& rGraphic
) const
768 ErrCode nRet
= ERRCODE_NONE
;
770 // rhbz#1079672 do not return maGraphic, it needs not to be the selected file
773 Sequence
<OUString
> aPathSeq
= mxFileDlg
->getFiles();
775 if (aPathSeq
.getLength() == 1)
780 if (!aPath
.isEmpty())
781 nRet
= getGraphic(aPath
, rGraphic
);
783 nRet
= ERRCODE_IO_GENERAL
;
788 static bool lcl_isSystemFilePicker( const uno::Reference
< XFilePicker3
>& _rxFP
)
792 uno::Reference
< XServiceInfo
> xSI( _rxFP
, UNO_QUERY
);
795 return xSI
->supportsService( "com.sun.star.ui.dialogs.SystemFilePicker" );
797 catch( const Exception
& )
805 enum open_or_save_t
{OPEN
, SAVE
, UNDEFINED
};
809 static open_or_save_t
lcl_OpenOrSave(sal_Int16
const nDialogType
)
813 case FILEOPEN_SIMPLE
:
814 case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE
:
815 case FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR
:
817 case FILEOPEN_LINK_PLAY
:
818 case FILEOPEN_READONLY_VERSION
:
819 case FILEOPEN_LINK_PREVIEW
:
820 case FILEOPEN_PREVIEW
:
822 case FILESAVE_SIMPLE
:
823 case FILESAVE_AUTOEXTENSION_PASSWORD
:
824 case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS
:
825 case FILESAVE_AUTOEXTENSION_SELECTION
:
826 case FILESAVE_AUTOEXTENSION_TEMPLATE
:
827 case FILESAVE_AUTOEXTENSION
:
830 assert(false); // invalid dialog type
835 // FileDialogHelper_Impl
837 css::uno::Reference
<css::awt::XWindow
> FileDialogHelper_Impl::GetFrameInterface()
840 return mpFrameWeld
->GetXWindow();
841 return css::uno::Reference
<css::awt::XWindow
>();
844 FileDialogHelper_Impl::FileDialogHelper_Impl(
845 FileDialogHelper
* _pAntiImpl
,
846 sal_Int16 nDialogType
,
847 FileDialogFlags nFlags
,
849 weld::Window
* pFrameWeld
,
850 const OUString
& sStandardDir
,
851 const css::uno::Sequence
< OUString
>& rDenyList
853 :m_nDialogType ( nDialogType
)
854 ,meContext ( FileDialogHelper::UNKNOWN_CONTEXT
)
856 const char* pServiceName
=nullptr;
859 case SFX2_IMPL_DIALOG_SYSTEM
:
860 case SFX2_IMPL_DIALOG_OOO
:
861 pServiceName
= "com.sun.star.ui.dialogs.OfficeFilePicker";
863 case SFX2_IMPL_DIALOG_REMOTE
:
864 pServiceName
= "com.sun.star.ui.dialogs.RemoteFilePicker";
867 pServiceName
= "com.sun.star.ui.dialogs.FilePicker";
871 OUString aService
= OUString::createFromAscii( pServiceName
);
873 uno::Reference
< XMultiServiceFactory
> xFactory( ::comphelper::getProcessServiceFactory() );
875 // create the file open dialog
876 // the flags can be SFXWB_INSERT or SFXWB_MULTISELECTION
878 mpFrameWeld
= pFrameWeld
;
879 mpAntiImpl
= _pAntiImpl
;
880 mbHasAutoExt
= false;
881 mbHasPassword
= false;
882 m_bHaveFilterOptions
= false;
883 mbIsPwdEnabled
= true;
884 mbHasVersions
= false;
885 mbHasPreview
= false;
886 mbShowPreview
= false;
887 mbDeleteMatcher
= false;
888 mbInsert
= bool(nFlags
& (FileDialogFlags::Insert
|
889 FileDialogFlags::InsertCompare
|
890 FileDialogFlags::InsertMerge
));
891 mbExport
= bool(nFlags
& FileDialogFlags::Export
);
893 mbPwdCheckBoxState
= false;
895 mbSelectionEnabled
= true;
896 mbHasSelectionBox
= false;
897 mbSelectionFltrEnabled
= false;
900 m_nDontFlags
= SFX_FILTER_NOTINSTALLED
| SfxFilterFlags::INTERNAL
| SfxFilterFlags::NOTINFILEDLG
;
901 if (OPEN
== lcl_OpenOrSave(m_nDialogType
))
902 m_nMustFlags
= SfxFilterFlags::IMPORT
;
904 m_nMustFlags
= SfxFilterFlags::EXPORT
;
908 mpGraphicFilter
= nullptr;
909 mnPostUserEventId
= nullptr;
911 // create the picker component
912 mxFileDlg
.set(xFactory
->createInstance( aService
), css::uno::UNO_QUERY
);
913 mbSystemPicker
= lcl_isSystemFilePicker( mxFileDlg
);
915 uno::Reference
< XInitialization
> xInit( mxFileDlg
, UNO_QUERY
);
917 if ( ! mxFileDlg
.is() )
925 sal_Int16 nTemplateDescription
= TemplateDescription::FILEOPEN_SIMPLE
;
927 switch ( m_nDialogType
)
929 case FILEOPEN_SIMPLE
:
930 nTemplateDescription
= TemplateDescription::FILEOPEN_SIMPLE
;
933 case FILESAVE_SIMPLE
:
934 nTemplateDescription
= TemplateDescription::FILESAVE_SIMPLE
;
938 case FILESAVE_AUTOEXTENSION_PASSWORD
:
939 nTemplateDescription
= TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD
;
940 mbHasPassword
= true;
945 case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS
:
946 nTemplateDescription
= TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS
;
947 mbHasPassword
= true;
949 m_bHaveFilterOptions
= true;
953 xFactory
->createInstance( "com.sun.star.document.FilterFactory" ),
961 case FILESAVE_AUTOEXTENSION_SELECTION
:
962 nTemplateDescription
= TemplateDescription::FILESAVE_AUTOEXTENSION_SELECTION
;
965 mbHasSelectionBox
= true;
966 if ( mbExport
&& !mxFilterCFG
.is() && xFactory
.is() )
969 xFactory
->createInstance( "com.sun.star.document.FilterFactory" ),
974 case FILESAVE_AUTOEXTENSION_TEMPLATE
:
975 nTemplateDescription
= TemplateDescription::FILESAVE_AUTOEXTENSION_TEMPLATE
;
980 case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE
:
981 nTemplateDescription
= TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE
;
985 case FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR
:
986 nTemplateDescription
= TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR
;
991 nTemplateDescription
= TemplateDescription::FILEOPEN_PLAY
;
994 case FILEOPEN_LINK_PLAY
:
995 nTemplateDescription
= TemplateDescription::FILEOPEN_LINK_PLAY
;
998 case FILEOPEN_READONLY_VERSION
:
999 nTemplateDescription
= TemplateDescription::FILEOPEN_READONLY_VERSION
;
1000 mbHasVersions
= true;
1003 case FILEOPEN_LINK_PREVIEW
:
1004 nTemplateDescription
= TemplateDescription::FILEOPEN_LINK_PREVIEW
;
1005 mbHasPreview
= true;
1008 case FILESAVE_AUTOEXTENSION
:
1009 nTemplateDescription
= TemplateDescription::FILESAVE_AUTOEXTENSION
;
1010 mbHasAutoExt
= true;
1014 case FILEOPEN_PREVIEW
:
1015 nTemplateDescription
= TemplateDescription::FILEOPEN_PREVIEW
;
1016 mbHasPreview
= true;
1020 SAL_WARN( "sfx.dialog", "FileDialogHelper::ctor with unknown type" );
1026 maPreviewIdle
.SetPriority( TaskPriority::LOWEST
);
1027 maPreviewIdle
.SetInvokeHandler( LINK( this, FileDialogHelper_Impl
, TimeOutHdl_Impl
) );
1030 auto xWindow
= GetFrameInterface();
1032 Sequence
< Any
> aInitArguments(!xWindow
.is() ? 3 : 4);
1034 // This is a hack. We currently know that the internal file picker implementation
1035 // supports the extended arguments as specified below.
1037 // a) adjust the service description so that it includes the TemplateDescription and ParentWindow args
1038 // b) adjust the implementation of the system file picker to that it recognizes it
1039 if ( mbSystemPicker
)
1041 aInitArguments
[0] <<= nTemplateDescription
;
1043 aInitArguments
[1] <<= xWindow
;
1047 aInitArguments
[0] <<= NamedValue(
1048 "TemplateDescription",
1049 makeAny( nTemplateDescription
)
1052 aInitArguments
[1] <<= NamedValue(
1054 makeAny( sStandardDir
)
1057 aInitArguments
[2] <<= NamedValue(
1059 makeAny( rDenyList
)
1064 aInitArguments
[3] <<= NamedValue("ParentWindow", makeAny(xWindow
));
1069 xInit
->initialize( aInitArguments
);
1071 catch( const Exception
& )
1073 OSL_FAIL( "FileDialogHelper_Impl::FileDialogHelper_Impl: could not initialize the picker!" );
1078 // set multiselection mode
1079 if ( nFlags
& FileDialogFlags::MultiSelection
)
1080 mxFileDlg
->setMultiSelectionMode( true );
1082 if ( nFlags
& FileDialogFlags::Graphic
) // generate graphic filter only on demand
1090 mxFileDlg
->setTitle( SfxResId( STR_SFX_EXPLORERFILE_EXPORT
) );
1092 css::uno::Reference
< XFilePickerControlAccess
> xCtrlAccess( mxFileDlg
, UNO_QUERY_THROW
);
1093 xCtrlAccess
->enableControl( ExtendedFilePickerElementIds::LISTBOX_FILTER_SELECTOR
, true );
1095 catch( const Exception
& ) { }
1098 // Save a copy dialog
1099 if ( nFlags
& FileDialogFlags::SaveACopy
)
1101 mxFileDlg
->setTitle( SfxResId( STR_PB_SAVEACOPY
) );
1104 // the "insert file" dialog needs another title
1107 if ( nFlags
& FileDialogFlags::InsertCompare
)
1109 mxFileDlg
->setTitle( SfxResId( STR_PB_COMPAREDOC
) );
1111 else if ( nFlags
& FileDialogFlags::InsertMerge
)
1113 mxFileDlg
->setTitle( SfxResId( STR_PB_MERGEDOC
) );
1117 mxFileDlg
->setTitle( SfxResId( STR_SFX_EXPLORERFILE_INSERT
) );
1119 uno::Reference
< XFilePickerControlAccess
> xExtDlg( mxFileDlg
, UNO_QUERY
);
1124 xExtDlg
->setLabel( CommonFilePickerElementIds::PUSHBUTTON_OK
,
1125 SfxResId( STR_SFX_EXPLORERFILE_BUTTONINSERT
) );
1127 catch( const IllegalArgumentException
& ){}
1131 // add the event listener
1132 mxFileDlg
->addFilePickerListener( this );
1135 FileDialogHelper_Impl::~FileDialogHelper_Impl()
1137 // Remove user event if we haven't received it yet
1138 if ( mnPostUserEventId
)
1139 Application::RemoveUserEvent( mnPostUserEventId
);
1140 mnPostUserEventId
= nullptr;
1142 mpGraphicFilter
.reset();
1144 if ( mbDeleteMatcher
)
1147 maPreviewIdle
.ClearInvokeHandler();
1149 ::comphelper::disposeComponent( mxFileDlg
);
1152 void FileDialogHelper_Impl::setControlHelpIds( const sal_Int16
* _pControlId
, const char** _pHelpId
)
1154 DBG_ASSERT( _pControlId
&& _pHelpId
, "FileDialogHelper_Impl::setControlHelpIds: invalid array pointers!" );
1155 if ( !_pControlId
|| !_pHelpId
)
1158 // forward these ids to the file picker
1161 const OUString
sHelpIdPrefix( INET_HID_SCHEME
);
1162 // the ids for the single controls
1163 uno::Reference
< XFilePickerControlAccess
> xControlAccess( mxFileDlg
, UNO_QUERY
);
1164 if ( xControlAccess
.is() )
1166 while ( *_pControlId
)
1168 DBG_ASSERT( INetURLObject( OStringToOUString( *_pHelpId
, RTL_TEXTENCODING_UTF8
) ).GetProtocol() == INetProtocol::NotValid
, "Wrong HelpId!" );
1169 OUString sId
= sHelpIdPrefix
+
1170 OUString( *_pHelpId
, strlen( *_pHelpId
), RTL_TEXTENCODING_UTF8
);
1171 xControlAccess
->setValue( *_pControlId
, ControlActions::SET_HELP_URL
, makeAny( sId
) );
1173 ++_pControlId
; ++_pHelpId
;
1177 catch( const Exception
& )
1179 OSL_FAIL( "FileDialogHelper_Impl::setControlHelpIds: caught an exception while setting the help ids!" );
1183 IMPL_LINK_NOARG( FileDialogHelper_Impl
, InitControls
, void*, void )
1185 mnPostUserEventId
= nullptr;
1186 enablePasswordBox( true );
1187 updateFilterOptionsBox( );
1188 updateSelectionBox( );
1191 void FileDialogHelper_Impl::preExecute()
1194 setDefaultValues( );
1195 updatePreviewState( false );
1197 implInitializeFileName( );
1199 #if !(defined(MACOSX) && defined(MACOSX)) && !defined(_WIN32)
1200 // allow for dialog implementations which need to be executed before they return valid values for
1201 // current filter and such
1203 // On Vista (at least SP1) it's the same as on MacOSX, the modal dialog won't let message pass
1204 // through before it returns from execution
1205 mnPostUserEventId
= Application::PostUserEvent( LINK( this, FileDialogHelper_Impl
, InitControls
) );
1207 // However, the macOS implementation's pickers run modally in execute and so the event doesn't
1208 // get through in time... so we call the methods directly
1209 enablePasswordBox( true );
1210 updateFilterOptionsBox( );
1211 updateSelectionBox( );
1215 void FileDialogHelper_Impl::postExecute( sal_Int16 _nResult
)
1217 if ( ExecutableDialogResults::CANCEL
!= _nResult
)
1221 void FileDialogHelper_Impl::implInitializeFileName( )
1223 if ( maFileName
.isEmpty() )
1226 INetURLObject
aObj( maPath
);
1227 aObj
.Append( maFileName
);
1229 // in case we're operating as save dialog, and "auto extension" is checked,
1230 // cut the extension from the name
1231 if ( !(mbIsSaveDlg
&& mbHasAutoExt
) )
1236 bool bAutoExtChecked
= false;
1238 uno::Reference
< XFilePickerControlAccess
> xControlAccess( mxFileDlg
, UNO_QUERY
);
1239 if ( xControlAccess
.is()
1240 && ( xControlAccess
->getValue( ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION
, 0 )
1245 if ( bAutoExtChecked
)
1246 { // cut the extension
1247 aObj
.removeExtension( );
1248 mxFileDlg
->setDefaultName(
1249 aObj
.GetLastName(INetURLObject::DecodeMechanism::WithCharset
));
1253 catch( const Exception
& )
1255 OSL_FAIL( "FileDialogHelper_Impl::implInitializeFileName: could not ask for the auto-extension current-value!" );
1259 sal_Int16
FileDialogHelper_Impl::implDoExecute()
1263 sal_Int16 nRet
= ExecutableDialogResults::CANCEL
;
1265 //On MacOSX the native file picker has to run in the primordial thread because of drawing issues
1266 //On Linux the native gtk file picker, when backed by gnome-vfs2, needs to be run in the same
1267 //primordial thread as the ucb gnome-vfs2 provider was initialized in.
1273 if ( mbSystemPicker
)
1275 SolarMutexReleaser aSolarMutex
;
1276 nRet
= mxFileDlg
->execute();
1280 nRet
= mxFileDlg
->execute();
1282 catch( const Exception
& )
1284 TOOLS_WARN_EXCEPTION( "sfx.dialog", "FileDialogHelper_Impl::implDoExecute" );
1288 postExecute( nRet
);
1293 void FileDialogHelper_Impl::implStartExecute()
1295 DBG_ASSERT( mxFileDlg
.is(), "invalid file dialog" );
1299 if ( mbSystemPicker
)
1306 uno::Reference
< XAsynchronousExecutableDialog
> xAsyncDlg( mxFileDlg
, UNO_QUERY
);
1307 if ( xAsyncDlg
.is() )
1308 xAsyncDlg
->startExecuteModal( this );
1310 catch( const Exception
& )
1312 TOOLS_WARN_EXCEPTION( "sfx.dialog", "FileDialogHelper_Impl::implDoExecute" );
1317 static void lcl_saveLastURLs(std::vector
<OUString
>& rpURLList
,
1318 ::std::vector
< OUString
>& lLastURLs
)
1321 for (auto const& url
: rpURLList
)
1322 lLastURLs
.push_back(url
);
1325 void FileDialogHelper_Impl::implGetAndCacheFiles(const uno::Reference
< XInterface
>& xPicker
, std::vector
<OUString
>& rpURLList
)
1329 // a) the new way (optional!)
1330 uno::Reference
< XFilePicker3
> xPickNew(xPicker
, UNO_QUERY
);
1333 Sequence
< OUString
> lFiles
= xPickNew
->getSelectedFiles();
1334 comphelper::sequenceToContainer(rpURLList
, lFiles
);
1337 // b) the olde way ... non optional.
1340 uno::Reference
< XFilePicker3
> xPickOld(xPicker
, UNO_QUERY_THROW
);
1341 Sequence
< OUString
> lFiles
= xPickOld
->getFiles();
1342 ::sal_Int32 nFiles
= lFiles
.getLength();
1345 rpURLList
.push_back(lFiles
[0]);
1347 else if ( nFiles
> 1 )
1349 INetURLObject
aPath( lFiles
[0] );
1350 aPath
.setFinalSlash();
1352 for (::sal_Int32 i
= 1; i
< nFiles
; i
++)
1355 aPath
.Append( lFiles
[i
] );
1357 aPath
.setName( lFiles
[i
] );
1359 rpURLList
.push_back(aPath
.GetMainURL(INetURLObject::DecodeMechanism::NONE
));
1364 lcl_saveLastURLs(rpURLList
, mlLastURLs
);
1367 ErrCode
FileDialogHelper_Impl::execute( std::vector
<OUString
>& rpURLList
,
1368 std::unique_ptr
<SfxItemSet
>& rpSet
,
1371 // rFilter is a pure output parameter, it shouldn't be used for anything else
1372 // changing this would surely break code
1373 // rpSet is in/out parameter, usually just a media-descriptor that can be changed by dialog
1375 uno::Reference
< XFilePickerControlAccess
> xCtrlAccess( mxFileDlg
, UNO_QUERY
);
1377 // retrieves parameters from rpSet
1378 // for now only Password is used
1381 // check password checkbox if the document had password before
1384 const SfxBoolItem
* pPassItem
= SfxItemSet::GetItem
<SfxBoolItem
>(rpSet
.get(), SID_PASSWORDINTERACTION
, false);
1385 mbPwdCheckBoxState
= ( pPassItem
!= nullptr && pPassItem
->GetValue() );
1387 // in case the document has password to modify, the dialog should be shown
1388 const SfxUnoAnyItem
* pPassToModifyItem
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(rpSet
.get(), SID_MODIFYPASSWORDINFO
, false);
1389 mbPwdCheckBoxState
|= ( pPassToModifyItem
&& pPassToModifyItem
->GetValue().hasValue() );
1392 const SfxBoolItem
* pSelectItem
= SfxItemSet::GetItem
<SfxBoolItem
>(rpSet
.get(), SID_SELECTION
, false);
1394 mbSelection
= pSelectItem
->GetValue();
1396 mbSelectionEnabled
= false;
1398 // the password will be set in case user decide so
1399 rpSet
->ClearItem( SID_PASSWORDINTERACTION
);
1400 if (rpSet
->HasItem( SID_PASSWORD
))
1402 // As the SID_ENCRYPTIONDATA and SID_PASSWORD are using for setting password together, we need to clear them both.
1403 // Note: Do not remove SID_ENCRYPTIONDATA without SID_PASSWORD
1404 rpSet
->ClearItem( SID_PASSWORD
);
1405 rpSet
->ClearItem( SID_ENCRYPTIONDATA
);
1407 rpSet
->ClearItem( SID_RECOMMENDREADONLY
);
1408 rpSet
->ClearItem( SID_MODIFYPASSWORDINFO
);
1412 if ( mbHasPassword
&& !mbPwdCheckBoxState
)
1414 SvtSecurityOptions aSecOpt
;
1415 mbPwdCheckBoxState
= (
1416 aSecOpt
.IsOptionSet( SvtSecurityOptions::EOption::DocWarnRecommendPassword
) );
1421 if ( ! mxFileDlg
.is() )
1422 return ERRCODE_ABORT
;
1424 if ( ExecutableDialogResults::CANCEL
!= implDoExecute() )
1426 // create an itemset if there is no
1428 rpSet
.reset(new SfxAllItemSet( SfxGetpApp()->GetPool() ));
1430 // the item should remain only if it was set by the dialog
1431 rpSet
->ClearItem( SID_SELECTION
);
1433 if( mbExport
&& mbHasSelectionBox
)
1437 Any aValue
= xCtrlAccess
->getValue( ExtendedFilePickerElementIds::CHECKBOX_SELECTION
, 0 );
1438 bool bSelection
= false;
1439 if ( aValue
>>= bSelection
)
1440 rpSet
->Put( SfxBoolItem( SID_SELECTION
, bSelection
) );
1442 catch( const IllegalArgumentException
& )
1444 OSL_FAIL( "FileDialogHelper_Impl::execute: caught an IllegalArgumentException!" );
1449 // set the read-only flag. When inserting a file, this flag is always set
1451 rpSet
->Put( SfxBoolItem( SID_DOC_READONLY
, true ) );
1454 if ( ( FILEOPEN_READONLY_VERSION
== m_nDialogType
) && xCtrlAccess
.is() )
1458 Any aValue
= xCtrlAccess
->getValue( ExtendedFilePickerElementIds::CHECKBOX_READONLY
, 0 );
1459 bool bReadOnly
= false;
1460 if ( ( aValue
>>= bReadOnly
) && bReadOnly
)
1461 rpSet
->Put( SfxBoolItem( SID_DOC_READONLY
, bReadOnly
) );
1463 catch( const IllegalArgumentException
& )
1465 OSL_FAIL( "FileDialogHelper_Impl::execute: caught an IllegalArgumentException!" );
1469 if ( mbHasVersions
&& xCtrlAccess
.is() )
1473 Any aValue
= xCtrlAccess
->getValue( ExtendedFilePickerElementIds::LISTBOX_VERSION
,
1474 ControlActions::GET_SELECTED_ITEM_INDEX
);
1475 sal_Int32 nVersion
= 0;
1476 if ( ( aValue
>>= nVersion
) && nVersion
> 0 )
1477 // open a special version; 0 == current version
1478 rpSet
->Put( SfxInt16Item( SID_VERSION
, static_cast<short>(nVersion
) ) );
1480 catch( const IllegalArgumentException
& ){}
1484 getRealFilter( rFilter
);
1486 std::shared_ptr
<const SfxFilter
> pCurrentFilter
= getCurentSfxFilter();
1488 // fill the rpURLList
1489 implGetAndCacheFiles( mxFileDlg
, rpURLList
);
1490 if ( rpURLList
.empty() )
1491 return ERRCODE_ABORT
;
1493 // check, whether or not we have to display a password box
1494 if ( pCurrentFilter
&& mbHasPassword
&& mbIsPwdEnabled
&& xCtrlAccess
.is() )
1498 Any aValue
= xCtrlAccess
->getValue( ExtendedFilePickerElementIds::CHECKBOX_PASSWORD
, 0 );
1499 bool bPassWord
= false;
1500 if ( ( aValue
>>= bPassWord
) && bPassWord
)
1502 // ask for a password
1503 OUString
aDocName(rpURLList
[0]);
1504 ErrCode errCode
= RequestPassword(pCurrentFilter
, aDocName
, rpSet
.get(), GetFrameInterface());
1505 if (errCode
!= ERRCODE_NONE
)
1509 catch( const IllegalArgumentException
& ){}
1511 // check, whether or not we have to display a key selection box
1512 if ( pCurrentFilter
&& mbHasPassword
&& xCtrlAccess
.is() )
1516 Any aValue
= xCtrlAccess
->getValue( ExtendedFilePickerElementIds::CHECKBOX_GPGENCRYPTION
, 0 );
1518 if ( ( aValue
>>= bGpg
) && bGpg
)
1520 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
1526 aEncryptionData
= ::comphelper::OStorageHelper::CreateGpgPackageEncryptionData();
1527 break; // user cancelled or we've some keys now
1529 catch( const IllegalArgumentException
& )
1531 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(mpFrameWeld
,
1532 VclMessageType::Warning
, VclButtonsType::Ok
,
1533 SfxResId(RID_SVXSTR_GPG_ENCRYPT_FAILURE
)));
1538 if ( aEncryptionData
.hasElements() )
1539 rpSet
->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA
, uno::makeAny( aEncryptionData
) ) );
1542 catch( const IllegalArgumentException
& ){}
1545 SaveLastUsedFilter();
1546 return ERRCODE_NONE
;
1549 return ERRCODE_ABORT
;
1552 ErrCode
FileDialogHelper_Impl::execute()
1554 if ( ! mxFileDlg
.is() )
1555 return ERRCODE_ABORT
;
1557 sal_Int16 nRet
= implDoExecute();
1559 maPath
= mxFileDlg
->getDisplayDirectory();
1561 if ( ExecutableDialogResults::CANCEL
== nRet
)
1562 return ERRCODE_ABORT
;
1565 return ERRCODE_NONE
;
1569 OUString
FileDialogHelper_Impl::getPath() const
1573 if ( mxFileDlg
.is() )
1574 aPath
= mxFileDlg
->getDisplayDirectory();
1576 if ( aPath
.isEmpty() )
1582 OUString
FileDialogHelper_Impl::getFilter() const
1584 OUString aFilter
= getCurrentFilterUIName();
1586 if( aFilter
.isEmpty() )
1587 aFilter
= maCurFilter
;
1592 void FileDialogHelper_Impl::getRealFilter( OUString
& _rFilter
) const
1594 _rFilter
= getCurrentFilterUIName();
1596 if ( _rFilter
.isEmpty() )
1597 _rFilter
= maCurFilter
;
1599 if ( !_rFilter
.isEmpty() && mpMatcher
)
1601 std::shared_ptr
<const SfxFilter
> pFilter
=
1602 mpMatcher
->GetFilter4UIName( _rFilter
, m_nMustFlags
, m_nDontFlags
);
1603 _rFilter
= pFilter
? pFilter
->GetFilterName() : OUString();
1607 void FileDialogHelper_Impl::verifyPath()
1610 // lp#905355, fdo#43895
1611 // Check that the file has read only permission and is in /tmp -- this is
1612 // the case if we have opened the file from the web with firefox only.
1613 if (maFileName
.isEmpty()) {
1616 INetURLObject
url(maPath
);
1617 if (url
.GetProtocol() != INetProtocol::File
1618 || url
.getName(0, true, INetURLObject::DecodeMechanism::WithCharset
) != "tmp")
1622 if (maFileName
.indexOf('/') != -1) {
1623 SAL_WARN("sfx.dialog", maFileName
<< " contains /");
1627 maFileName
, false, INetURLObject::LAST_SEGMENT
,
1628 INetURLObject::EncodeMechanism::All
);
1630 osl::FileBase::RC e
= osl::FileBase::getSystemPathFromFileURL(
1631 url
.GetMainURL(INetURLObject::DecodeMechanism::NONE
), sysPathU
);
1632 if (e
!= osl::FileBase::E_None
) {
1635 "getSystemPathFromFileURL("
1636 << url
.GetMainURL(INetURLObject::DecodeMechanism::NONE
) << ") failed with "
1641 if (!sysPathU
.convertToString(
1642 &sysPathC
, osl_getThreadTextEncoding(),
1643 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
1644 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
)))
1648 "convertToString(" << sysPathU
<< ") failed for encoding "
1649 << +osl_getThreadTextEncoding());
1652 struct stat aFileStat
;
1653 if (stat(sysPathC
.getStr(), &aFileStat
) == -1) {
1654 SAL_WARN( "sfx.dialog", "stat(" << sysPathC
<< ") failed with errno " << errno
);
1657 if ((aFileStat
.st_mode
& (S_IRWXO
| S_IRWXG
| S_IRWXU
)) == S_IRUSR
) {
1658 maPath
= SvtPathOptions().GetWorkPath();
1659 mxFileDlg
->setDisplayDirectory( maPath
);
1666 void FileDialogHelper_Impl::displayFolder( const OUString
& _rPath
)
1668 if ( _rPath
.isEmpty() )
1673 if ( mxFileDlg
.is() )
1677 mxFileDlg
->setDisplayDirectory( maPath
);
1680 catch( const IllegalArgumentException
& )
1682 TOOLS_WARN_EXCEPTION( "sfx", "FileDialogHelper_Impl::displayFolder" );
1687 void FileDialogHelper_Impl::setFileName( const OUString
& _rFile
)
1689 maFileName
= _rFile
;
1690 if ( mxFileDlg
.is() )
1694 mxFileDlg
->setDefaultName( maFileName
);
1697 catch( const IllegalArgumentException
& )
1699 TOOLS_WARN_EXCEPTION( "sfx", "FileDialogHelper_Impl::setFileName" );
1704 void FileDialogHelper_Impl::setFilter( const OUString
& rFilter
)
1706 DBG_ASSERT( rFilter
.indexOf(':') == -1, "Old filter name used!");
1708 maCurFilter
= rFilter
;
1710 if ( !rFilter
.isEmpty() && mpMatcher
)
1712 std::shared_ptr
<const SfxFilter
> pFilter
= mpMatcher
->GetFilter4FilterName(
1713 rFilter
, m_nMustFlags
, m_nDontFlags
);
1715 maCurFilter
= pFilter
->GetUIName();
1718 if ( !maCurFilter
.isEmpty() && mxFileDlg
.is() )
1722 mxFileDlg
->setCurrentFilter( maCurFilter
);
1724 catch( const IllegalArgumentException
& ){}
1728 void FileDialogHelper_Impl::createMatcher( const OUString
& rFactory
)
1730 if (mbDeleteMatcher
)
1733 mpMatcher
= new SfxFilterMatcher( SfxObjectShell::GetServiceNameFromFactory(rFactory
) );
1734 mbDeleteMatcher
= true;
1737 void FileDialogHelper_Impl::addFilters( const OUString
& rFactory
,
1738 SfxFilterFlags nMust
,
1739 SfxFilterFlags nDont
)
1741 if ( ! mxFileDlg
.is() )
1744 if (mbDeleteMatcher
)
1747 // we still need a matcher to convert UI names to filter names
1748 if ( rFactory
.isEmpty() )
1750 SfxApplication
*pSfxApp
= SfxGetpApp();
1751 mpMatcher
= &pSfxApp
->GetFilterMatcher();
1752 mbDeleteMatcher
= false;
1756 mpMatcher
= new SfxFilterMatcher( rFactory
);
1757 mbDeleteMatcher
= true;
1760 uno::Reference
< XMultiServiceFactory
> xSMGR
= ::comphelper::getProcessServiceFactory();
1761 uno::Reference
< XContainerQuery
> xFilterCont(
1762 xSMGR
->createInstance("com.sun.star.document.FilterFactory"),
1764 if ( ! xFilterCont
.is() )
1767 m_nMustFlags
|= nMust
;
1768 m_nDontFlags
|= nDont
;
1770 // create the list of filters
1772 "getSortedFilterList()"
1774 rFactory
+ // use long name here !
1776 OUString::number(static_cast<sal_Int32
>(m_nMustFlags
)) +
1778 OUString::number(static_cast<sal_Int32
>(m_nDontFlags
));
1780 uno::Reference
< XEnumeration
> xResult
;
1783 xResult
= xFilterCont
->createSubSetEnumerationByQuery(sQuery
);
1785 catch( const uno::Exception
& )
1787 SAL_WARN( "sfx.dialog", "Could not get filters from the configuration!" );
1790 TSortedFilterList
aIter (xResult
);
1792 // append the filters
1793 OUString sFirstFilter
;
1794 if (OPEN
== lcl_OpenOrSave(m_nDialogType
))
1795 ::sfx2::appendFiltersForOpen( aIter
, mxFileDlg
, sFirstFilter
, *this );
1796 else if ( mbExport
)
1797 ::sfx2::appendExportFilters( aIter
, mxFileDlg
, sFirstFilter
, *this );
1799 ::sfx2::appendFiltersForSave( aIter
, mxFileDlg
, sFirstFilter
, *this, rFactory
);
1801 // set our initial selected filter (if we do not already have one)
1802 if ( maSelectFilter
.isEmpty() )
1803 maSelectFilter
= sFirstFilter
;
1806 void FileDialogHelper_Impl::addFilter( const OUString
& rFilterName
,
1807 const OUString
& rExtension
)
1809 if ( ! mxFileDlg
.is() )
1814 mxFileDlg
->appendFilter( rFilterName
, rExtension
);
1816 if ( maSelectFilter
.isEmpty() )
1817 maSelectFilter
= rFilterName
;
1819 catch( const IllegalArgumentException
& )
1821 SAL_WARN( "sfx.dialog", "Could not append Filter" << rFilterName
);
1825 void FileDialogHelper_Impl::addGraphicFilter()
1827 if ( ! mxFileDlg
.is() )
1830 // create the list of filters
1831 mpGraphicFilter
.reset( new GraphicFilter
);
1832 sal_uInt16 i
, j
, nCount
= mpGraphicFilter
->GetImportFormatCount();
1834 // compute the extension string for all known import filters
1835 OUString aExtensions
;
1837 for ( i
= 0; i
< nCount
; i
++ )
1842 OUString sWildcard
= mpGraphicFilter
->GetImportWildcard( i
, j
++ );
1843 if ( sWildcard
.isEmpty() )
1845 if ( aExtensions
.indexOf( sWildcard
) == -1 )
1847 if ( !aExtensions
.isEmpty() )
1849 aExtensions
+= sWildcard
;
1855 if ( aExtensions
.getLength() > 240 )
1856 aExtensions
= FILEDIALOG_FILTER_ALL
;
1858 bool bIsInOpenMode
= isInOpenMode();
1862 // if the extension is not "All files", insert "All images"
1863 if (aExtensions
!= FILEDIALOG_FILTER_ALL
)
1865 OUString aAllFilterName
= SfxResId(STR_SFX_IMPORT_ALL_IMAGES
);
1866 aAllFilterName
= ::sfx2::addExtension( aAllFilterName
, aExtensions
, bIsInOpenMode
, *this );
1867 mxFileDlg
->appendFilter( aAllFilterName
, aExtensions
);
1868 maSelectFilter
= aAllFilterName
; // and make it the default
1871 // rhbz#1715109 always include All files *.* or *
1872 OUString aAllFilesName
= SfxResId( STR_SFX_FILTERNAME_ALL
);
1873 aAllFilesName
= ::sfx2::addExtension( aAllFilesName
, FILEDIALOG_FILTER_ALL
, bIsInOpenMode
, *this );
1874 mxFileDlg
->appendFilter( aAllFilesName
, FILEDIALOG_FILTER_ALL
);
1876 // if the extension is "All files", make that the default
1877 if (aExtensions
== FILEDIALOG_FILTER_ALL
)
1878 maSelectFilter
= aAllFilesName
;
1880 catch( const IllegalArgumentException
& )
1882 SAL_WARN( "sfx.dialog", "Could not append Filter" );
1885 // Now add the filter
1886 for ( i
= 0; i
< nCount
; i
++ )
1888 OUString aName
= mpGraphicFilter
->GetImportFormatName( i
);
1893 OUString sWildcard
= mpGraphicFilter
->GetImportWildcard( i
, j
++ );
1894 if ( sWildcard
.isEmpty() )
1896 if ( aExt
.indexOf( sWildcard
) == -1 )
1898 if ( !aExt
.isEmpty() )
1903 aName
= ::sfx2::addExtension( aName
, aExt
, bIsInOpenMode
, *this );
1906 mxFileDlg
->appendFilter( aName
, aExt
);
1908 catch( const IllegalArgumentException
& )
1910 SAL_WARN( "sfx.dialog", "Could not append Filter" );
1915 #define GRF_CONFIG_STR " "
1916 #define STD_CONFIG_STR "1 "
1918 static void SetToken( OUString
& rOrigStr
, sal_Int32 nToken
, sal_Unicode cTok
, const OUString
& rStr
)
1920 const sal_Unicode
* pStr
= rOrigStr
.getStr();
1921 sal_Int32 nLen
= rOrigStr
.getLength();
1923 sal_Int32 nFirstChar
= 0;
1924 sal_Int32 i
= nFirstChar
;
1926 // Determine token position and length
1930 // Increase token count if match
1931 if ( *pStr
== cTok
)
1935 if ( nTok
== nToken
)
1939 if ( nTok
> nToken
)
1948 if ( nTok
>= nToken
)
1949 rOrigStr
= rOrigStr
.replaceAt( nFirstChar
, i
-nFirstChar
, rStr
);
1953 void FileDialogHelper_Impl::saveConfig()
1955 uno::Reference
< XFilePickerControlAccess
> xDlg( mxFileDlg
, UNO_QUERY
);
1963 SvtViewOptions
aDlgOpt( EViewType::Dialog
, IMPGRF_CONFIGNAME
);
1967 aValue
= xDlg
->getValue( ExtendedFilePickerElementIds::CHECKBOX_PREVIEW
, 0 );
1968 bool bValue
= false;
1970 OUString
aUserData(GRF_CONFIG_STR
);
1971 SetToken( aUserData
, 1, ' ', OUString::number( static_cast<sal_Int32
>(bValue
) ) );
1973 INetURLObject
aObj( getPath() );
1975 if ( aObj
.GetProtocol() == INetProtocol::File
)
1976 SetToken( aUserData
, 2, ' ', aObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
1978 OUString aFilter
= getFilter();
1979 aFilter
= EncodeSpaces_Impl( aFilter
);
1980 SetToken( aUserData
, 3, ' ', aFilter
);
1982 aDlgOpt
.SetUserItem( USERITEM_NAME
, makeAny( aUserData
) );
1984 catch( const IllegalArgumentException
& ){}
1988 bool bWriteConfig
= false;
1989 SvtViewOptions
aDlgOpt( EViewType::Dialog
, IODLG_CONFIGNAME
);
1990 OUString
aUserData(STD_CONFIG_STR
);
1992 if ( aDlgOpt
.Exists() )
1994 Any aUserItem
= aDlgOpt
.GetUserItem( USERITEM_NAME
);
1996 if ( aUserItem
>>= aTemp
)
2004 aValue
= xDlg
->getValue( ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION
, 0 );
2005 bool bAutoExt
= true;
2006 aValue
>>= bAutoExt
;
2007 SetToken( aUserData
, 0, ' ', OUString::number( static_cast<sal_Int32
>(bAutoExt
) ) );
2008 bWriteConfig
= true;
2010 catch( const IllegalArgumentException
& ){}
2013 if ( ! mbIsSaveDlg
)
2015 OUString aPath
= getPath();
2016 if ( comphelper::isFileUrl( aPath
) )
2018 SetToken( aUserData
, 1, ' ', aPath
);
2019 bWriteConfig
= true;
2023 if( mbHasSelectionBox
&& mbSelectionFltrEnabled
)
2027 aValue
= xDlg
->getValue( ExtendedFilePickerElementIds::CHECKBOX_SELECTION
, 0 );
2028 bool bSelection
= true;
2029 aValue
>>= bSelection
;
2030 if ( comphelper::string::getTokenCount(aUserData
, ' ') < 3 )
2032 SetToken( aUserData
, 2, ' ', OUString::number( static_cast<sal_Int32
>(bSelection
) ) );
2033 bWriteConfig
= true;
2035 catch( const IllegalArgumentException
& ){}
2039 aDlgOpt
.SetUserItem( USERITEM_NAME
, makeAny( aUserData
) );
2042 SfxApplication
*pSfxApp
= SfxGetpApp();
2043 pSfxApp
->SetLastDir_Impl( getPath() );
2048 OUString
getInitPath( const OUString
& _rFallback
, const sal_Int32 _nFallbackToken
)
2050 SfxApplication
*pSfxApp
= SfxGetpApp();
2051 OUString sPath
= pSfxApp
->GetLastDir_Impl();
2053 if ( sPath
.isEmpty() )
2054 sPath
= _rFallback
.getToken( _nFallbackToken
, ' ' );
2056 // check if the path points to a valid (accessible) directory
2057 bool bValid
= false;
2058 if ( !sPath
.isEmpty() )
2060 OUString
sPathCheck( sPath
);
2061 if ( sPathCheck
[ sPathCheck
.getLength() - 1 ] != '/' )
2066 ::ucbhelper::Content
aContent( sPathCheck
,
2067 utl::UCBContentHelper::getDefaultCommandEnvironment(),
2068 comphelper::getProcessComponentContext() );
2069 bValid
= aContent
.isFolder();
2071 catch( const Exception
& ) {}
2081 void FileDialogHelper_Impl::loadConfig()
2083 uno::Reference
< XFilePickerControlAccess
> xDlg( mxFileDlg
, UNO_QUERY
);
2091 SvtViewOptions
aViewOpt( EViewType::Dialog
, IMPGRF_CONFIGNAME
);
2094 if ( aViewOpt
.Exists() )
2096 Any aUserItem
= aViewOpt
.GetUserItem( USERITEM_NAME
);
2098 if ( aUserItem
>>= aTemp
)
2102 if ( !aUserData
.isEmpty() )
2106 // respect the last "insert as link" state
2107 bool bLink
= aUserData
.getToken( 0, ' ' ).toInt32();
2109 xDlg
->setValue( ExtendedFilePickerElementIds::CHECKBOX_LINK
, 0, aValue
);
2111 // respect the last "show preview" state
2112 bool bShowPreview
= aUserData
.getToken( 1, ' ' ).toInt32();
2113 aValue
<<= bShowPreview
;
2114 xDlg
->setValue( ExtendedFilePickerElementIds::CHECKBOX_PREVIEW
, 0, aValue
);
2116 if ( maPath
.isEmpty() )
2117 displayFolder( getInitPath( aUserData
, 2 ) );
2119 if ( maCurFilter
.isEmpty() )
2121 OUString aFilter
= aUserData
.getToken( 3, ' ' );
2122 aFilter
= DecodeSpaces_Impl( aFilter
);
2123 setFilter( aFilter
);
2126 // set the member so we know that we have to show the preview
2127 mbShowPreview
= bShowPreview
;
2129 catch( const IllegalArgumentException
& ){}
2132 if ( maPath
.isEmpty() )
2133 displayFolder( SvtPathOptions().GetGraphicPath() );
2137 SvtViewOptions
aViewOpt( EViewType::Dialog
, IODLG_CONFIGNAME
);
2140 if ( aViewOpt
.Exists() )
2142 Any aUserItem
= aViewOpt
.GetUserItem( USERITEM_NAME
);
2144 if ( aUserItem
>>= aTemp
)
2148 if ( aUserData
.isEmpty() )
2149 aUserData
= STD_CONFIG_STR
;
2151 if ( maPath
.isEmpty() )
2152 displayFolder( getInitPath( aUserData
, 1 ) );
2156 sal_Int32 nFlag
= aUserData
.getToken( 0, ' ' ).toInt32();
2157 aValue
<<= static_cast<bool>(nFlag
);
2160 xDlg
->setValue( ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION
, 0, aValue
);
2162 catch( const IllegalArgumentException
& ){}
2165 if( mbHasSelectionBox
)
2167 sal_Int32 nFlag
= aUserData
.getToken( 2, ' ' ).toInt32();
2168 aValue
<<= static_cast<bool>(nFlag
);
2171 xDlg
->setValue( ExtendedFilePickerElementIds::CHECKBOX_SELECTION
, 0, aValue
);
2173 catch( const IllegalArgumentException
& ){}
2176 if ( maPath
.isEmpty() )
2177 displayFolder( SvtPathOptions().GetWorkPath() );
2181 void FileDialogHelper_Impl::setDefaultValues()
2183 // when no filter is set, we set the currentFilter to <all>
2184 if ( maCurFilter
.isEmpty() && !maSelectFilter
.isEmpty() )
2188 mxFileDlg
->setCurrentFilter( maSelectFilter
);
2190 catch( const IllegalArgumentException
& )
2194 // when no path is set, we use the standard 'work' folder
2195 if ( maPath
.isEmpty() )
2197 OUString aWorkFolder
= SvtPathOptions().GetWorkPath();
2200 mxFileDlg
->setDisplayDirectory( aWorkFolder
);
2202 catch( const Exception
& )
2204 OSL_FAIL( "FileDialogHelper_Impl::setDefaultValues: caught an exception while setting the display directory!" );
2209 bool FileDialogHelper_Impl::isShowFilterExtensionEnabled() const
2211 return !maFilters
.empty();
2214 void FileDialogHelper_Impl::addFilterPair( const OUString
& rFilter
,
2215 const OUString
& rFilterWithExtension
)
2217 maFilters
.emplace_back( rFilter
, rFilterWithExtension
);
2221 OUString
FileDialogHelper_Impl::getFilterName( const OUString
& rFilterWithExtension
) const
2224 for (auto const& filter
: maFilters
)
2226 if (filter
.Second
== rFilterWithExtension
)
2228 sRet
= filter
.First
;
2235 OUString
FileDialogHelper_Impl::getFilterWithExtension( const OUString
& rFilter
) const
2238 for (auto const& filter
: maFilters
)
2240 if ( filter
.First
== rFilter
)
2242 sRet
= filter
.Second
;
2249 void FileDialogHelper_Impl::SetContext( FileDialogHelper::Context _eNewContext
)
2251 meContext
= _eNewContext
;
2253 const std::u16string_view
* pConfigId
= GetLastFilterConfigId( _eNewContext
);
2255 LoadLastUsedFilter( *pConfigId
);
2260 FileDialogHelper::FileDialogHelper(
2261 sal_Int16 nDialogType
,
2262 FileDialogFlags nFlags
,
2263 const OUString
& rFact
,
2264 SfxFilterFlags nMust
,
2265 SfxFilterFlags nDont
,
2266 weld::Window
* pPreferredParent
)
2268 mpImpl(new FileDialogHelper_Impl(this, nDialogType
, nFlags
, SFX2_IMPL_DIALOG_CONFIG
, pPreferredParent
))
2271 // create the list of filters
2273 SfxObjectShell::GetServiceNameFromFactory(rFact
), nMust
, nDont
);
2276 FileDialogHelper::FileDialogHelper(
2277 sal_Int16 nDialogType
,
2278 FileDialogFlags nFlags
,
2279 const OUString
& rFact
,
2281 SfxFilterFlags nMust
,
2282 SfxFilterFlags nDont
,
2283 const OUString
& rStandardDir
,
2284 const css::uno::Sequence
< OUString
>& rDenyList
,
2285 weld::Window
* pPreferredParent
)
2287 mpImpl( new FileDialogHelper_Impl( this, nDialogType
, nFlags
, nDialog
, pPreferredParent
, rStandardDir
, rDenyList
) )
2289 // create the list of filters
2291 SfxObjectShell::GetServiceNameFromFactory(rFact
), nMust
, nDont
);
2294 FileDialogHelper::FileDialogHelper(sal_Int16 nDialogType
, FileDialogFlags nFlags
, weld::Window
* pPreferredParent
)
2296 mpImpl( new FileDialogHelper_Impl( this, nDialogType
, nFlags
, SFX2_IMPL_DIALOG_CONFIG
, pPreferredParent
) )
2300 FileDialogHelper::FileDialogHelper(
2301 sal_Int16 nDialogType
,
2302 FileDialogFlags nFlags
,
2303 const OUString
& aFilterUIName
,
2304 const OUString
& aExtName
,
2305 const OUString
& rStandardDir
,
2306 const css::uno::Sequence
< OUString
>& rDenyList
,
2307 weld::Window
* pPreferredParent
)
2309 mpImpl( new FileDialogHelper_Impl( this, nDialogType
, nFlags
, SFX2_IMPL_DIALOG_CONFIG
, pPreferredParent
, rStandardDir
, rDenyList
) )
2311 // the wildcard here is expected in form "*.extension"
2313 if ( aExtName
.indexOf( '*' ) != 0 )
2315 if ( !aExtName
.isEmpty() && aExtName
.indexOf( '.' ) != 0 )
2321 aWildcard
+= aExtName
;
2323 OUString
const aUIString
= ::sfx2::addExtension(
2324 aFilterUIName
, aWildcard
, (OPEN
== lcl_OpenOrSave(mpImpl
->m_nDialogType
)), *mpImpl
);
2325 AddFilter( aUIString
, aWildcard
);
2328 FileDialogHelper::~FileDialogHelper()
2333 void FileDialogHelper::CreateMatcher( const OUString
& rFactory
)
2335 mpImpl
->createMatcher( SfxObjectShell::GetServiceNameFromFactory(rFactory
) );
2338 void FileDialogHelper::SetControlHelpIds( const sal_Int16
* _pControlId
, const char** _pHelpId
)
2340 mpImpl
->setControlHelpIds( _pControlId
, _pHelpId
);
2343 void FileDialogHelper::SetContext( Context _eNewContext
)
2345 mpImpl
->SetContext( _eNewContext
);
2348 IMPL_LINK_NOARG(FileDialogHelper
, ExecuteSystemFilePicker
, void*, void)
2350 m_nError
= mpImpl
->execute();
2351 m_aDialogClosedLink
.Call( this );
2354 // rDirPath has to be a directory
2355 ErrCode
FileDialogHelper::Execute( std::vector
<OUString
>& rpURLList
,
2356 std::unique_ptr
<SfxItemSet
>& rpSet
,
2358 const OUString
& rDirPath
)
2360 SetDisplayFolder( rDirPath
);
2361 return mpImpl
->execute( rpURLList
, rpSet
, rFilter
);
2365 ErrCode
FileDialogHelper::Execute()
2367 return mpImpl
->execute();
2370 ErrCode
FileDialogHelper::Execute( std::unique_ptr
<SfxItemSet
>& rpSet
,
2374 std::vector
<OUString
> rURLList
;
2375 nRet
= mpImpl
->execute(rURLList
, rpSet
, rFilter
);
2379 void FileDialogHelper::StartExecuteModal( const Link
<FileDialogHelper
*,void>& rEndDialogHdl
)
2381 m_aDialogClosedLink
= rEndDialogHdl
;
2382 m_nError
= ERRCODE_NONE
;
2383 if ( mpImpl
->isSystemFilePicker() )
2384 Application::PostUserEvent( LINK( this, FileDialogHelper
, ExecuteSystemFilePicker
) );
2386 mpImpl
->implStartExecute();
2389 sal_Int16
FileDialogHelper::GetDialogType() const { return mpImpl
? mpImpl
->m_nDialogType
: 0; }
2391 bool FileDialogHelper::IsPasswordEnabled() const
2393 return mpImpl
&& mpImpl
->isPasswordEnabled();
2396 OUString
FileDialogHelper::GetRealFilter() const
2400 mpImpl
->getRealFilter( sFilter
);
2404 void FileDialogHelper::SetTitle( const OUString
& rNewTitle
)
2406 if ( mpImpl
->mxFileDlg
.is() )
2407 mpImpl
->mxFileDlg
->setTitle( rNewTitle
);
2410 OUString
FileDialogHelper::GetPath() const
2414 if ( !mpImpl
->mlLastURLs
.empty())
2415 return mpImpl
->mlLastURLs
[0];
2417 if ( mpImpl
->mxFileDlg
.is() )
2419 Sequence
< OUString
> aPathSeq
= mpImpl
->mxFileDlg
->getFiles();
2421 if ( aPathSeq
.getLength() == 1 )
2423 aPath
= aPathSeq
[0];
2430 Sequence
< OUString
> FileDialogHelper::GetMPath() const
2432 if ( !mpImpl
->mlLastURLs
.empty())
2433 return comphelper::containerToSequence(mpImpl
->mlLastURLs
);
2435 if ( mpImpl
->mxFileDlg
.is() )
2436 return mpImpl
->mxFileDlg
->getFiles();
2439 Sequence
< OUString
> aEmpty
;
2444 Sequence
< OUString
> FileDialogHelper::GetSelectedFiles() const
2446 // a) the new way (optional!)
2447 uno::Sequence
< OUString
> aResultSeq
;
2448 if (mpImpl
->mxFileDlg
.is())
2450 aResultSeq
= mpImpl
->mxFileDlg
->getSelectedFiles();
2452 // b) the olde way ... non optional.
2455 uno::Reference
< XFilePicker
> xPickOld(mpImpl
->mxFileDlg
, UNO_QUERY_THROW
);
2456 Sequence
< OUString
> lFiles
= xPickOld
->getFiles();
2457 ::sal_Int32 nFiles
= lFiles
.getLength();
2460 aResultSeq
= Sequence
< OUString
>( nFiles
-1 );
2462 INetURLObject
aPath( lFiles
[0] );
2463 aPath
.setFinalSlash();
2465 for (::sal_Int32 i
= 1; i
< nFiles
; i
++)
2468 aPath
.Append( lFiles
[i
] );
2470 aPath
.setName( lFiles
[i
] );
2472 aResultSeq
[i
-1] = aPath
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
2476 aResultSeq
= lFiles
;
2482 OUString
FileDialogHelper::GetDisplayDirectory() const
2484 return mpImpl
->getPath();
2487 OUString
FileDialogHelper::GetCurrentFilter() const
2489 return mpImpl
->getFilter();
2492 ErrCode
FileDialogHelper::GetGraphic( Graphic
& rGraphic
) const
2494 return mpImpl
->getGraphic( rGraphic
);
2497 static int impl_isFolder( const OUString
& rPath
)
2501 ::ucbhelper::Content
aContent(
2502 rPath
, uno::Reference
< ucb::XCommandEnvironment
> (),
2503 comphelper::getProcessComponentContext() );
2504 if ( aContent
.isFolder() )
2509 catch ( const Exception
& )
2516 void FileDialogHelper::SetDisplayDirectory( const OUString
& _rPath
)
2518 if ( _rPath
.isEmpty() )
2521 // if the given path isn't a folder, we cut off the last part
2522 // and take it as filename and the rest of the path should be
2525 INetURLObject
aObj( _rPath
);
2527 OUString sFileName
= aObj
.GetLastName(INetURLObject::DecodeMechanism::WithCharset
);
2528 aObj
.removeSegment();
2529 OUString sPath
= aObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
2531 int nIsFolder
= impl_isFolder( _rPath
);
2532 if ( nIsFolder
== 0 ||
2533 ( nIsFolder
== -1 && impl_isFolder( sPath
) == 1 ) )
2535 mpImpl
->setFileName( sFileName
);
2536 mpImpl
->displayFolder( sPath
);
2540 INetURLObject
aObjPathName( _rPath
);
2541 OUString
sFolder( aObjPathName
.GetMainURL( INetURLObject::DecodeMechanism::NONE
) );
2542 if ( sFolder
.isEmpty() )
2544 // _rPath is not a valid path -> fallback to home directory
2545 osl::Security aSecurity
;
2546 aSecurity
.getHomeDir( sFolder
);
2548 mpImpl
->displayFolder( sFolder
);
2552 void FileDialogHelper::SetDisplayFolder( const OUString
& _rURL
)
2554 mpImpl
->displayFolder( _rURL
);
2557 void FileDialogHelper::SetFileName( const OUString
& _rFileName
)
2559 mpImpl
->setFileName( _rFileName
);
2562 void FileDialogHelper::AddFilter( const OUString
& rFilterName
,
2563 const OUString
& rExtension
)
2565 mpImpl
->addFilter( rFilterName
, rExtension
);
2568 void FileDialogHelper::SetCurrentFilter( const OUString
& rFilter
)
2570 OUString
sFilter( rFilter
);
2571 if ( mpImpl
->isShowFilterExtensionEnabled() )
2572 sFilter
= mpImpl
->getFilterWithExtension( rFilter
);
2573 mpImpl
->setFilter( sFilter
);
2576 const uno::Reference
< XFilePicker3
>& FileDialogHelper::GetFilePicker() const
2578 return mpImpl
->mxFileDlg
;
2581 // XFilePickerListener Methods
2582 void FileDialogHelper::FileSelectionChanged()
2584 mpImpl
->handleFileSelectionChanged();
2587 void FileDialogHelper::DirectoryChanged()
2589 mpImpl
->handleDirectoryChanged();
2592 OUString
FileDialogHelper::HelpRequested( const FilePickerEvent
& aEvent
)
2594 return sfx2::FileDialogHelper_Impl::handleHelpRequested( aEvent
);
2597 void FileDialogHelper::ControlStateChanged( const FilePickerEvent
& aEvent
)
2599 mpImpl
->handleControlStateChanged( aEvent
);
2602 void FileDialogHelper::DialogSizeChanged()
2604 mpImpl
->handleDialogSizeChanged();
2607 void FileDialogHelper::DialogClosed( const DialogClosedEvent
& _rEvent
)
2609 m_nError
= ( RET_OK
== _rEvent
.DialogResult
) ? ERRCODE_NONE
: ERRCODE_ABORT
;
2610 m_aDialogClosedLink
.Call( this );
2613 ErrCode
FileOpenDialog_Impl( weld::Window
* pParent
,
2614 sal_Int16 nDialogType
,
2615 FileDialogFlags nFlags
,
2616 std::vector
<OUString
>& rpURLList
,
2618 std::unique_ptr
<SfxItemSet
>& rpSet
,
2619 const OUString
* pPath
,
2621 const OUString
& rStandardDir
,
2622 const css::uno::Sequence
< OUString
>& rDenyList
)
2625 std::unique_ptr
<FileDialogHelper
> pDialog
;
2626 // Sign existing PDF: only works with PDF files and they are opened
2627 // read-only to discourage editing (which would invalidate existing
2629 if (nFlags
& FileDialogFlags::SignPDF
)
2630 pDialog
.reset(new FileDialogHelper(nDialogType
, nFlags
, SfxResId(STR_SFX_FILTERNAME_PDF
), "pdf", rStandardDir
, rDenyList
, pParent
));
2632 pDialog
.reset(new FileDialogHelper(nDialogType
, nFlags
, OUString(), nDialog
, SfxFilterFlags::NONE
, SfxFilterFlags::NONE
, rStandardDir
, rDenyList
, pParent
));
2638 nRet
= pDialog
->Execute(rpURLList
, rpSet
, rFilter
, aPath
);
2639 DBG_ASSERT( rFilter
.indexOf(": ") == -1, "Old filter name used!");
2641 if (rpSet
&& nFlags
& FileDialogFlags::SignPDF
)
2642 rpSet
->Put(SfxBoolItem(SID_DOC_READONLY
, true));
2646 ErrCode
RequestPassword(const std::shared_ptr
<const SfxFilter
>& pCurrentFilter
, OUString
const & aURL
, SfxItemSet
* pSet
, const css::uno::Reference
<css::awt::XWindow
>& rParent
)
2648 uno::Reference
<task::XInteractionHandler2
> xInteractionHandler
= task::InteractionHandler::createWithParent(::comphelper::getProcessComponentContext(), rParent
);
2649 // TODO: need a save way to distinguish MS filters from other filters
2650 // for now MS-filters are the only alien filters that support encryption
2651 const bool bMSType
= !pCurrentFilter
->IsOwnFormat();
2652 // For OOXML we can use the standard password ("unlimited" characters)
2653 // request, otherwise the MS limited password request is needed.
2654 const bool bOOXML
= bMSType
&& lclSupportsOOXMLEncryption( pCurrentFilter
->GetFilterName());
2655 const ::comphelper::DocPasswordRequestType eType
= bMSType
&& !bOOXML
?
2656 ::comphelper::DocPasswordRequestType::MS
:
2657 ::comphelper::DocPasswordRequestType::Standard
;
2659 ::rtl::Reference
< ::comphelper::DocPasswordRequest
> pPasswordRequest( new ::comphelper::DocPasswordRequest( eType
, css::task::PasswordRequestMode_PASSWORD_CREATE
, aURL
, bool( pCurrentFilter
->GetFilterFlags() & SfxFilterFlags::PASSWORDTOMODIFY
) ) );
2661 uno::Reference
< css::task::XInteractionRequest
> rRequest( pPasswordRequest
.get() );
2664 xInteractionHandler
->handle( rRequest
);
2665 if (!pPasswordRequest
->isPassword() || bMSType
)
2669 OString
const utf8Pwd(OUStringToOString(pPasswordRequest
->getPassword(), RTL_TEXTENCODING_UTF8
));
2670 OString
const utf8Ptm(OUStringToOString(pPasswordRequest
->getPasswordToModify(), RTL_TEXTENCODING_UTF8
));
2671 if (!(52 <= utf8Pwd
.getLength() && utf8Pwd
.getLength() <= 55
2672 && SvtSaveOptions().GetODFSaneDefaultVersion() < SvtSaveOptions::ODFSVER_012
)
2673 && (52 > utf8Ptm
.getLength() || utf8Ptm
.getLength() > 55))
2677 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(Application::GetFrameWeld(rParent
), VclMessageType::Warning
,
2678 VclButtonsType::Ok
, SfxResId(STR_PASSWORD_LEN
)));
2679 xBox
->set_secondary_text(SfxResId(STR_PASSWORD_WARNING
));
2683 if ( pPasswordRequest
->isPassword() )
2685 if ( pPasswordRequest
->getPassword().getLength() )
2687 css::uno::Sequence
< css::beans::NamedValue
> aEncryptionData
;
2689 // TODO/LATER: The filters should show the password dialog themself in future
2694 ::comphelper::SequenceAsHashMap aHashData
;
2695 aHashData
[ OUString( "OOXPassword" ) ] <<= pPasswordRequest
->getPassword();
2696 aHashData
[ OUString( "CryptoType" ) ] <<= OUString( "Standard" );
2697 aEncryptionData
= aHashData
.getAsConstNamedValueList();
2701 uno::Sequence
< sal_Int8
> aUniqueID
= ::comphelper::DocPasswordHelper::GenerateRandomByteSequence( 16 );
2702 uno::Sequence
< sal_Int8
> aEncryptionKey
= ::comphelper::DocPasswordHelper::GenerateStd97Key( pPasswordRequest
->getPassword(), aUniqueID
);
2704 if ( aEncryptionKey
.hasElements() )
2706 ::comphelper::SequenceAsHashMap aHashData
;
2707 aHashData
[ OUString( "STD97EncryptionKey" ) ] <<= aEncryptionKey
;
2708 aHashData
[ OUString( "STD97UniqueID" ) ] <<= aUniqueID
;
2710 aEncryptionData
= aHashData
.getAsConstNamedValueList();
2714 return ERRCODE_IO_NOTSUPPORTED
;
2719 // tdf#118639: We need ODF encryption data for autorecovery where password will already
2720 // be unavailable, even for non-ODF documents, so append it here unconditionally
2721 pSet
->Put(SfxUnoAnyItem(
2723 uno::makeAny(comphelper::concatSequences(
2724 aEncryptionData
, comphelper::OStorageHelper::CreatePackageEncryptionData(
2725 pPasswordRequest
->getPassword())))));
2728 if ( pPasswordRequest
->getRecommendReadOnly() )
2729 pSet
->Put( SfxBoolItem( SID_RECOMMENDREADONLY
, true ) );
2733 // the empty password has 0 as Hash
2734 sal_Int32 nHash
= SfxMedium::CreatePasswordToModifyHash( pPasswordRequest
->getPasswordToModify(),
2735 pCurrentFilter
->GetServiceName() == "com.sun.star.text.TextDocument" );
2737 pSet
->Put( SfxUnoAnyItem( SID_MODIFYPASSWORDINFO
, uno::makeAny( nHash
) ) );
2741 uno::Sequence
< beans::PropertyValue
> aModifyPasswordInfo
= ::comphelper::DocPasswordHelper::GenerateNewModifyPasswordInfo( pPasswordRequest
->getPasswordToModify() );
2742 if ( aModifyPasswordInfo
.hasElements() )
2743 pSet
->Put( SfxUnoAnyItem( SID_MODIFYPASSWORDINFO
, uno::makeAny( aModifyPasswordInfo
) ) );
2747 return ERRCODE_ABORT
;
2748 return ERRCODE_NONE
;
2751 OUString
EncodeSpaces_Impl( const OUString
& rSource
)
2753 OUString sRet
= rSource
.replaceAll( " ", "%20" );
2757 OUString
DecodeSpaces_Impl( const OUString
& rSource
)
2759 OUString sRet
= rSource
.replaceAll( "%20", " " );
2763 } // end of namespace sfx2
2765 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */