    /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
    /*
     * This file is part of the LibreOffice project.
     *
     * This Source Code Form is subject to the terms of the Mozilla Public
     * License, v. 2.0. If a copy of the MPL was not distributed with this
     * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     *
     * This file incorporates work covered by the following license notice:
     *
     *   Licensed to the Apache Software Foundation (ASF) under one or more
     *   contributor license agreements. See the NOTICE file distributed
     *   with this work for additional information regarding copyright
     *   ownership. The ASF licenses this file to you under the Apache
     *   License, Version 2.0 (the "License"); you may not use this file
     *   except in compliance with the License. You may obtain a copy of
     *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
     */

    #include <memory>
    #include <sfx2/filedlghelper.hxx>
    #include <sal/types.h>
    #include <com/sun/star/lang/XInitialization.hpp>
    #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
    #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
    #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
    #include <com/sun/star/ui/dialogs/FilePreviewImageFormats.hpp>
    #include <com/sun/star/ui/dialogs/ControlActions.hpp>
    #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
    #include <com/sun/star/ui/dialogs/XControlInformation.hpp>
    #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
    #include <com/sun/star/ui/dialogs/XFilePickerNotifier.hpp>
    #include <com/sun/star/ui/dialogs/XFilePreview.hpp>
    #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
    #include <com/sun/star/ui/dialogs/XFilterGroupManager.hpp>
    #include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
    #include <com/sun/star/ui/dialogs/XAsynchronousExecutableDialog.hpp>
    #include <com/sun/star/lang/XServiceInfo.hpp>
    #include <com/sun/star/beans/XPropertySet.hpp>
    #include <com/sun/star/beans/NamedValue.hpp>
    #include <com/sun/star/embed/ElementModes.hpp>
    #include <com/sun/star/container/XEnumeration.hpp>
    #include <com/sun/star/container/XContainerQuery.hpp>
    #include <com/sun/star/task/InteractionHandler.hpp>
    #include <com/sun/star/task/XInteractionRequest.hpp>
    #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
    #include <comphelper/fileurl.hxx>
    #include <comphelper/processfactory.hxx>
    #include <comphelper/sequenceashashmap.hxx>
    #include <comphelper/string.hxx>
    #include <comphelper/types.hxx>
    #include <tools/urlobj.hxx>
    #include <vcl/help.hxx>
    #include <vcl/weld.hxx>
    #include <unotools/ucbstreamhelper.hxx>
    #include <unotools/ucbhelper.hxx>
    #include <osl/file.hxx>
    #include <osl/security.hxx>
    #include <osl/thread.hxx>
    #include <vcl/cvtgrf.hxx>
    #include <vcl/mnemonic.hxx>
    #include <unotools/pathoptions.hxx>
    #include <unotools/saveopt.hxx>
    #include <unotools/securityoptions.hxx>
    #include <svl/itemset.hxx>
    #include <svl/eitem.hxx>
    #include <svl/intitem.hxx>
    #include <svl/stritem.hxx>
    #include <vcl/dibtools.hxx>
    #include <vcl/graphicfilter.hxx>
    #include <unotools/viewoptions.hxx>
    #include <unotools/moduleoptions.hxx>
    #include <svtools/helpids.h>
    #include <comphelper/docpasswordrequest.hxx>
    #include <comphelper/docpasswordhelper.hxx>
    #include <ucbhelper/content.hxx>
    #include <ucbhelper/commandenvironment.hxx>
    #include <comphelper/storagehelper.hxx>
    #include <toolkit/helper/vclunohelper.hxx>
    #include <sfx2/app.hxx>
    #include <sfx2/frame.hxx>
    #include <sfx2/docfile.hxx>
    #include <sfx2/docfac.hxx>
    #include <openflag.hxx>
    #include <sfx2/passwd.hxx>
    #include <sfx2/sfxresid.hxx>
    #include <sfx2/sfxsids.hrc>
    #include "filtergrouping.hxx"
    #include <sfx2/request.hxx>
    #include "filedlgimpl.hxx"
    #include <helpids.h>
    #include <sfx2/strings.hrc>
    #include <rtl/strbuf.hxx>
    #include <sal/log.hxx>
    #include <comphelper/sequence.hxx>

    #ifdef UNX
    #include <errno.h>
    #include <sys/stat.h>
    #endif

    using namespace ::com::sun::star;
    using namespace ::com::sun::star::container;
    using namespace ::com::sun::star::lang;
    using namespace ::com::sun::star::ui::dialogs;
    using namespace ::com::sun::star::ui::dialogs::TemplateDescription;
    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::beans;
    using namespace ::cppu;

    #define IODLG_CONFIGNAME        "FilePicker_Save"
    #define IMPGRF_CONFIGNAME       "FilePicker_Graph"
    #define USERITEM_NAME           "UserItem"

    namespace sfx2
    {

    namespace
    {
        bool lclSupportsOOXMLEncryption(const OUString& aFilterName)
        {
            return  aFilterName == "Calc MS Excel 2007 XML"
                    ||  aFilterName == "MS Word 2007 XML"
                    ||  aFilterName == "Impress MS PowerPoint 2007 XML"
                    ||  aFilterName == "Impress MS PowerPoint 2007 XML AutoPlay"
                    ||  aFilterName == "Calc Office Open XML"
                    ||  aFilterName == "Impress Office Open XML"
                    ||  aFilterName == "Impress Office Open XML AutoPlay"
                    ||  aFilterName == "Office Open XML Text";
        }
    }

    const OUString* GetLastFilterConfigId( FileDialogHelper::Context _eContext )
    {
        static const OUString aSD_EXPORT_IDENTIFIER("SdExportLastFilter");
        static const OUString aSI_EXPORT_IDENTIFIER("SiExportLastFilter");
        static const OUString aSW_EXPORT_IDENTIFIER("SwExportLastFilter");

        const OUString* pRet = nullptr;

        switch( _eContext )
        {
            case FileDialogHelper::SD_EXPORT: pRet = &aSD_EXPORT_IDENTIFIER; break;
            case FileDialogHelper::SI_EXPORT: pRet = &aSI_EXPORT_IDENTIFIER; break;
            case FileDialogHelper::SW_EXPORT: pRet = &aSW_EXPORT_IDENTIFIER; break;
            default: break;
        }

        return pRet;
    }

    OUString EncodeSpaces_Impl( const OUString& rSource );
    OUString DecodeSpaces_Impl( const OUString& rSource );

    // FileDialogHelper_Impl

    // XFilePickerListener Methods
    void SAL_CALL FileDialogHelper_Impl::fileSelectionChanged( const FilePickerEvent& )
    {
        SolarMutexGuard aGuard;
        mpAntiImpl->FileSelectionChanged();
    }

    void SAL_CALL FileDialogHelper_Impl::directoryChanged( const FilePickerEvent& )
    {
        SolarMutexGuard aGuard;
        mpAntiImpl->DirectoryChanged();
    }

    OUString SAL_CALL FileDialogHelper_Impl::helpRequested( const FilePickerEvent& aEvent )
    {
        SolarMutexGuard aGuard;
        return sfx2::FileDialogHelper::HelpRequested( aEvent );
    }

    void SAL_CALL FileDialogHelper_Impl::controlStateChanged( const FilePickerEvent& aEvent )
    {
        SolarMutexGuard aGuard;
        mpAntiImpl->ControlStateChanged( aEvent );
    }

    void SAL_CALL FileDialogHelper_Impl::dialogSizeChanged()
    {
        SolarMutexGuard aGuard;
        mpAntiImpl->DialogSizeChanged();
    }

    // XDialogClosedListener Methods
    void SAL_CALL FileDialogHelper_Impl::dialogClosed( const DialogClosedEvent& _rEvent )
    {
        SolarMutexGuard aGuard;
        mpAntiImpl->DialogClosed( _rEvent );
        postExecute( _rEvent.DialogResult );
    }

    // handle XFilePickerListener events
    void FileDialogHelper_Impl::handleFileSelectionChanged()
    {
        if ( mbHasVersions )
            updateVersions();

        if ( mbShowPreview )
            maPreviewIdle.Start();
    }

    void FileDialogHelper_Impl::handleDirectoryChanged()
    {
        if ( mbShowPreview )
            TimeOutHdl_Impl( nullptr );
    }

    OUString FileDialogHelper_Impl::handleHelpRequested( const FilePickerEvent& aEvent )
    {
        //!!! todo: cache the help strings (here or TRA)

        OString sHelpId;
        // mapping from element id -> help id
        switch ( aEvent.ElementId )
        {
            case ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION :
                sHelpId = HID_FILESAVE_AUTOEXTENSION;
                break;

            case ExtendedFilePickerElementIds::CHECKBOX_PASSWORD :
                sHelpId = HID_FILESAVE_SAVEWITHPASSWORD;
                break;

            case ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS :
                sHelpId = HID_FILESAVE_CUSTOMIZEFILTER;
                break;

            case ExtendedFilePickerElementIds::CHECKBOX_READONLY :
                sHelpId = HID_FILEOPEN_READONLY;
                break;

            case ExtendedFilePickerElementIds::CHECKBOX_LINK :
                sHelpId = HID_FILEDLG_LINK_CB;
                break;

            case ExtendedFilePickerElementIds::CHECKBOX_PREVIEW :
                sHelpId = HID_FILEDLG_PREVIEW_CB;
                break;

            case ExtendedFilePickerElementIds::PUSHBUTTON_PLAY :
                sHelpId = HID_FILESAVE_DOPLAY;
                break;

            case ExtendedFilePickerElementIds::LISTBOX_VERSION_LABEL :
            case ExtendedFilePickerElementIds::LISTBOX_VERSION :
                sHelpId = HID_FILEOPEN_VERSION;
                break;

            case ExtendedFilePickerElementIds::LISTBOX_TEMPLATE_LABEL :
            case ExtendedFilePickerElementIds::LISTBOX_TEMPLATE :
                sHelpId = HID_FILESAVE_TEMPLATE;
                break;

            case ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE_LABEL :
            case ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE :
                sHelpId = HID_FILEOPEN_IMAGE_TEMPLATE;
                break;

            case ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR_LABEL :
            case ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR :
                sHelpId = HID_FILEOPEN_IMAGE_ANCHOR;
                break;

            case ExtendedFilePickerElementIds::CHECKBOX_SELECTION :
                sHelpId = HID_FILESAVE_SELECTION;
                break;

            default:
                SAL_WARN( "sfx.dialog", "invalid element id" );
        }

        OUString aHelpText;
        Help* pHelp = Application::GetHelp();
        if ( pHelp )
            aHelpText = pHelp->GetHelpText( OStringToOUString(sHelpId, RTL_TEXTENCODING_UTF8), nullptr );
        return aHelpText;
    }

    void FileDialogHelper_Impl::handleControlStateChanged( const FilePickerEvent& aEvent )
    {
        switch ( aEvent.ElementId )
        {
            case CommonFilePickerElementIds::LISTBOX_FILTER:
                updateFilterOptionsBox();
                enablePasswordBox( false );
                updateSelectionBox();
                // only use it for export and with our own dialog
                if ( mbExport && !mbSystemPicker )
                    updateExportButton();
                break;

            case ExtendedFilePickerElementIds::CHECKBOX_PREVIEW:
                updatePreviewState(true);
                break;
        }
    }

    void FileDialogHelper_Impl::handleDialogSizeChanged()
    {
        if ( mbShowPreview )
            TimeOutHdl_Impl( nullptr );
    }

    // XEventListener Methods
    void SAL_CALL FileDialogHelper_Impl::disposing( const EventObject& )
    {
        SolarMutexGuard aGuard;
        dispose();
    }

    void FileDialogHelper_Impl::dispose()
    {
        if ( mxFileDlg.is() )
        {
            // remove the event listener
            uno::Reference< XFilePickerNotifier > xNotifier( mxFileDlg, UNO_QUERY );
            if ( xNotifier.is() )
                xNotifier->removeFilePickerListener( this );

            ::comphelper::disposeComponent( mxFileDlg );
            mxFileDlg.clear();
        }
    }

    OUString FileDialogHelper_Impl::getCurrentFilterUIName() const
    {
        OUString aFilterName;
        uno::Reference< XFilterManager > xFltMgr( mxFileDlg, UNO_QUERY );

        if( xFltMgr.is() )
        {
            aFilterName = xFltMgr->getCurrentFilter();

            if ( !aFilterName.isEmpty() && isShowFilterExtensionEnabled() )
                aFilterName = getFilterName( aFilterName );
        }

        return aFilterName;
    }

    void FileDialogHelper_Impl::LoadLastUsedFilter( const OUString& _rContextIdentifier )
    {
        SvtViewOptions aDlgOpt( EViewType::Dialog, IODLG_CONFIGNAME );

        if( aDlgOpt.Exists() )
        {
            OUString    aLastFilter;
            if( aDlgOpt.GetUserItem( _rContextIdentifier ) >>= aLastFilter )
                setFilter( aLastFilter );
        }
    }

    void FileDialogHelper_Impl::SaveLastUsedFilter()
    {
        const OUString* pConfigId = GetLastFilterConfigId( meContext );
        if( pConfigId )
            SvtViewOptions( EViewType::Dialog, IODLG_CONFIGNAME ).SetUserItem( *pConfigId,
                                makeAny( getFilterWithExtension( getFilter() ) ) );
    }

    std::shared_ptr<const SfxFilter> FileDialogHelper_Impl::getCurentSfxFilter()
    {
        OUString aFilterName = getCurrentFilterUIName();

        if ( mpMatcher && !aFilterName.isEmpty() )
            return mpMatcher->GetFilter4UIName( aFilterName, m_nMustFlags, m_nDontFlags );

        return nullptr;
    }

    bool FileDialogHelper_Impl::updateExtendedControl( sal_Int16 _nExtendedControlId, bool _bEnable )
    {
        bool bIsEnabled = false;

        uno::Reference < XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY );
        if ( xCtrlAccess.is() )
        {
            try
            {
                xCtrlAccess->enableControl( _nExtendedControlId, _bEnable );
                bIsEnabled = _bEnable;
            }
            catch( const IllegalArgumentException& )
            {
                OSL_FAIL( "FileDialogHelper_Impl::updateExtendedControl: caught an exception!" );
            }
        }
        return bIsEnabled;
    }

    bool FileDialogHelper_Impl::CheckFilterOptionsCapability( const std::shared_ptr<const SfxFilter>& _pFilter )
    {
        bool bResult = false;

        if( mxFilterCFG.is() && _pFilter )
        {
            try {
                   Sequence < PropertyValue > aProps;
                   Any aAny = mxFilterCFG->getByName( _pFilter->GetName() );
                   if ( aAny >>= aProps )
                   {
                       OUString aServiceName;
                       sal_Int32 nPropertyCount = aProps.getLength();
                       for( sal_Int32 nProperty=0; nProperty < nPropertyCount; ++nProperty )
                    {
                           if( aProps[nProperty].Name == "UIComponent" )
                           {
                               aProps[nProperty].Value >>= aServiceName;
                            if( !aServiceName.isEmpty() )
                                bResult = true;
                        }
                    }
                }
            }
            catch( const Exception& )
            {
            }
        }

        return bResult;
    }

    bool FileDialogHelper_Impl::isInOpenMode() const
    {
        bool bRet = false;

        switch ( m_nDialogType )
        {
            case FILEOPEN_SIMPLE:
            case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE:
            case FILEOPEN_PLAY:
            case FILEOPEN_LINK_PLAY:
            case FILEOPEN_READONLY_VERSION:
            case FILEOPEN_LINK_PREVIEW:
            case FILEOPEN_PREVIEW:
                bRet = true;
        }

        return bRet;
    }

    void FileDialogHelper_Impl::updateFilterOptionsBox()
    {
        if ( !m_bHaveFilterOptions )
            return;

        updateExtendedControl(
            ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS,
            CheckFilterOptionsCapability( getCurentSfxFilter() )
        );
    }

    void FileDialogHelper_Impl::updateExportButton()
    {
        uno::Reference < XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY );
        if ( xCtrlAccess.is() )
        {
            OUString sOldLabel( xCtrlAccess->getLabel( CommonFilePickerElementIds::PUSHBUTTON_OK ) );

            // initialize button label; we need the label with the mnemonic char
            if ( maButtonLabel.isEmpty() || maButtonLabel.indexOf( MNEMONIC_CHAR ) == -1 )
            {
                // cut the ellipses, if necessary
                sal_Int32 nIndex = sOldLabel.indexOf( "..." );
                if ( -1 == nIndex )
                    nIndex = sOldLabel.getLength();
                maButtonLabel = sOldLabel.copy( 0, nIndex );
            }

            OUString sLabel = maButtonLabel;
            // filter with options -> append ellipses on export button label
            if ( CheckFilterOptionsCapability( getCurentSfxFilter() ) )
                sLabel += "...";

            if ( sOldLabel != sLabel )
            {
                try
                {
                    xCtrlAccess->setLabel( CommonFilePickerElementIds::PUSHBUTTON_OK, sLabel );
                }
                catch( const IllegalArgumentException& )
                {
                    SAL_WARN( "sfx.dialog", "FileDialogHelper_Impl::updateExportButton: caught an exception!" );
                }
            }
        }
    }

    void FileDialogHelper_Impl::updateSelectionBox()
    {
        if ( !mbHasSelectionBox )
            return;

        // Does the selection box exist?
        bool bSelectionBoxFound = false;
        uno::Reference< XControlInformation > xCtrlInfo( mxFileDlg, UNO_QUERY );
        if ( xCtrlInfo.is() )
        {
            Sequence< OUString > aCtrlList = xCtrlInfo->getSupportedControls();
            sal_uInt32 nCount = aCtrlList.getLength();
            for ( sal_uInt32 nCtrl = 0; nCtrl < nCount; ++nCtrl )
                if ( aCtrlList[ nCtrl ] == "SelectionBox" )
                {
                    bSelectionBoxFound = true;
                    break;
                }
        }

        if ( bSelectionBoxFound )
        {
            std::shared_ptr<const SfxFilter> pFilter = getCurentSfxFilter();
            mbSelectionFltrEnabled = updateExtendedControl(
                ExtendedFilePickerElementIds::CHECKBOX_SELECTION,
                ( mbSelectionEnabled && pFilter && ( pFilter->GetFilterFlags() & SfxFilterFlags::SUPPORTSSELECTION ) ) );
            uno::Reference< XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY );
            xCtrlAccess->setValue( ExtendedFilePickerElementIds::CHECKBOX_SELECTION, 0, makeAny( mbSelection ) );
        }
    }

    void FileDialogHelper_Impl::enablePasswordBox( bool bInit )
    {
        if ( ! mbHasPassword )
            return;

        bool bWasEnabled = mbIsPwdEnabled;

        std::shared_ptr<const SfxFilter> pCurrentFilter = getCurentSfxFilter();
        mbIsPwdEnabled = updateExtendedControl(
            ExtendedFilePickerElementIds::CHECKBOX_PASSWORD,
            pCurrentFilter && ( pCurrentFilter->GetFilterFlags() & SfxFilterFlags::ENCRYPTION )
        );

        if( bInit )
        {
            // in case of initialization previous state is not interesting
            if( mbIsPwdEnabled )
            {
                uno::Reference< XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY );
                if( mbPwdCheckBoxState )
                    xCtrlAccess->setValue( ExtendedFilePickerElementIds::CHECKBOX_PASSWORD, 0, makeAny( true ) );
            }
        }
        else if( !bWasEnabled && mbIsPwdEnabled )
        {
            uno::Reference< XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY );
            if( mbPwdCheckBoxState )
                xCtrlAccess->setValue( ExtendedFilePickerElementIds::CHECKBOX_PASSWORD, 0, makeAny( true ) );
        }
        else if( bWasEnabled && !mbIsPwdEnabled )
        {
            // remember user settings until checkbox is enabled
            uno::Reference< XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY );
            Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::CHECKBOX_PASSWORD, 0 );
            bool bPassWord = false;
            mbPwdCheckBoxState = ( aValue >>= bPassWord ) && bPassWord;
            xCtrlAccess->setValue( ExtendedFilePickerElementIds::CHECKBOX_PASSWORD, 0, makeAny( false ) );
        }
    }

    void FileDialogHelper_Impl::updatePreviewState( bool _bUpdatePreviewWindow )
    {
        if ( mbHasPreview )
        {
            uno::Reference< XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY );

            // check, whether or not we have to display a preview
            if ( xCtrlAccess.is() )
            {
                try
                {
                    Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, 0 );
                    bool bShowPreview = false;

                    if ( aValue >>= bShowPreview )
                    {
                        mbShowPreview = bShowPreview;

                        // setShowState has currently no effect for the
                        // OpenOffice FilePicker (see svtools/source/filepicker/iodlg.cxx)
                        uno::Reference< XFilePreview > xFilePreview( mxFileDlg, UNO_QUERY );
                        if ( xFilePreview.is() )
                            xFilePreview->setShowState( mbShowPreview );

                        if ( _bUpdatePreviewWindow )
                            TimeOutHdl_Impl( nullptr );
                    }
                }
                catch( const Exception& )
                {
                    SAL_WARN( "sfx.dialog", "FileDialogHelper_Impl::updatePreviewState: caught an exception!" );
                }
            }
        }
    }

    void FileDialogHelper_Impl::updateVersions()
    {
        Sequence < OUString > aEntries;
        Sequence < OUString > aPathSeq = mxFileDlg->getFiles();

        if ( aPathSeq.getLength() == 1 )
        {
            INetURLObject aObj( aPathSeq[0] );

            if ( ( aObj.GetProtocol() == INetProtocol::File ) &&
                ( utl::UCBContentHelper::IsDocument( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) ) )
            {
                try
                {
                    uno::Reference< embed::XStorage > xStorage = ::comphelper::OStorageHelper::GetStorageFromURL(
                                                                    aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
                                                                    embed::ElementModes::READ );

                    DBG_ASSERT( xStorage.is(), "The method must return the storage or throw an exception!" );
                    if ( !xStorage.is() )
                        throw uno::RuntimeException();

                    uno::Sequence < util::RevisionTag > xVersions = SfxMedium::GetVersionList( xStorage );

                    aEntries.realloc( xVersions.getLength() + 1 );
                    aEntries[0] = SfxResId( STR_SFX_FILEDLG_ACTUALVERSION );

                    for ( sal_Int32 i=0; i<xVersions.getLength(); i++ )
                        aEntries[ i + 1 ] = xVersions[i].Identifier;
                }
                catch( const uno::Exception& )
                {
                }
            }
        }

        uno::Reference < XFilePickerControlAccess > xDlg( mxFileDlg, UNO_QUERY );
        Any aValue;

        try
        {
            xDlg->setValue( ExtendedFilePickerElementIds::LISTBOX_VERSION,
                            ControlActions::DELETE_ITEMS, aValue );
        }
        catch( const IllegalArgumentException& ){}

        sal_Int32 nCount = aEntries.getLength();

        if ( nCount )
        {
            try
            {
                aValue <<= aEntries;
                xDlg->setValue( ExtendedFilePickerElementIds::LISTBOX_VERSION,
                                ControlActions::ADD_ITEMS, aValue );

                Any aPos;
                aPos <<= sal_Int32(0);
                xDlg->setValue( ExtendedFilePickerElementIds::LISTBOX_VERSION,
                                ControlActions::SET_SELECT_ITEM, aPos );
            }
            catch( const IllegalArgumentException& ){}
        }
    }

    IMPL_LINK_NOARG(FileDialogHelper_Impl, TimeOutHdl_Impl, Timer *, void)
    {
        if ( !mbHasPreview )
            return;

        maGraphic.Clear();

        Any aAny;
        uno::Reference < XFilePreview > xFilePicker( mxFileDlg, UNO_QUERY );

        if ( ! xFilePicker.is() )
            return;

        Sequence < OUString > aPathSeq = mxFileDlg->getFiles();

        if ( mbShowPreview && ( aPathSeq.getLength() == 1 ) )
        {
            OUString    aURL = aPathSeq[0];

            if ( ERRCODE_NONE == getGraphic( aURL, maGraphic ) )
            {
                // changed the code slightly;
                // before: the bitmap was scaled and
                // surrounded a white frame
                // now: the bitmap will only be scaled
                // and the filepicker implementation
                // is responsible for placing it at its
                // proper position and painting a frame

                BitmapEx aBmp = maGraphic.GetBitmapEx();
                if ( !aBmp.IsEmpty() )
                {
                    // scale the bitmap to the correct size
                    sal_Int32 nOutWidth  = xFilePicker->getAvailableWidth();
                    sal_Int32 nOutHeight = xFilePicker->getAvailableHeight();
                    sal_Int32 nBmpWidth  = aBmp.GetSizePixel().Width();
                    sal_Int32 nBmpHeight = aBmp.GetSizePixel().Height();

                    double nXRatio = static_cast<double>(nOutWidth) / nBmpWidth;
                    double nYRatio = static_cast<double>(nOutHeight) / nBmpHeight;

                    if ( nXRatio < nYRatio )
                        aBmp.Scale( nXRatio, nXRatio );
                    else
                        aBmp.Scale( nYRatio, nYRatio );

                    // Convert to true color, to allow CopyPixel
                    aBmp.Convert( BmpConversion::N24Bit );

                    // and copy it into the Any
                    SvMemoryStream aData;

                    WriteDIB(aBmp, aData, false);

                    const Sequence < sal_Int8 > aBuffer(
                        static_cast< const sal_Int8* >(aData.GetData()),
                        aData.GetEndOfData() );

                    aAny <<= aBuffer;
                }
            }
        }

        try
        {
            SolarMutexReleaser aReleaseForCallback;
            // clear the preview window
            xFilePicker->setImage( FilePreviewImageFormats::BITMAP, aAny );
        }
        catch( const IllegalArgumentException& )
        {
        }
    }

    ErrCode FileDialogHelper_Impl::getGraphic( const OUString& rURL,
                                               Graphic& rGraphic ) const
    {
        if ( utl::UCBContentHelper::IsFolder( rURL ) )
            return ERRCODE_IO_NOTAFILE;

        if ( !mpGraphicFilter )
            return ERRCODE_IO_NOTSUPPORTED;

        // select graphic filter from dialog filter selection
        OUString aCurFilter( getFilter() );

        sal_uInt16 nFilter = !aCurFilter.isEmpty() && mpGraphicFilter->GetImportFormatCount()
                        ? mpGraphicFilter->GetImportFormatNumber( aCurFilter )
                        : GRFILTER_FORMAT_DONTKNOW;

        INetURLObject aURLObj( rURL );

        if ( aURLObj.HasError() || INetProtocol::NotValid == aURLObj.GetProtocol() )
        {
            aURLObj.SetSmartProtocol( INetProtocol::File );
            aURLObj.SetSmartURL( rURL );
        }

        ErrCode nRet = ERRCODE_NONE;

        GraphicFilterImportFlags nFilterImportFlags = GraphicFilterImportFlags::SetLogsizeForJpeg;
        // non-local?
        if ( INetProtocol::File != aURLObj.GetProtocol() )
        {
            std::unique_ptr<SvStream> pStream = ::utl::UcbStreamHelper::CreateStream( rURL, StreamMode::READ );

            if( pStream )
                nRet = mpGraphicFilter->ImportGraphic( rGraphic, rURL, *pStream, nFilter, nullptr, nFilterImportFlags );
            else
                nRet = mpGraphicFilter->ImportGraphic( rGraphic, aURLObj, nFilter, nullptr, nFilterImportFlags );
        }
        else
        {
            nRet = mpGraphicFilter->ImportGraphic( rGraphic, aURLObj, nFilter, nullptr, nFilterImportFlags );
        }

        return nRet;
    }

    ErrCode FileDialogHelper_Impl::getGraphic( Graphic& rGraphic ) const
    {
        ErrCode nRet = ERRCODE_NONE;

        // rhbz#1079672 do not return maGraphic, it need not be the selected file

        OUString aPath;
        Sequence<OUString> aPathSeq = mxFileDlg->getFiles();

        if (aPathSeq.getLength() == 1)
        {
            aPath = aPathSeq[0];
        }

        if (!aPath.isEmpty())
            nRet = getGraphic(aPath, rGraphic);
        else
            nRet = ERRCODE_IO_GENERAL;

        return nRet;
    }

    static bool lcl_isSystemFilePicker( const uno::Reference< XFilePicker3 >& _rxFP )
    {
        try
        {
            uno::Reference< XServiceInfo > xSI( _rxFP, UNO_QUERY );
            if ( !xSI.is() )
                return true;
            return xSI->supportsService( "com.sun.star.ui.dialogs.SystemFilePicker" );
        }
        catch( const Exception& )
        {
        }
        return false;
    }

    enum open_or_save_t {OPEN, SAVE, UNDEFINED};
    static open_or_save_t lcl_OpenOrSave(sal_Int16 const nDialogType)
    {
        switch (nDialogType)
        {
            case FILEOPEN_SIMPLE:
            case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE:
            case FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR:
            case FILEOPEN_PLAY:
            case FILEOPEN_LINK_PLAY:
            case FILEOPEN_READONLY_VERSION:
            case FILEOPEN_LINK_PREVIEW:
            case FILEOPEN_PREVIEW:
                return OPEN;
            case FILESAVE_SIMPLE:
            case FILESAVE_AUTOEXTENSION_PASSWORD:
            case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS:
            case FILESAVE_AUTOEXTENSION_SELECTION:
            case FILESAVE_AUTOEXTENSION_TEMPLATE:
            case FILESAVE_AUTOEXTENSION:
                return SAVE;
            default:
                assert(false); // invalid dialog type
        }
        return UNDEFINED;
    }

    // FileDialogHelper_Impl

    css::uno::Reference<css::awt::XWindow> FileDialogHelper_Impl::GetFrameInterface()
    {
        if (mpFrameWeld)
            return mpFrameWeld->GetXWindow();
        return css::uno::Reference<css::awt::XWindow>();
    }

    FileDialogHelper_Impl::FileDialogHelper_Impl(
        FileDialogHelper* _pAntiImpl,
        sal_Int16 nDialogType,
        FileDialogFlags nFlags,
        sal_Int16 nDialog,
        weld::Window* pFrameWeld,
        const OUString& sStandardDir,
        const css::uno::Sequence< OUString >& rBlackList
        )
        :m_nDialogType          ( nDialogType )
        ,meContext              ( FileDialogHelper::UNKNOWN_CONTEXT )
    {
        const char* pServiceName=nullptr;
        switch (nDialog)
        {
            case SFX2_IMPL_DIALOG_SYSTEM:
            case SFX2_IMPL_DIALOG_OOO:
                pServiceName = "com.sun.star.ui.dialogs.OfficeFilePicker";
                break;
            case SFX2_IMPL_DIALOG_REMOTE:
                pServiceName = "com.sun.star.ui.dialogs.RemoteFilePicker";
                break;
            default:
                pServiceName = "com.sun.star.ui.dialogs.FilePicker";
                break;
        }

        OUString aService = OUString::createFromAscii( pServiceName );

        uno::Reference< XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );

        // create the file open dialog
        // the flags can be SFXWB_INSERT or SFXWB_MULTISELECTION

        mpFrameWeld             = pFrameWeld;
        mpAntiImpl              = _pAntiImpl;
        mbHasAutoExt            = false;
        mbHasPassword           = false;
        m_bHaveFilterOptions    = false;
        mbIsPwdEnabled          = true;
        mbIsGpgEnabled          = true;
        mbHasVersions           = false;
        mbHasPreview            = false;
        mbShowPreview           = false;
        mbDeleteMatcher         = false;
        mbInsert                = bool(nFlags & (FileDialogFlags::Insert|
                                                 FileDialogFlags::InsertCompare|
                                                 FileDialogFlags::InsertMerge));
        mbExport                = bool(nFlags & FileDialogFlags::Export);
        mbIsSaveDlg             = false;
        mbPwdCheckBoxState      = false;
        mbSelection             = false;
        mbSelectionEnabled      = true;
        mbHasSelectionBox       = false;
        mbSelectionFltrEnabled  = false;

        // default settings
        m_nDontFlags = SFX_FILTER_NOTINSTALLED | SfxFilterFlags::INTERNAL | SfxFilterFlags::NOTINFILEDLG;
        if (OPEN == lcl_OpenOrSave(m_nDialogType))
            m_nMustFlags = SfxFilterFlags::IMPORT;
        else
            m_nMustFlags = SfxFilterFlags::EXPORT;

        mpMatcher = nullptr;
        mpGraphicFilter = nullptr;
        mnPostUserEventId = nullptr;

        // create the picker component
        mxFileDlg.set(xFactory->createInstance( aService ), css::uno::UNO_QUERY);
        mbSystemPicker = lcl_isSystemFilePicker( mxFileDlg );

        uno::Reference< XFilePickerNotifier > xNotifier( mxFileDlg, UNO_QUERY );
        uno::Reference< XInitialization > xInit( mxFileDlg, UNO_QUERY );

        if ( ! mxFileDlg.is() || ! xNotifier.is() )
        {
            return;
        }

        if ( xInit.is() )
        {
            sal_Int16 nTemplateDescription = TemplateDescription::FILEOPEN_SIMPLE;

            switch ( m_nDialogType )
            {
                case FILEOPEN_SIMPLE:
                    nTemplateDescription = TemplateDescription::FILEOPEN_SIMPLE;
                    break;

                case FILESAVE_SIMPLE:
                    nTemplateDescription = TemplateDescription::FILESAVE_SIMPLE;
                    mbIsSaveDlg = true;
                    break;

                case FILESAVE_AUTOEXTENSION_PASSWORD:
                    nTemplateDescription = TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD;
                    mbHasPassword = true;
                    mbHasAutoExt = true;
                    mbIsSaveDlg = true;
                    break;

                case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS:
                    nTemplateDescription = TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS;
                    mbHasPassword = true;

                    m_bHaveFilterOptions = true;
                    if( xFactory.is() )
                    {
                        mxFilterCFG.set(
                            xFactory->createInstance( "com.sun.star.document.FilterFactory" ),
                            UNO_QUERY );
                    }

                    mbHasAutoExt = true;
                    mbIsSaveDlg = true;
                    break;

                case FILESAVE_AUTOEXTENSION_SELECTION:
                    nTemplateDescription = TemplateDescription::FILESAVE_AUTOEXTENSION_SELECTION;
                    mbHasAutoExt = true;
                    mbIsSaveDlg = true;
                    mbHasSelectionBox = true;
                    if ( mbExport && !mxFilterCFG.is() && xFactory.is() )
                    {
                        mxFilterCFG.set(
                            xFactory->createInstance( "com.sun.star.document.FilterFactory" ),
                            UNO_QUERY );
                    }
                    break;

                case FILESAVE_AUTOEXTENSION_TEMPLATE:
                    nTemplateDescription = TemplateDescription::FILESAVE_AUTOEXTENSION_TEMPLATE;
                    mbHasAutoExt = true;
                    mbIsSaveDlg = true;
                    break;

                case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE:
                    nTemplateDescription = TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE;
                    mbHasPreview = true;
                    break;

                case FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR:
                    nTemplateDescription = TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR;
                    mbHasPreview = true;
                    break;

                case FILEOPEN_PLAY:
                    nTemplateDescription = TemplateDescription::FILEOPEN_PLAY;
                    break;

                case FILEOPEN_LINK_PLAY:
                    nTemplateDescription = TemplateDescription::FILEOPEN_LINK_PLAY;
                    break;

                case FILEOPEN_READONLY_VERSION:
                    nTemplateDescription = TemplateDescription::FILEOPEN_READONLY_VERSION;
                    mbHasVersions = true;
                    break;

                case FILEOPEN_LINK_PREVIEW:
                    nTemplateDescription = TemplateDescription::FILEOPEN_LINK_PREVIEW;
                    mbHasPreview = true;
                    break;

                case FILESAVE_AUTOEXTENSION:
                    nTemplateDescription = TemplateDescription::FILESAVE_AUTOEXTENSION;
                    mbHasAutoExt = true;
                    mbIsSaveDlg = true;
                    break;

                case FILEOPEN_PREVIEW:
                    nTemplateDescription = TemplateDescription::FILEOPEN_PREVIEW;
                    mbHasPreview = true;
                    break;

                default:
                    SAL_WARN( "sfx.dialog", "FileDialogHelper::ctor with unknown type" );
                    break;
            }

            if (mbHasPreview)
            {
                maPreviewIdle.SetPriority( TaskPriority::LOWEST );
                maPreviewIdle.SetInvokeHandler( LINK( this, FileDialogHelper_Impl, TimeOutHdl_Impl ) );
            }

            auto xWindow = GetFrameInterface();

            Sequence < Any > aInitArguments(!xWindow.is() ? 3 : 4);

            // This is a hack. We currently know that the internal file picker implementation
            // supports the extended arguments as specified below.
            // TODO:
            // a) adjust the service description so that it includes the TemplateDescription and ParentWindow args
            // b) adjust the implementation of the system file picker to that it recognizes it
            if ( mbSystemPicker )
            {
                aInitArguments[0] <<= nTemplateDescription;
                if (xWindow.is())
                    aInitArguments[1] <<= xWindow;
            }
            else
            {
                aInitArguments[0] <<= NamedValue(
                                        "TemplateDescription",
                                        makeAny( nTemplateDescription )
                                    );

                aInitArguments[1] <<= NamedValue(
                                        "StandardDir",
                                        makeAny( sStandardDir )
                                    );

                aInitArguments[2] <<= NamedValue(
                                        "BlackList",
                                        makeAny( rBlackList )
                                    );

                if (xWindow.is())
                    aInitArguments[3] <<= NamedValue("ParentWindow", makeAny(xWindow));
            }

            try
            {
                xInit->initialize( aInitArguments );
            }
            catch( const Exception& )
            {
                OSL_FAIL( "FileDialogHelper_Impl::FileDialogHelper_Impl: could not initialize the picker!" );
            }
        }

        // set multiselection mode
        if ( nFlags & FileDialogFlags::MultiSelection )
            mxFileDlg->setMultiSelectionMode( true );

        if ( nFlags & FileDialogFlags::Graphic ) // generate graphic filter only on demand
        {
            addGraphicFilter();
        }

        // Export dialog
        if ( mbExport )
        {
            mxFileDlg->setTitle( SfxResId( STR_SFX_EXPLORERFILE_EXPORT ) );
            try {
                    css::uno::Reference < XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY_THROW );
                    xCtrlAccess->enableControl( ExtendedFilePickerElementIds::LISTBOX_FILTER_SELECTOR, true );
            }
            catch( const Exception & ) { }
        }

        // Save a copy dialog
        if ( nFlags & FileDialogFlags::SaveACopy )
        {
            mxFileDlg->setTitle( SfxResId( STR_PB_SAVEACOPY ) );
        }

        // the "insert file" dialog needs another title
        if ( mbInsert )
        {
            if ( nFlags & FileDialogFlags::InsertCompare )
            {
                mxFileDlg->setTitle( SfxResId( STR_PB_COMPAREDOC ) );
            }
            else if ( nFlags & FileDialogFlags::InsertMerge )
            {
                mxFileDlg->setTitle( SfxResId( STR_PB_MERGEDOC ) );
            }
            else
            {
                mxFileDlg->setTitle( SfxResId( STR_SFX_EXPLORERFILE_INSERT ) );
            }
            uno::Reference < XFilePickerControlAccess > xExtDlg( mxFileDlg, UNO_QUERY );
            if ( xExtDlg.is() )
            {
                try
                {
                    xExtDlg->setLabel( CommonFilePickerElementIds::PUSHBUTTON_OK,
                                       SfxResId( STR_SFX_EXPLORERFILE_BUTTONINSERT ) );
                }
                catch( const IllegalArgumentException& ){}
            }
        }

        // add the event listener
        xNotifier->addFilePickerListener( this );
    }

    FileDialogHelper_Impl::~FileDialogHelper_Impl()
    {
        // Remove user event if we haven't received it yet
        if ( mnPostUserEventId )
            Application::RemoveUserEvent( mnPostUserEventId );
        mnPostUserEventId = nullptr;

        mpGraphicFilter.reset();

        if ( mbDeleteMatcher )
            delete mpMatcher;

        maPreviewIdle.ClearInvokeHandler();

        ::comphelper::disposeComponent( mxFileDlg );
    }

    void FileDialogHelper_Impl::setControlHelpIds( const sal_Int16* _pControlId, const char** _pHelpId )
    {
        DBG_ASSERT( _pControlId && _pHelpId, "FileDialogHelper_Impl::setControlHelpIds: invalid array pointers!" );
        if ( !_pControlId || !_pHelpId )
            return;

        // forward these ids to the file picker
        try
        {
            const OUString sHelpIdPrefix( INET_HID_SCHEME  );
            // the ids for the single controls
            uno::Reference< XFilePickerControlAccess > xControlAccess( mxFileDlg, UNO_QUERY );
            if ( xControlAccess.is() )
            {
                while ( *_pControlId )
                {
                    DBG_ASSERT( INetURLObject( OStringToOUString( *_pHelpId, RTL_TEXTENCODING_UTF8 ) ).GetProtocol() == INetProtocol::NotValid, "Wrong HelpId!" );
                    OUString sId( sHelpIdPrefix );
                    sId += OUString( *_pHelpId, strlen( *_pHelpId ), RTL_TEXTENCODING_UTF8 );
                    xControlAccess->setValue( *_pControlId, ControlActions::SET_HELP_URL, makeAny( sId ) );

                    ++_pControlId; ++_pHelpId;
                }
            }
        }
        catch( const Exception& )
        {
            OSL_FAIL( "FileDialogHelper_Impl::setControlHelpIds: caught an exception while setting the help ids!" );
        }
    }

    IMPL_LINK_NOARG( FileDialogHelper_Impl, InitControls, void*, void )
    {
        mnPostUserEventId = nullptr;
        enablePasswordBox( true );
        updateFilterOptionsBox( );
        updateSelectionBox( );
    }

    void FileDialogHelper_Impl::preExecute()
    {
        loadConfig( );
        setDefaultValues( );
        updatePreviewState( false );

        implInitializeFileName( );

    #if !(defined(MACOSX) && defined(MACOSX)) && !defined(_WIN32)
        // allow for dialog implementations which need to be executed before they return valid values for
        // current filter and such

        // On Vista (at least SP1) it's the same as on MacOSX, the modal dialog won't let message pass
        // through before it returns from execution
        mnPostUserEventId = Application::PostUserEvent( LINK( this, FileDialogHelper_Impl, InitControls ) );
    #else
        // However, the Mac OS X implementation's pickers run modally in execute and so the event doesn't
        // get through in time... so we call the methods directly
        enablePasswordBox( true );
        updateFilterOptionsBox( );
        updateSelectionBox( );
    #endif
    }

    void FileDialogHelper_Impl::postExecute( sal_Int16 _nResult )
    {
        if ( ExecutableDialogResults::CANCEL != _nResult )
            saveConfig();
    }

    void FileDialogHelper_Impl::implInitializeFileName( )
    {
        if ( !maFileName.isEmpty() )
        {
            INetURLObject aObj( maPath );
            aObj.Append( maFileName );

            // in case we're operating as save dialog, and "auto extension" is checked,
            // cut the extension from the name
            if ( mbIsSaveDlg && mbHasAutoExt )
            {
                try
                {
                    bool bAutoExtChecked = false;

                    uno::Reference < XFilePickerControlAccess > xControlAccess( mxFileDlg, UNO_QUERY );
                    if  (   xControlAccess.is()
                        &&  (   xControlAccess->getValue( ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, 0 )
                            >>= bAutoExtChecked
                            )
                        )
                    {
                        if ( bAutoExtChecked )
                        {   // cut the extension
                            aObj.removeExtension( );
                            mxFileDlg->setDefaultName( aObj.GetName( INetURLObject::DecodeMechanism::WithCharset ) );
                        }
                    }
                }
                catch( const Exception& )
                {
                    OSL_FAIL( "FileDialogHelper_Impl::implInitializeFileName: could not ask for the auto-extension current-value!" );
                }
            }
        }
    }

    sal_Int16 FileDialogHelper_Impl::implDoExecute()
    {
        preExecute();

        sal_Int16 nRet = ExecutableDialogResults::CANCEL;

    //On MacOSX the native file picker has to run in the primordial thread because of drawing issues
    //On Linux the native gtk file picker, when backed by gnome-vfs2, needs to be run in the same
    //primordial thread as the ucb gnome-vfs2 provider was initialized in.

        {
            try
            {
    #ifdef _WIN32
                if ( mbSystemPicker )
                {
                    SolarMutexReleaser aSolarMutex;
                    nRet = mxFileDlg->execute();
                }
                else
    #endif
                nRet = mxFileDlg->execute();
            }
            catch( const Exception& )
            {
                SAL_WARN( "sfx.dialog", "FileDialogHelper_Impl::implDoExecute: caught an exception!" );
            }
        }

        postExecute( nRet );

        return nRet;
    }

    void FileDialogHelper_Impl::implStartExecute()
    {
        DBG_ASSERT( mxFileDlg.is(), "invalid file dialog" );

        preExecute();

        if ( mbSystemPicker )
        {
        }
        else
        {
            try
            {
                uno::Reference< XAsynchronousExecutableDialog > xAsyncDlg( mxFileDlg, UNO_QUERY );
                if ( xAsyncDlg.is() )
                    xAsyncDlg->startExecuteModal( this );
            }
            catch( const Exception& )
            {
                SAL_WARN( "sfx.dialog", "FileDialogHelper_Impl::implDoExecute: caught an exception!" );
            }
        }
    }

    void lcl_saveLastURLs(std::vector<OUString>& rpURLList,
                          ::std::vector< OUString >& lLastURLs )
    {
        lLastURLs.clear();
        for (auto const& url : rpURLList)
            lLastURLs.push_back(url);
    }

    void FileDialogHelper_Impl::implGetAndCacheFiles(const uno::Reference< XInterface >& xPicker, std::vector<OUString>& rpURLList, const std::shared_ptr<const SfxFilter>& pFilter)
    {
        rpURLList.clear();

        OUString sExtension;
        if (pFilter)
        {
            sExtension = pFilter->GetDefaultExtension ();
            sExtension = sExtension.replaceAll("*", "").replaceAll(".", "");
        }

        // a) the new way (optional!)
        uno::Reference< XFilePicker3 > xPickNew(xPicker, UNO_QUERY);
        if (xPickNew.is())
        {
            Sequence< OUString > lFiles    = xPickNew->getSelectedFiles();
            ::sal_Int32          nFiles    = lFiles.getLength();
            for(sal_Int32 i = 0; i < nFiles; ++i)
                rpURLList.push_back(lFiles[i]);
        }

        // b) the olde way ... non optional.
        else
        {
            uno::Reference< XFilePicker3 > xPickOld(xPicker, UNO_QUERY_THROW);
            Sequence< OUString > lFiles = xPickOld->getFiles();
            ::sal_Int32          nFiles = lFiles.getLength();
            if ( nFiles == 1 )
            {
                rpURLList.push_back(lFiles[0]);
            }
            else if ( nFiles > 1 )
            {
                INetURLObject aPath( lFiles[0] );
                aPath.setFinalSlash();

                for (::sal_Int32 i = 1; i < nFiles; i++)
                {
                    if (i == 1)
                        aPath.Append( lFiles[i] );
                    else
                        aPath.setName( lFiles[i] );

                    rpURLList.push_back(aPath.GetMainURL(INetURLObject::DecodeMechanism::NONE));
                }
            }
        }

        lcl_saveLastURLs(rpURLList, mlLastURLs);
    }

    ErrCode FileDialogHelper_Impl::execute( std::vector<OUString>& rpURLList,
                                            SfxItemSet *&   rpSet,
                                            OUString&       rFilter )
    {
        // rFilter is a pure output parameter, it shouldn't be used for anything else
        // changing this would surely break code
        // rpSet is in/out parameter, usually just a media-descriptor that can be changed by dialog

        uno::Reference< XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY );

        // retrieves parameters from rpSet
        // for now only Password is used
        if ( rpSet )
        {
            // check password checkbox if the document had password before
            if( mbHasPassword )
            {
                const SfxBoolItem* pPassItem = SfxItemSet::GetItem<SfxBoolItem>(rpSet, SID_PASSWORDINTERACTION, false);
                mbPwdCheckBoxState = ( pPassItem != nullptr && pPassItem->GetValue() );

                // in case the document has password to modify, the dialog should be shown
                const SfxUnoAnyItem* pPassToModifyItem = SfxItemSet::GetItem<SfxUnoAnyItem>(rpSet, SID_MODIFYPASSWORDINFO, false);
                mbPwdCheckBoxState |= ( pPassToModifyItem && pPassToModifyItem->GetValue().hasValue() );
            }

            const SfxBoolItem* pSelectItem = SfxItemSet::GetItem<SfxBoolItem>(rpSet, SID_SELECTION, false);
            if ( pSelectItem )
                mbSelection = pSelectItem->GetValue();
            else
                mbSelectionEnabled = false;

            // the password will be set in case user decide so
            rpSet->ClearItem( SID_PASSWORDINTERACTION );
            rpSet->ClearItem( SID_PASSWORD );
            rpSet->ClearItem( SID_ENCRYPTIONDATA );
            rpSet->ClearItem( SID_RECOMMENDREADONLY );
            rpSet->ClearItem( SID_MODIFYPASSWORDINFO );

        }

        if ( mbHasPassword && !mbPwdCheckBoxState )
        {
            SvtSecurityOptions aSecOpt;
            mbPwdCheckBoxState = (
                aSecOpt.IsOptionSet( SvtSecurityOptions::EOption::DocWarnRecommendPassword ) );
        }

        rpURLList.clear();

        if ( ! mxFileDlg.is() )
            return ERRCODE_ABORT;

        if ( ExecutableDialogResults::CANCEL != implDoExecute() )
        {
            // create an itemset if there is no
            if( !rpSet )
                rpSet = new SfxAllItemSet( SfxGetpApp()->GetPool() );

            // the item should remain only if it was set by the dialog
            rpSet->ClearItem( SID_SELECTION );

            if( mbExport && mbHasSelectionBox )
            {
                try
                {
                    Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::CHECKBOX_SELECTION, 0 );
                    bool bSelection = false;
                    if ( aValue >>= bSelection )
                        rpSet->Put( SfxBoolItem( SID_SELECTION, bSelection ) );
                }
                catch( const IllegalArgumentException& )
                {
                    OSL_FAIL( "FileDialogHelper_Impl::execute: caught an IllegalArgumentException!" );
                }
            }

            // set the read-only flag. When inserting a file, this flag is always set
            if ( mbInsert )
                rpSet->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
            else
            {
                if ( ( FILEOPEN_READONLY_VERSION == m_nDialogType ) && xCtrlAccess.is() )
                {
                    try
                    {
                        Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::CHECKBOX_READONLY, 0 );
                        bool bReadOnly = false;
                        if ( ( aValue >>= bReadOnly ) && bReadOnly )
                            rpSet->Put( SfxBoolItem( SID_DOC_READONLY, bReadOnly ) );
                    }
                    catch( const IllegalArgumentException& )
                    {
                        OSL_FAIL( "FileDialogHelper_Impl::execute: caught an IllegalArgumentException!" );
                    }
                }
            }
            if ( mbHasVersions && xCtrlAccess.is() )
            {
                try
                {
                    Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::LISTBOX_VERSION,
                                                        ControlActions::GET_SELECTED_ITEM_INDEX );
                    sal_Int32 nVersion = 0;
                    if ( ( aValue >>= nVersion ) && nVersion > 0 )
                        // open a special version; 0 == current version
                        rpSet->Put( SfxInt16Item( SID_VERSION, static_cast<short>(nVersion) ) );
                }
                catch( const IllegalArgumentException& ){}
            }

            // set the filter
            getRealFilter( rFilter );

            std::shared_ptr<const SfxFilter> pCurrentFilter = getCurentSfxFilter();

            // fill the rpURLList
            implGetAndCacheFiles( mxFileDlg, rpURLList, pCurrentFilter );
            if ( rpURLList.empty() )
                return ERRCODE_ABORT;

            // check, whether or not we have to display a password box
            if ( pCurrentFilter && mbHasPassword && mbIsPwdEnabled && xCtrlAccess.is() )
            {
                try
                {
                    Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::CHECKBOX_PASSWORD, 0 );
                    bool bPassWord = false;
                    if ( ( aValue >>= bPassWord ) && bPassWord )
                    {
                        // ask for a password
                        OUString aDocName(rpURLList[0]);
                        ErrCode errCode = RequestPassword(pCurrentFilter, aDocName, rpSet, GetFrameInterface());
                        if (errCode != ERRCODE_NONE)
                            return errCode;
                    }
                }
                catch( const IllegalArgumentException& ){}
            }
            // check, whether or not we have to display a key selection box
            if ( pCurrentFilter && mbHasPassword && mbIsGpgEnabled && xCtrlAccess.is() )
            {
                try
                {
                    Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::CHECKBOX_GPGENCRYPTION, 0 );
                    bool bGpg = false;
                    if ( ( aValue >>= bGpg ) && bGpg )
                    {
                        uno::Sequence< beans::NamedValue > aEncryptionData;
                        while(true)
                        {
                            try
                            {
                                // ask for keys
                                aEncryptionData = ::comphelper::OStorageHelper::CreateGpgPackageEncryptionData();
                                break; // user cancelled or we've some keys now
                            }
                            catch( const IllegalArgumentException& )
                            {
                                std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(mpFrameWeld,
                                                                                         VclMessageType::Warning, VclButtonsType::Ok,
                                                                                         SfxResId(RID_SVXSTR_GPG_ENCRYPT_FAILURE)));
                                xBox->run();
                            }
                        }

                        if ( aEncryptionData.hasElements() )
                            rpSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData) ) );
                    }
                }
                catch( const IllegalArgumentException& ){}
            }

            SaveLastUsedFilter();
            return ERRCODE_NONE;
        }
        else
            return ERRCODE_ABORT;
    }

    ErrCode FileDialogHelper_Impl::execute()
    {
        if ( ! mxFileDlg.is() )
            return ERRCODE_ABORT;

        sal_Int16 nRet = implDoExecute();

        maPath = mxFileDlg->getDisplayDirectory();

        if ( ExecutableDialogResults::CANCEL == nRet )
            return ERRCODE_ABORT;
        else
        {
            return ERRCODE_NONE;
        }
    }

    OUString FileDialogHelper_Impl::getPath() const
    {
        OUString aPath;

        if ( mxFileDlg.is() )
            aPath = mxFileDlg->getDisplayDirectory();

        if ( aPath.isEmpty() )
            aPath = maPath;

        return aPath;
    }

    OUString FileDialogHelper_Impl::getFilter() const
    {
        OUString aFilter = getCurrentFilterUIName();

        if( aFilter.isEmpty() )
            aFilter = maCurFilter;

        return aFilter;
    }

    void FileDialogHelper_Impl::getRealFilter( OUString& _rFilter ) const
    {
        _rFilter = getCurrentFilterUIName();

        if ( _rFilter.isEmpty() )
            _rFilter = maCurFilter;

        if ( !_rFilter.isEmpty() && mpMatcher )
        {
            std::shared_ptr<const SfxFilter> pFilter =
                mpMatcher->GetFilter4UIName( _rFilter, m_nMustFlags, m_nDontFlags );
            _rFilter = pFilter ? pFilter->GetFilterName() : OUString();
        }
    }

    void FileDialogHelper_Impl::verifyPath()
    {
    #ifdef UNX
        // lp#905355, fdo#43895
        // Check that the file has read only permission and is in /tmp -- this is
        //  the case if we have opened the file from the web with firefox only.
        if (maFileName.isEmpty()) {
            return;
        }
        INetURLObject url(maPath);
        if (url.GetProtocol() != INetProtocol::File
            || url.getName(0, true, INetURLObject::DecodeMechanism::WithCharset) != "tmp")
        {
            return;
        }
        if (maFileName.indexOf('/') != -1) {
            SAL_WARN("sfx.dialog", maFileName << " contains /");
            return;
        }
        url.insertName(
            maFileName, false, INetURLObject::LAST_SEGMENT,
            INetURLObject::EncodeMechanism::All);
        OUString sysPathU;
        osl::FileBase::RC e = osl::FileBase::getSystemPathFromFileURL(
            url.GetMainURL(INetURLObject::DecodeMechanism::NONE), sysPathU);
        if (e != osl::FileBase::E_None) {
            SAL_WARN(
                "sfx.dialog",
                "getSystemPathFromFileURL("
                    << url.GetMainURL(INetURLObject::DecodeMechanism::NONE) << ") failed with "
                    << +e);
            return;
        }
        OString sysPathC;
        if (!sysPathU.convertToString(
                &sysPathC, osl_getThreadTextEncoding(),
                (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
                 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
        {
            SAL_WARN(
                "sfx.dialog",
                "convertToString(" << sysPathU << ") failed for encoding "
                    << +osl_getThreadTextEncoding());
            return;
        }
        struct stat aFileStat;
        if (stat(sysPathC.getStr(), &aFileStat) == -1) {
            SAL_WARN( "sfx.dialog", "stat(" << sysPathC << ") failed with errno " << errno);
            return;
        }
        if ((aFileStat.st_mode & (S_IRWXO | S_IRWXG | S_IRWXU)) == S_IRUSR) {
            maPath = SvtPathOptions().GetWorkPath();
            mxFileDlg->setDisplayDirectory( maPath );
        }
    #else
        (void) this;
    #endif
    }

    void FileDialogHelper_Impl::displayFolder( const OUString& _rPath )
    {
        if ( _rPath.isEmpty() )
            // nothing to do
            return;

        maPath = _rPath;
        if ( mxFileDlg.is() )
        {
            try
            {
                mxFileDlg->setDisplayDirectory( maPath );
                verifyPath();
            }
            catch( const IllegalArgumentException& )
            {
                OSL_FAIL( "FileDialogHelper_Impl::displayFolder: caught an exception!" );
            }
        }
    }

    void FileDialogHelper_Impl::setFileName( const OUString& _rFile )
    {
        maFileName = _rFile;
        if ( mxFileDlg.is() )
        {
            try
            {
                mxFileDlg->setDefaultName( maFileName );
                verifyPath();
            }
            catch( const IllegalArgumentException& )
            {
                OSL_FAIL( "FileDialogHelper_Impl::setFileName: caught an exception!" );
            }
        }
    }

    void FileDialogHelper_Impl::setFilter( const OUString& rFilter )
    {
        DBG_ASSERT( rFilter.indexOf(':') == -1, "Old filter name used!");

        maCurFilter = rFilter;

        if ( !rFilter.isEmpty() && mpMatcher )
        {
            std::shared_ptr<const SfxFilter> pFilter = mpMatcher->GetFilter4FilterName(
                                            rFilter, m_nMustFlags, m_nDontFlags );
            if ( pFilter )
                maCurFilter = pFilter->GetUIName();
        }

        uno::Reference< XFilterManager > xFltMgr( mxFileDlg, UNO_QUERY );

        if ( !maCurFilter.isEmpty() && xFltMgr.is() )
        {
            try
            {
                xFltMgr->setCurrentFilter( maCurFilter );
            }
            catch( const IllegalArgumentException& ){}
        }
    }

    void FileDialogHelper_Impl::createMatcher( const OUString& rFactory )
    {
        if (mbDeleteMatcher)
            delete mpMatcher;

        mpMatcher = new SfxFilterMatcher( SfxObjectShell::GetServiceNameFromFactory(rFactory) );
        mbDeleteMatcher = true;
    }

    void FileDialogHelper_Impl::addFilters( const OUString& rFactory,
                                            SfxFilterFlags nMust,
                                            SfxFilterFlags nDont )
    {
        uno::Reference< XFilterManager > xFltMgr( mxFileDlg, UNO_QUERY );

        if ( ! xFltMgr.is() )
            return;

        if (mbDeleteMatcher)
            delete mpMatcher;

        // we still need a matcher to convert UI names to filter names
        if ( rFactory.isEmpty() )
        {
            SfxApplication *pSfxApp = SfxGetpApp();
            mpMatcher = &pSfxApp->GetFilterMatcher();
            mbDeleteMatcher = false;
        }
        else
        {
            mpMatcher = new SfxFilterMatcher( rFactory );
            mbDeleteMatcher = true;
        }

        uno::Reference< XMultiServiceFactory > xSMGR = ::comphelper::getProcessServiceFactory();
        uno::Reference< XContainerQuery > xFilterCont(
            xSMGR->createInstance("com.sun.star.document.FilterFactory"),
            UNO_QUERY);
        if ( ! xFilterCont.is() )
            return;

        m_nMustFlags |= nMust;
        m_nDontFlags |= nDont;

        // create the list of filters
        OUStringBuffer sQuery(256);
        sQuery.append("getSortedFilterList()");
        sQuery.append(":module=");
        sQuery.append(rFactory); // use long name here !
        sQuery.append(":iflags=");
        sQuery.append(OUString::number(static_cast<sal_Int32>(m_nMustFlags)));
        sQuery.append(":eflags=");
        sQuery.append(OUString::number(static_cast<sal_Int32>(m_nDontFlags)));

        uno::Reference< XEnumeration > xResult;
        try
        {
            xResult = xFilterCont->createSubSetEnumerationByQuery(sQuery.makeStringAndClear());
        }
        catch( const uno::Exception& )
        {
            SAL_WARN( "sfx.dialog", "Could not get filters from the configuration!" );
        }

        TSortedFilterList         aIter   (xResult);

        // append the filters
        OUString sFirstFilter;
        if (OPEN == lcl_OpenOrSave(m_nDialogType))
            ::sfx2::appendFiltersForOpen( aIter, xFltMgr, sFirstFilter, *this );
        else if ( mbExport )
            ::sfx2::appendExportFilters( aIter, xFltMgr, sFirstFilter, *this );
        else
            ::sfx2::appendFiltersForSave( aIter, xFltMgr, sFirstFilter, *this, rFactory );

        // set our initial selected filter (if we do not already have one)
        if ( maSelectFilter.isEmpty() )
            maSelectFilter = sFirstFilter;
    }

    void FileDialogHelper_Impl::addFilter( const OUString& rFilterName,
                                           const OUString& rExtension )
    {
        uno::Reference< XFilterManager > xFltMgr( mxFileDlg, UNO_QUERY );

        if ( ! xFltMgr.is() )
            return;

        try
        {
            xFltMgr->appendFilter( rFilterName, rExtension );

            if ( maSelectFilter.isEmpty() )
                maSelectFilter = rFilterName;
        }
        catch( const IllegalArgumentException& )
        {
            SAL_WARN( "sfx.dialog", "Could not append Filter" << rFilterName );
        }
    }

    void FileDialogHelper_Impl::addGraphicFilter()
    {
        uno::Reference< XFilterManager > xFltMgr( mxFileDlg, UNO_QUERY );

        if ( ! xFltMgr.is() )
            return;

        // create the list of filters
        mpGraphicFilter.reset( new GraphicFilter );
        sal_uInt16 i, j, nCount = mpGraphicFilter->GetImportFormatCount();

        // compute the extension string for all known import filters
        OUString aExtensions;

        for ( i = 0; i < nCount; i++ )
        {
            j = 0;
            while( true )
            {
                OUString sWildcard = mpGraphicFilter->GetImportWildcard( i, j++ );
                if ( sWildcard.isEmpty() )
                    break;
                if ( aExtensions.indexOf( sWildcard ) == -1 )
                {
                    if ( !aExtensions.isEmpty() )
                        aExtensions += ";";
                    aExtensions += sWildcard;
                }
            }
        }

    #if defined(_WIN32)
        if ( aExtensions.getLength() > 240 )
            aExtensions = FILEDIALOG_FILTER_ALL;
    #endif
        bool bIsInOpenMode = isInOpenMode();

        try
        {
            OUString aAllFilterName = SfxResId( STR_SFX_IMPORT_ALL );
            aAllFilterName = ::sfx2::addExtension( aAllFilterName, aExtensions, bIsInOpenMode, *this );

            xFltMgr->appendFilter( aAllFilterName, aExtensions );
            maSelectFilter = aAllFilterName;
        }
        catch( const IllegalArgumentException& )
        {
            SAL_WARN( "sfx.dialog", "Could not append Filter" );
        }

        // Now add the filter
        for ( i = 0; i < nCount; i++ )
        {
            OUString aName = mpGraphicFilter->GetImportFormatName( i );
            OUString aExt;
            j = 0;
            while( true )
            {
                OUString sWildcard = mpGraphicFilter->GetImportWildcard( i, j++ );
                if ( sWildcard.isEmpty() )
                    break;
                if ( aExt.indexOf( sWildcard ) == -1 )
                {
                    if ( !aExt.isEmpty() )
                        aExt += ";";
                    aExt += sWildcard;
                }
            }
            aName = ::sfx2::addExtension( aName, aExt, bIsInOpenMode, *this );
            try
            {
                xFltMgr->appendFilter( aName, aExt );
            }
            catch( const IllegalArgumentException& )
            {
                SAL_WARN( "sfx.dialog", "Could not append Filter" );
            }
        }
    }

    #define GRF_CONFIG_STR      "   "
    #define STD_CONFIG_STR      "1 "

    static void SetToken( OUString& rOrigStr, sal_Int32 nToken, sal_Unicode cTok, const OUString& rStr)
    {
        const sal_Unicode*  pStr        = rOrigStr.getStr();
        sal_Int32     nLen              = rOrigStr.getLength();
        sal_Int32     nTok              = 0;
        sal_Int32     nFirstChar        = 0;
        sal_Int32     i                 = nFirstChar;

        // Determine token position and length
        pStr += i;
        while ( i < nLen )
        {
            // Increase token count if match
            if ( *pStr == cTok )
            {
                ++nTok;

                if ( nTok == nToken )
                    nFirstChar = i+1;
                else
                {
                    if ( nTok > nToken )
                        break;
                }
            }

            ++pStr;
            ++i;
        }

        if ( nTok >= nToken )
            rOrigStr = rOrigStr.replaceAt( nFirstChar, i-nFirstChar, rStr );
    }

    void FileDialogHelper_Impl::saveConfig()
    {
        uno::Reference < XFilePickerControlAccess > xDlg( mxFileDlg, UNO_QUERY );
        Any aValue;

        if ( ! xDlg.is() )
            return;

        if ( mbHasPreview )
        {
            SvtViewOptions aDlgOpt( EViewType::Dialog, IMPGRF_CONFIGNAME );
            OUString aUserData(GRF_CONFIG_STR);

            try
            {
                aValue = xDlg->getValue( ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, 0 );
                bool bValue = false;
                aValue >>= bValue;
                SetToken( aUserData, 1, ' ', OUString::number( static_cast<sal_Int32>(bValue) ) );

                INetURLObject aObj( getPath() );

                if ( aObj.GetProtocol() == INetProtocol::File )
                    SetToken( aUserData, 2, ' ', aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );

                OUString aFilter = getFilter();
                aFilter = EncodeSpaces_Impl( aFilter );
                SetToken( aUserData, 3, ' ', aFilter );

                aDlgOpt.SetUserItem( USERITEM_NAME, makeAny( aUserData ) );
            }
            catch( const IllegalArgumentException& ){}
        }
        else
        {
            bool bWriteConfig = false;
            SvtViewOptions aDlgOpt( EViewType::Dialog, IODLG_CONFIGNAME );
            OUString aUserData(STD_CONFIG_STR);

            if ( aDlgOpt.Exists() )
            {
                Any aUserItem = aDlgOpt.GetUserItem( USERITEM_NAME );
                OUString aTemp;
                if ( aUserItem >>= aTemp )
                    aUserData = aTemp;
            }

            if ( mbHasAutoExt )
            {
                try
                {
                    aValue = xDlg->getValue( ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, 0 );
                    bool bAutoExt = true;
                    aValue >>= bAutoExt;
                    SetToken( aUserData, 0, ' ', OUString::number( static_cast<sal_Int32>(bAutoExt) ) );
                    bWriteConfig = true;
                }
                catch( const IllegalArgumentException& ){}
            }

            if ( ! mbIsSaveDlg )
            {
                OUString aPath = getPath();
                if ( comphelper::isFileUrl( aPath ) )
                {
                    SetToken( aUserData, 1, ' ', aPath );
                    bWriteConfig = true;
                }
            }

            if( mbHasSelectionBox && mbSelectionFltrEnabled )
            {
                try
                {
                    aValue = xDlg->getValue( ExtendedFilePickerElementIds::CHECKBOX_SELECTION, 0 );
                    bool bSelection = true;
                    aValue >>= bSelection;
                    if ( comphelper::string::getTokenCount(aUserData, ' ') < 3 )
                        aUserData += " ";
                    SetToken( aUserData, 2, ' ', OUString::number( static_cast<sal_Int32>(bSelection) ) );
                    bWriteConfig = true;
                }
                catch( const IllegalArgumentException& ){}
            }

            if ( bWriteConfig )
                aDlgOpt.SetUserItem( USERITEM_NAME, makeAny( aUserData ) );
        }

        SfxApplication *pSfxApp = SfxGetpApp();
        pSfxApp->SetLastDir_Impl( getPath() );
    }

    namespace
    {
        OUString getInitPath( const OUString& _rFallback, const sal_Int32 _nFallbackToken )
        {
            SfxApplication *pSfxApp = SfxGetpApp();
            OUString sPath = pSfxApp->GetLastDir_Impl();

            if ( sPath.isEmpty() )
                sPath = _rFallback.getToken( _nFallbackToken, ' ' );

            // check if the path points to a valid (accessible) directory
            bool bValid = false;
            if ( !sPath.isEmpty() )
            {
                OUString sPathCheck( sPath );
                if ( sPathCheck[ sPathCheck.getLength() - 1 ] != '/' )
                    sPathCheck += "/";
                sPathCheck += ".";
                try
                {
                    ::ucbhelper::Content aContent( sPathCheck,
                                                   utl::UCBContentHelper::getDefaultCommandEnvironment(),
                                                   comphelper::getProcessComponentContext() );
                    bValid = aContent.isFolder();
                }
                catch( const Exception& ) {}
            }

            if ( !bValid )
                sPath.clear();

            return sPath;
        }
    }

    void FileDialogHelper_Impl::loadConfig()
    {
        uno::Reference < XFilePickerControlAccess > xDlg( mxFileDlg, UNO_QUERY );
        Any aValue;

        if ( ! xDlg.is() )
            return;

        if ( mbHasPreview )
        {
            SvtViewOptions aViewOpt( EViewType::Dialog, IMPGRF_CONFIGNAME );
            OUString aUserData;

            if ( aViewOpt.Exists() )
            {
                Any aUserItem = aViewOpt.GetUserItem( USERITEM_NAME );
                OUString aTemp;
                if ( aUserItem >>= aTemp )
                    aUserData = aTemp;
            }

            if ( !aUserData.isEmpty() )
            {
                try
                {
                    // respect the last "insert as link" state
                    bool bLink = aUserData.getToken( 0, ' ' ).toInt32();
                    aValue <<= bLink;
                    xDlg->setValue( ExtendedFilePickerElementIds::CHECKBOX_LINK, 0, aValue );

                    // respect the last "show preview" state
                    bool bShowPreview = aUserData.getToken( 1, ' ' ).toInt32();
                    aValue <<= bShowPreview;
                    xDlg->setValue( ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, 0, aValue );

                    if ( maPath.isEmpty() )
                        displayFolder( getInitPath( aUserData, 2 ) );

                    if ( maCurFilter.isEmpty() )
                    {
                        OUString aFilter = aUserData.getToken( 3, ' ' );
                        aFilter = DecodeSpaces_Impl( aFilter );
                        setFilter( aFilter );
                    }

                    // set the member so we know that we have to show the preview
                    mbShowPreview = bShowPreview;
                }
                catch( const IllegalArgumentException& ){}
            }

            if ( maPath.isEmpty() )
                displayFolder( SvtPathOptions().GetGraphicPath() );
        }
        else
        {
            SvtViewOptions aViewOpt( EViewType::Dialog, IODLG_CONFIGNAME );
            OUString aUserData;

            if ( aViewOpt.Exists() )
            {
                Any aUserItem = aViewOpt.GetUserItem( USERITEM_NAME );
                OUString aTemp;
                if ( aUserItem >>= aTemp )
                    aUserData = aTemp;
            }

            if ( aUserData.isEmpty() )
                aUserData = STD_CONFIG_STR;

            if ( maPath.isEmpty() )
                displayFolder( getInitPath( aUserData, 1 ) );

            if ( mbHasAutoExt )
            {
                sal_Int32 nFlag = aUserData.getToken( 0, ' ' ).toInt32();
                aValue <<= static_cast<bool>(nFlag);
                try
                {
                    xDlg->setValue( ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, 0, aValue );
                }
                catch( const IllegalArgumentException& ){}
            }

            if( mbHasSelectionBox )
            {
                sal_Int32 nFlag = aUserData.getToken( 2, ' ' ).toInt32();
                aValue <<= static_cast<bool>(nFlag);
                try
                {
                    xDlg->setValue( ExtendedFilePickerElementIds::CHECKBOX_SELECTION, 0, aValue );
                }
                catch( const IllegalArgumentException& ){}
            }

            if ( maPath.isEmpty() )
                displayFolder( SvtPathOptions().GetWorkPath() );
        }
    }

    void FileDialogHelper_Impl::setDefaultValues()
    {
        // when no filter is set, we set the currentFilter to <all>
        if ( maCurFilter.isEmpty() && !maSelectFilter.isEmpty() )
        {
            uno::Reference< XFilterManager > xFltMgr( mxFileDlg, UNO_QUERY );
            try
            {
                xFltMgr->setCurrentFilter( maSelectFilter );
            }
            catch( const IllegalArgumentException& )
            {}
        }

        // when no path is set, we use the standard 'work' folder
        if ( maPath.isEmpty() )
        {
            OUString aWorkFolder = SvtPathOptions().GetWorkPath();
            try
            {
                mxFileDlg->setDisplayDirectory( aWorkFolder );
            }
            catch( const Exception& )
            {
                OSL_FAIL( "FileDialogHelper_Impl::setDefaultValues: caught an exception while setting the display directory!" );
            }
        }
    }

    bool FileDialogHelper_Impl::isShowFilterExtensionEnabled() const
    {
        return !maFilters.empty();
    }

    void FileDialogHelper_Impl::addFilterPair( const OUString& rFilter,
                                               const OUString& rFilterWithExtension )
    {
        maFilters.emplace_back( rFilter, rFilterWithExtension );

    }

    OUString FileDialogHelper_Impl::getFilterName( const OUString& rFilterWithExtension ) const
    {
        OUString sRet;
        for (auto const& filter : maFilters)
        {
            if (filter.Second == rFilterWithExtension)
            {
                sRet = filter.First;
                break;
            }
        }
        return sRet;
    }

    OUString FileDialogHelper_Impl::getFilterWithExtension( const OUString& rFilter ) const
    {
        OUString sRet;
        for (auto const& filter : maFilters)
        {
            if ( filter.First == rFilter )
            {
                sRet = filter.Second;
                break;
            }
        }
        return sRet;
    }

    void FileDialogHelper_Impl::SetContext( FileDialogHelper::Context _eNewContext )
    {
        meContext = _eNewContext;

        const OUString* pConfigId = GetLastFilterConfigId( _eNewContext );
        if( pConfigId )
            LoadLastUsedFilter( *pConfigId );
    }

    // FileDialogHelper

    FileDialogHelper::FileDialogHelper(
        sal_Int16 nDialogType,
        FileDialogFlags nFlags,
        const OUString& rFact,
        SfxFilterFlags nMust,
        SfxFilterFlags nDont,
        weld::Window* pPreferredParent)
        :   m_nError(0),
            mpImpl(new FileDialogHelper_Impl(this, nDialogType, nFlags, SFX2_IMPL_DIALOG_CONFIG, pPreferredParent))
    {

        // create the list of filters
        mpImpl->addFilters(
                SfxObjectShell::GetServiceNameFromFactory(rFact), nMust, nDont );
    }

    FileDialogHelper::FileDialogHelper(
        sal_Int16 nDialogType,
        FileDialogFlags nFlags,
        const OUString& rFact,
        sal_Int16 nDialog,
        SfxFilterFlags nMust,
        SfxFilterFlags nDont,
        const OUString& rStandardDir,
        const css::uno::Sequence< OUString >& rBlackList,
        weld::Window* pPreferredParent)
        :   m_nError(0),
            mpImpl( new FileDialogHelper_Impl( this, nDialogType, nFlags, nDialog, pPreferredParent, rStandardDir, rBlackList ) )
    {
        // create the list of filters
        mpImpl->addFilters(
                SfxObjectShell::GetServiceNameFromFactory(rFact), nMust, nDont );
    }

    FileDialogHelper::FileDialogHelper(sal_Int16 nDialogType, FileDialogFlags nFlags, weld::Window* pPreferredParent)
        :   m_nError(0),
            mpImpl( new FileDialogHelper_Impl( this, nDialogType, nFlags, SFX2_IMPL_DIALOG_CONFIG, pPreferredParent ) )
    {
    }

    FileDialogHelper::FileDialogHelper(
        sal_Int16 nDialogType,
        FileDialogFlags nFlags,
        const OUString& aFilterUIName,
        const OUString& aExtName,
        const OUString& rStandardDir,
        const css::uno::Sequence< OUString >& rBlackList,
        weld::Window* pPreferredParent )
        :   m_nError(0),
            mpImpl( new FileDialogHelper_Impl( this, nDialogType, nFlags, SFX2_IMPL_DIALOG_CONFIG, pPreferredParent, rStandardDir, rBlackList ) )
    {
        // the wildcard here is expected in form "*.extension"
        OUString aWildcard;
        if ( aExtName.indexOf( '*' ) != 0 )
        {
            if ( !aExtName.isEmpty() && aExtName.indexOf( '.' ) != 0 )
                aWildcard = "*.";
            else
                aWildcard = "*";
        }

        aWildcard += aExtName;

        OUString const aUIString = ::sfx2::addExtension( aFilterUIName,
                aWildcard, (OPEN == lcl_OpenOrSave(mpImpl->m_nDialogType)), *mpImpl.get());
        AddFilter( aUIString, aWildcard );
    }

    FileDialogHelper::~FileDialogHelper()
    {
        mpImpl->dispose();
    }

    void FileDialogHelper::CreateMatcher( const OUString& rFactory )
    {
        mpImpl->createMatcher( SfxObjectShell::GetServiceNameFromFactory(rFactory) );
    }

    void FileDialogHelper::SetControlHelpIds( const sal_Int16* _pControlId, const char** _pHelpId )
    {
        mpImpl->setControlHelpIds( _pControlId, _pHelpId );
    }

    void FileDialogHelper::SetContext( Context _eNewContext )
    {
        mpImpl->SetContext( _eNewContext );
    }

    IMPL_LINK_NOARG(FileDialogHelper, ExecuteSystemFilePicker, void*, void)
    {
        m_nError = mpImpl->execute();
        m_aDialogClosedLink.Call( this );
    }

    // rDirPath has to be a directory
    ErrCode FileDialogHelper::Execute( std::vector<OUString>& rpURLList,
                                       SfxItemSet *&   rpSet,
                                       OUString&       rFilter,
                                       const OUString& rDirPath )
    {
        SetDisplayFolder( rDirPath );
        return mpImpl->execute( rpURLList, rpSet, rFilter );
    }

    ErrCode FileDialogHelper::Execute()
    {
        return mpImpl->execute();
    }

    ErrCode FileDialogHelper::Execute( SfxItemSet *&   rpSet,
                                       OUString&       rFilter )
    {
        ErrCode nRet;
        std::vector<OUString> rURLList;
        nRet = mpImpl->execute(rURLList, rpSet, rFilter);
        return nRet;
    }

    void FileDialogHelper::StartExecuteModal( const Link<FileDialogHelper*,void>& rEndDialogHdl )
    {
        m_aDialogClosedLink = rEndDialogHdl;
        m_nError = ERRCODE_NONE;
        if ( mpImpl->isSystemFilePicker() )
            Application::PostUserEvent( LINK( this, FileDialogHelper, ExecuteSystemFilePicker ) );
        else
            mpImpl->implStartExecute();
    }

    short FileDialogHelper::GetDialogType() const
    {
        return mpImpl.get() ? mpImpl->m_nDialogType : 0;
    }

    bool FileDialogHelper::IsPasswordEnabled() const
    {
        return mpImpl.get() && mpImpl->isPasswordEnabled();
    }

    OUString FileDialogHelper::GetRealFilter() const
    {
        OUString sFilter;
        if ( mpImpl.get() )
            mpImpl->getRealFilter( sFilter );
        return sFilter;
    }

    void FileDialogHelper::SetTitle( const OUString& rNewTitle )
    {
        if ( mpImpl->mxFileDlg.is() )
            mpImpl->mxFileDlg->setTitle( rNewTitle );
    }

    OUString FileDialogHelper::GetPath() const
    {
        OUString aPath;

        if ( mpImpl->mlLastURLs.size() > 0)
            return mpImpl->mlLastURLs[0];

        if ( mpImpl->mxFileDlg.is() )
        {
            Sequence < OUString > aPathSeq = mpImpl->mxFileDlg->getFiles();

            if ( aPathSeq.getLength() == 1 )
            {
                aPath = aPathSeq[0];
            }
        }

        return aPath;
    }

    Sequence < OUString > FileDialogHelper::GetMPath() const
    {
        if ( mpImpl->mlLastURLs.size() > 0)
            return comphelper::containerToSequence(mpImpl->mlLastURLs);

        if ( mpImpl->mxFileDlg.is() )
            return mpImpl->mxFileDlg->getFiles();
        else
        {
            Sequence < OUString > aEmpty;
            return aEmpty;
        }
    }

    Sequence< OUString > FileDialogHelper::GetSelectedFiles() const
    {
        // a) the new way (optional!)
        uno::Sequence< OUString > aResultSeq;
        uno::Reference< XFilePicker3 > xPickNew(mpImpl->mxFileDlg, UNO_QUERY);
        if (xPickNew.is())
        {
            aResultSeq = xPickNew->getSelectedFiles();
        }
        // b) the olde way ... non optional.
        else
        {
            uno::Reference< XFilePicker > xPickOld(mpImpl->mxFileDlg, UNO_QUERY_THROW);
            Sequence< OUString > lFiles = xPickOld->getFiles();
            ::sal_Int32          nFiles = lFiles.getLength();
            if ( nFiles > 1 )
            {
                aResultSeq = Sequence< OUString >( nFiles-1 );

                INetURLObject aPath( lFiles[0] );
                aPath.setFinalSlash();

                for (::sal_Int32 i = 1; i < nFiles; i++)
                {
                    if (i == 1)
                        aPath.Append( lFiles[i] );
                    else
                        aPath.setName( lFiles[i] );

                    aResultSeq[i-1] = aPath.GetMainURL( INetURLObject::DecodeMechanism::NONE );
                }
            }
            else
                aResultSeq = lFiles;
        }

        return aResultSeq;
    }

    OUString FileDialogHelper::GetDisplayDirectory() const
    {
        return mpImpl->getPath();
    }

    OUString FileDialogHelper::GetCurrentFilter() const
    {
        return mpImpl->getFilter();
    }

    ErrCode FileDialogHelper::GetGraphic( Graphic& rGraphic ) const
    {
        return mpImpl->getGraphic( rGraphic );
    }

    static int impl_isFolder( const OUString& rPath )
    {
        try
        {
            ::ucbhelper::Content aContent(
                rPath, uno::Reference< ucb::XCommandEnvironment > (),
                comphelper::getProcessComponentContext() );
            if ( aContent.isFolder() )
                return 1;

            return 0;
        }
        catch ( const Exception & )
        {
        }

        return -1;
    }

    void FileDialogHelper::SetDisplayDirectory( const OUString& _rPath )
    {
        if ( _rPath.isEmpty() )
            return;

        // if the given path isn't a folder, we cut off the last part
        // and take it as filename and the rest of the path should be
        // the folder

        INetURLObject aObj( _rPath );

        OUString sFileName = aObj.GetName( INetURLObject::DecodeMechanism::WithCharset );
        aObj.removeSegment();
        OUString sPath = aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );

        int nIsFolder = impl_isFolder( _rPath );
        if ( nIsFolder == 0 ||
             ( nIsFolder == -1 && impl_isFolder( sPath ) == 1 ) )
        {
            mpImpl->setFileName( sFileName );
            mpImpl->displayFolder( sPath );
        }
        else
        {
            INetURLObject aObjPathName( _rPath );
            OUString sFolder( aObjPathName.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
            if ( sFolder.isEmpty() )
            {
                // _rPath is not a valid path -> fallback to home directory
                osl::Security aSecurity;
                aSecurity.getHomeDir( sFolder );
            }
            mpImpl->displayFolder( sFolder );
        }
    }

    void FileDialogHelper::SetDisplayFolder( const OUString& _rURL )
    {
        mpImpl->displayFolder( _rURL );
    }

    void FileDialogHelper::SetFileName( const OUString& _rFileName )
    {
        mpImpl->setFileName( _rFileName );
    }

    void FileDialogHelper::AddFilter( const OUString& rFilterName,
                                      const OUString& rExtension )
    {
        mpImpl->addFilter( rFilterName, rExtension );
    }

    void FileDialogHelper::SetCurrentFilter( const OUString& rFilter )
    {
        OUString sFilter( rFilter );
        if ( mpImpl->isShowFilterExtensionEnabled() )
            sFilter = mpImpl->getFilterWithExtension( rFilter );
        mpImpl->setFilter( sFilter );
    }

    const uno::Reference < XFilePicker3 >& FileDialogHelper::GetFilePicker() const
    {
        return mpImpl->mxFileDlg;
    }

    // XFilePickerListener Methods
    void FileDialogHelper::FileSelectionChanged()
    {
        mpImpl->handleFileSelectionChanged();
    }

    void FileDialogHelper::DirectoryChanged()
    {
        mpImpl->handleDirectoryChanged();
    }

    OUString FileDialogHelper::HelpRequested( const FilePickerEvent& aEvent )
    {
        return sfx2::FileDialogHelper_Impl::handleHelpRequested( aEvent );
    }

    void FileDialogHelper::ControlStateChanged( const FilePickerEvent& aEvent )
    {
        mpImpl->handleControlStateChanged( aEvent );
    }

    void FileDialogHelper::DialogSizeChanged()
    {
        mpImpl->handleDialogSizeChanged();
    }

    void FileDialogHelper::DialogClosed( const DialogClosedEvent& _rEvent )
    {
        m_nError = ( RET_OK == _rEvent.DialogResult ) ? ERRCODE_NONE : ERRCODE_ABORT;
        m_aDialogClosedLink.Call( this );
    }

    ErrCode FileOpenDialog_Impl( weld::Window* pParent,
                                 sal_Int16 nDialogType,
                                 FileDialogFlags nFlags,
                                 std::vector<OUString>& rpURLList,
                                 OUString& rFilter,
                                 SfxItemSet *& rpSet,
                                 const OUString* pPath,
                                 sal_Int16 nDialog,
                                 const OUString& rStandardDir,
                                 const css::uno::Sequence< OUString >& rBlackList )
    {
        ErrCode nRet;
        std::unique_ptr<FileDialogHelper> pDialog;
        // Sign existing PDF: only works with PDF files and they are opened
        // read-only to discourage editing (which would invalidate existing
        // signatures).
        if (nFlags & FileDialogFlags::SignPDF)
            pDialog.reset(new FileDialogHelper(nDialogType, nFlags, SfxResId(STR_SFX_FILTERNAME_PDF), "pdf", rStandardDir, rBlackList, pParent));
        else
            pDialog.reset(new FileDialogHelper(nDialogType, nFlags, OUString(), nDialog, SfxFilterFlags::NONE, SfxFilterFlags::NONE, rStandardDir, rBlackList, pParent));

        OUString aPath;
        if ( pPath )
            aPath = *pPath;

        nRet = pDialog->Execute(rpURLList, rpSet, rFilter, aPath);
        DBG_ASSERT( rFilter.indexOf(": ") == -1, "Old filter name used!");

        if (rpSet && nFlags & FileDialogFlags::SignPDF)
            rpSet->Put(SfxBoolItem(SID_DOC_READONLY, true));
        return nRet;
    }

    ErrCode RequestPassword(const std::shared_ptr<const SfxFilter>& pCurrentFilter, OUString const & aURL, SfxItemSet* pSet, const css::uno::Reference<css::awt::XWindow>& rParent)
    {
        uno::Reference<task::XInteractionHandler2> xInteractionHandler = task::InteractionHandler::createWithParent(::comphelper::getProcessComponentContext(), rParent);
        // TODO: need a save way to distinguish MS filters from other filters
        // for now MS-filters are the only alien filters that support encryption
        bool bMSType = !pCurrentFilter->IsOwnFormat();
        ::comphelper::DocPasswordRequestType eType = bMSType ?
            ::comphelper::DocPasswordRequestType::MS :
            ::comphelper::DocPasswordRequestType::Standard;

        ::rtl::Reference< ::comphelper::DocPasswordRequest > pPasswordRequest( new ::comphelper::DocPasswordRequest( eType, css::task::PasswordRequestMode_PASSWORD_CREATE, aURL, bool( pCurrentFilter->GetFilterFlags() & SfxFilterFlags::PASSWORDTOMODIFY ) ) );

        uno::Reference< css::task::XInteractionRequest > rRequest( pPasswordRequest.get() );
        do
        {
            xInteractionHandler->handle( rRequest );
            if (!pPasswordRequest->isPassword() || bMSType)
            {
                break;
            }
            OString const utf8Pwd(OUStringToOString(pPasswordRequest->getPassword(), RTL_TEXTENCODING_UTF8));
            OString const utf8Ptm(OUStringToOString(pPasswordRequest->getPasswordToModify(), RTL_TEXTENCODING_UTF8));
            if (!(52 <= utf8Pwd.getLength() && utf8Pwd.getLength() <= 55
                    && SvtSaveOptions().GetODFDefaultVersion() < SvtSaveOptions::ODFVER_012)
                && !(52 <= utf8Ptm.getLength() && utf8Ptm.getLength() <= 55))
            {
                break;
            }
            vcl::Window* pWin = Application::GetDefDialogParent();
            std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pWin ? pWin->GetFrameWeld() : nullptr, VclMessageType::Warning,
                VclButtonsType::Ok, SfxResId(STR_PASSWORD_LEN)));
            xBox->set_secondary_text(SfxResId(STR_PASSWORD_WARNING));
            xBox->run();
        }
        while (true);
        if ( pPasswordRequest->isPassword() )
        {
            if ( pPasswordRequest->getPassword().getLength() )
            {
                // TODO/LATER: The filters should show the password dialog themself in future
                if ( bMSType )
                {
                    // Check if filter supports OOXML encryption
                    if ( lclSupportsOOXMLEncryption( pCurrentFilter->GetFilterName() ) )
                    {
                        ::comphelper::SequenceAsHashMap aHashData;
                        aHashData[ OUString( "OOXPassword"  ) ] <<= pPasswordRequest->getPassword();
                        pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aHashData.getAsConstNamedValueList() ) ) );
                    }
                    else
                    {
                        uno::Sequence< sal_Int8 > aUniqueID = ::comphelper::DocPasswordHelper::GenerateRandomByteSequence( 16 );
                        uno::Sequence< sal_Int8 > aEncryptionKey = ::comphelper::DocPasswordHelper::GenerateStd97Key( pPasswordRequest->getPassword(), aUniqueID );

                        if ( aEncryptionKey.getLength() )
                        {
                            ::comphelper::SequenceAsHashMap aHashData;
                            aHashData[ OUString( "STD97EncryptionKey"  ) ] <<= aEncryptionKey;
                            aHashData[ OUString( "STD97UniqueID"  ) ] <<= aUniqueID;

                            pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aHashData.getAsConstNamedValueList() ) ) );
                        }
                        else
                        {
                            return ERRCODE_IO_NOTSUPPORTED;
                        }
                    }
                }
                else
                {
                    pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( ::comphelper::OStorageHelper::CreatePackageEncryptionData( pPasswordRequest->getPassword() ) ) ) );
                }
            }

            if ( pPasswordRequest->getRecommendReadOnly() )
                pSet->Put( SfxBoolItem( SID_RECOMMENDREADONLY, true ) );

            if ( bMSType )
            {
                // the empty password has 0 as Hash
                sal_Int32 nHash = SfxMedium::CreatePasswordToModifyHash( pPasswordRequest->getPasswordToModify(),
                                                                         pCurrentFilter->GetServiceName() == "com.sun.star.text.TextDocument" );
                if ( nHash )
                    pSet->Put( SfxUnoAnyItem( SID_MODIFYPASSWORDINFO, uno::makeAny( nHash ) ) );
            }
            else
            {
                uno::Sequence< beans::PropertyValue > aModifyPasswordInfo = ::comphelper::DocPasswordHelper::GenerateNewModifyPasswordInfo( pPasswordRequest->getPasswordToModify() );
                if ( aModifyPasswordInfo.getLength() )
                    pSet->Put( SfxUnoAnyItem( SID_MODIFYPASSWORDINFO, uno::makeAny( aModifyPasswordInfo ) ) );
            }
        }
        else
            return ERRCODE_ABORT;
        return ERRCODE_NONE;
    }

    OUString EncodeSpaces_Impl( const OUString& rSource )
    {
        OUString sRet( rSource );
        sRet = sRet.replaceAll( " ", "%20" );
        return sRet;
    }

    OUString DecodeSpaces_Impl( const OUString& rSource )
    {
        OUString sRet( rSource );
        sRet = sRet.replaceAll( "%20", " " );
        return sRet;
    }

    }   // end of namespace sfx2

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V1019 Compound assignment expression is used inside condition.