bump product version to 5.0.4.1
[LibreOffice.git] / sfx2 / source / dialog / filedlghelper.cxx
bloba1a38f542c4e55b35d2bf0b271ba9cc46b5c1d96
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sfx2/filedlghelper.hxx>
21 #include <sal/types.h>
22 #include <com/sun/star/lang/XInitialization.hpp>
23 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
24 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
25 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
26 #include <com/sun/star/ui/dialogs/FilePreviewImageFormats.hpp>
27 #include <com/sun/star/ui/dialogs/ControlActions.hpp>
28 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
29 #include <com/sun/star/ui/dialogs/XControlInformation.hpp>
30 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
31 #include <com/sun/star/ui/dialogs/XFilePickerNotifier.hpp>
32 #include <com/sun/star/ui/dialogs/XFilePreview.hpp>
33 #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
34 #include <com/sun/star/ui/dialogs/XFilterGroupManager.hpp>
35 #include <com/sun/star/ui/dialogs/XFilePicker2.hpp>
36 #include <com/sun/star/ui/dialogs/XAsynchronousExecutableDialog.hpp>
37 #include <com/sun/star/lang/XServiceInfo.hpp>
38 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <com/sun/star/beans/NamedValue.hpp>
40 #include <com/sun/star/embed/ElementModes.hpp>
41 #include <com/sun/star/container/XEnumeration.hpp>
42 #include <com/sun/star/container/XContainerQuery.hpp>
43 #include <com/sun/star/task/InteractionHandler.hpp>
44 #include <com/sun/star/task/XInteractionRequest.hpp>
45 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
47 #include <comphelper/processfactory.hxx>
48 #include <comphelper/sequenceashashmap.hxx>
49 #include <comphelper/stillreadwriteinteraction.hxx>
50 #include <comphelper/string.hxx>
51 #include <comphelper/types.hxx>
52 #include <tools/urlobj.hxx>
53 #include <vcl/help.hxx>
54 #include <unotools/ucbstreamhelper.hxx>
55 #include <unotools/ucbhelper.hxx>
56 #include <unotools/localfilehelper.hxx>
57 #include <osl/file.hxx>
58 #include <osl/mutex.hxx>
59 #include <osl/security.hxx>
60 #include <osl/thread.hxx>
61 #include <vcl/cvtgrf.hxx>
62 #include <vcl/msgbox.hxx>
63 #include <vcl/mnemonic.hxx>
64 #include <unotools/pathoptions.hxx>
65 #include <unotools/securityoptions.hxx>
66 #include <svl/itemset.hxx>
67 #include <svl/eitem.hxx>
68 #include <svl/intitem.hxx>
69 #include <svl/stritem.hxx>
70 #include <vcl/dibtools.hxx>
71 #include <vcl/graphicfilter.hxx>
72 #include <unotools/viewoptions.hxx>
73 #include <unotools/moduleoptions.hxx>
74 #include <svtools/helpid.hrc>
75 #include <comphelper/docpasswordrequest.hxx>
76 #include <comphelper/docpasswordhelper.hxx>
77 #include <ucbhelper/content.hxx>
78 #include <ucbhelper/commandenvironment.hxx>
79 #include <comphelper/storagehelper.hxx>
80 #include <toolkit/helper/vclunohelper.hxx>
81 #include <sfx2/app.hxx>
82 #include <sfx2/frame.hxx>
83 #include <sfx2/docfile.hxx>
84 #include <sfx2/docfac.hxx>
85 #include "openflag.hxx"
86 #include <sfx2/passwd.hxx>
87 #include <sfx2/sfxresid.hxx>
88 #include <sfx2/sfxsids.hrc>
89 #include "filedlghelper.hrc"
90 #include "filtergrouping.hxx"
91 #include <sfx2/request.hxx>
92 #include "filedlgimpl.hxx"
93 #include <helpid.hrc>
94 #include <sfxlocal.hrc>
95 #include <rtl/strbuf.hxx>
96 #include <comphelper/sequence.hxx>
98 #ifdef UNX
99 #include <errno.h>
100 #include <sys/stat.h>
101 #endif
103 using namespace ::com::sun::star;
104 using namespace ::com::sun::star::container;
105 using namespace ::com::sun::star::lang;
106 using namespace ::com::sun::star::ui::dialogs;
107 using namespace ::com::sun::star::ui::dialogs::TemplateDescription;
108 using namespace ::com::sun::star::uno;
109 using namespace ::com::sun::star::beans;
110 using namespace ::cppu;
112 #define IODLG_CONFIGNAME OUString("FilePicker_Save")
113 #define IMPGRF_CONFIGNAME OUString("FilePicker_Graph")
114 #define USERITEM_NAME OUString("UserItem")
116 namespace sfx2
119 namespace
121 bool lclSupportsOOXMLEncryption(const OUString& aFilterName)
123 return aFilterName == "Calc MS Excel 2007 XML"
124 || aFilterName == "MS Word 2007 XML"
125 || aFilterName == "Impress MS PowerPoint 2007 XML"
126 || aFilterName == "Impress MS PowerPoint 2007 XML AutoPlay"
127 || aFilterName == "Calc Office Open XML"
128 || aFilterName == "Impress Office Open XML"
129 || aFilterName == "Impress Office Open XML AutoPlay"
130 || aFilterName == "Office Open XML Text";
134 const OUString* GetLastFilterConfigId( FileDialogHelper::Context _eContext )
136 static const OUString aSD_EXPORT_IDENTIFIER("SdExportLastFilter");
137 static const OUString aSI_EXPORT_IDENTIFIER("SiExportLastFilter");
138 static const OUString aSW_EXPORT_IDENTIFIER("SwExportLastFilter");
140 const OUString* pRet = NULL;
142 switch( _eContext )
144 case FileDialogHelper::SD_EXPORT: pRet = &aSD_EXPORT_IDENTIFIER; break;
145 case FileDialogHelper::SI_EXPORT: pRet = &aSI_EXPORT_IDENTIFIER; break;
146 case FileDialogHelper::SW_EXPORT: pRet = &aSW_EXPORT_IDENTIFIER; break;
147 default: break;
150 return pRet;
153 OUString EncodeSpaces_Impl( const OUString& rSource );
154 OUString DecodeSpaces_Impl( const OUString& rSource );
156 // FileDialogHelper_Impl
158 // XFilePickerListener Methods
159 void SAL_CALL FileDialogHelper_Impl::fileSelectionChanged( const FilePickerEvent& aEvent ) throw ( RuntimeException, std::exception )
161 SolarMutexGuard aGuard;
162 mpAntiImpl->FileSelectionChanged( aEvent );
165 void SAL_CALL FileDialogHelper_Impl::directoryChanged( const FilePickerEvent& aEvent ) throw ( RuntimeException, std::exception )
167 SolarMutexGuard aGuard;
168 mpAntiImpl->DirectoryChanged( aEvent );
171 OUString SAL_CALL FileDialogHelper_Impl::helpRequested( const FilePickerEvent& aEvent ) throw ( RuntimeException, std::exception )
173 SolarMutexGuard aGuard;
174 return sfx2::FileDialogHelper::HelpRequested( aEvent );
177 void SAL_CALL FileDialogHelper_Impl::controlStateChanged( const FilePickerEvent& aEvent ) throw ( RuntimeException, std::exception )
179 SolarMutexGuard aGuard;
180 mpAntiImpl->ControlStateChanged( aEvent );
183 void SAL_CALL FileDialogHelper_Impl::dialogSizeChanged() throw ( RuntimeException, std::exception )
185 SolarMutexGuard aGuard;
186 mpAntiImpl->DialogSizeChanged();
189 // XDialogClosedListener Methods
190 void SAL_CALL FileDialogHelper_Impl::dialogClosed( const DialogClosedEvent& _rEvent ) throw ( RuntimeException, std::exception )
192 SolarMutexGuard aGuard;
193 mpAntiImpl->DialogClosed( _rEvent );
194 postExecute( _rEvent.DialogResult );
197 // handle XFilePickerListener events
198 void FileDialogHelper_Impl::handleFileSelectionChanged( const FilePickerEvent& )
200 if ( mbHasVersions )
201 updateVersions();
203 if ( mbShowPreview )
204 maPreviewIdle.Start();
207 void FileDialogHelper_Impl::handleDirectoryChanged( const FilePickerEvent& )
209 if ( mbShowPreview )
210 TimeOutHdl_Impl( NULL );
213 OUString FileDialogHelper_Impl::handleHelpRequested( const FilePickerEvent& aEvent )
215 //!!! todo: cache the help strings (here or TRA)
217 OString sHelpId;
218 // mapping from element id -> help id
219 switch ( aEvent.ElementId )
221 case ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION :
222 sHelpId = HID_FILESAVE_AUTOEXTENSION;
223 break;
225 case ExtendedFilePickerElementIds::CHECKBOX_PASSWORD :
226 sHelpId = HID_FILESAVE_SAVEWITHPASSWORD;
227 break;
229 case ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS :
230 sHelpId = HID_FILESAVE_CUSTOMIZEFILTER;
231 break;
233 case ExtendedFilePickerElementIds::CHECKBOX_READONLY :
234 sHelpId = HID_FILEOPEN_READONLY;
235 break;
237 case ExtendedFilePickerElementIds::CHECKBOX_LINK :
238 sHelpId = HID_FILEDLG_LINK_CB;
239 break;
241 case ExtendedFilePickerElementIds::CHECKBOX_PREVIEW :
242 sHelpId = HID_FILEDLG_PREVIEW_CB;
243 break;
245 case ExtendedFilePickerElementIds::PUSHBUTTON_PLAY :
246 sHelpId = HID_FILESAVE_DOPLAY;
247 break;
249 case ExtendedFilePickerElementIds::LISTBOX_VERSION_LABEL :
250 case ExtendedFilePickerElementIds::LISTBOX_VERSION :
251 sHelpId = HID_FILEOPEN_VERSION;
252 break;
254 case ExtendedFilePickerElementIds::LISTBOX_TEMPLATE_LABEL :
255 case ExtendedFilePickerElementIds::LISTBOX_TEMPLATE :
256 sHelpId = HID_FILESAVE_TEMPLATE;
257 break;
259 case ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE_LABEL :
260 case ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE :
261 sHelpId = HID_FILEOPEN_IMAGE_TEMPLATE;
262 break;
264 case ExtendedFilePickerElementIds::CHECKBOX_SELECTION :
265 sHelpId = HID_FILESAVE_SELECTION;
266 break;
268 default:
269 SAL_WARN( "sfx.dialog", "invalid element id" );
272 OUString aHelpText;
273 Help* pHelp = Application::GetHelp();
274 if ( pHelp )
275 aHelpText = pHelp->GetHelpText( OStringToOUString(sHelpId, RTL_TEXTENCODING_UTF8), NULL );
276 return aHelpText;
279 void FileDialogHelper_Impl::handleControlStateChanged( const FilePickerEvent& aEvent )
281 switch ( aEvent.ElementId )
283 case CommonFilePickerElementIds::LISTBOX_FILTER:
284 updateFilterOptionsBox();
285 enablePasswordBox( false );
286 updateSelectionBox();
287 // only use it for export and with our own dialog
288 if ( mbExport && !mbSystemPicker )
289 updateExportButton();
290 break;
292 case ExtendedFilePickerElementIds::CHECKBOX_PREVIEW:
293 updatePreviewState();
294 break;
298 void FileDialogHelper_Impl::handleDialogSizeChanged()
300 if ( mbShowPreview )
301 TimeOutHdl_Impl( NULL );
304 // XEventListener Methods
305 void SAL_CALL FileDialogHelper_Impl::disposing( const EventObject& ) throw ( RuntimeException, std::exception )
307 SolarMutexGuard aGuard;
308 dispose();
311 void FileDialogHelper_Impl::dispose()
313 if ( mxFileDlg.is() )
315 // remove the event listener
316 uno::Reference< XFilePickerNotifier > xNotifier( mxFileDlg, UNO_QUERY );
317 if ( xNotifier.is() )
318 xNotifier->removeFilePickerListener( this );
320 ::comphelper::disposeComponent( mxFileDlg );
321 mxFileDlg.clear();
325 OUString FileDialogHelper_Impl::getCurrentFilterUIName() const
327 OUString aFilterName;
328 uno::Reference< XFilterManager > xFltMgr( mxFileDlg, UNO_QUERY );
330 if( xFltMgr.is() )
332 aFilterName = xFltMgr->getCurrentFilter();
334 if ( !aFilterName.isEmpty() && isShowFilterExtensionEnabled() )
335 aFilterName = getFilterName( aFilterName );
338 return aFilterName;
341 void FileDialogHelper_Impl::LoadLastUsedFilter( const OUString& _rContextIdentifier )
343 SvtViewOptions aDlgOpt( E_DIALOG, IODLG_CONFIGNAME );
345 if( aDlgOpt.Exists() )
347 OUString aLastFilter;
348 if( aDlgOpt.GetUserItem( _rContextIdentifier ) >>= aLastFilter )
349 setFilter( aLastFilter );
353 void FileDialogHelper_Impl::SaveLastUsedFilter( const OUString& _rContextIdentifier )
355 SvtViewOptions( E_DIALOG, IODLG_CONFIGNAME ).SetUserItem( _rContextIdentifier,
356 makeAny( getFilterWithExtension( getFilter() ) ) );
359 void FileDialogHelper_Impl::SaveLastUsedFilter()
361 const OUString* pConfigId = GetLastFilterConfigId( meContext );
362 if( pConfigId )
363 SaveLastUsedFilter( *pConfigId );
366 const SfxFilter* FileDialogHelper_Impl::getCurentSfxFilter()
368 OUString aFilterName = getCurrentFilterUIName();
370 const SfxFilter* pFilter = NULL;
371 if ( mpMatcher && !aFilterName.isEmpty() )
372 pFilter = mpMatcher->GetFilter4UIName( aFilterName, m_nMustFlags, m_nDontFlags );
374 return pFilter;
377 bool FileDialogHelper_Impl::updateExtendedControl( sal_Int16 _nExtendedControlId, bool _bEnable )
379 bool bIsEnabled = false;
381 uno::Reference < XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY );
382 if ( xCtrlAccess.is() )
386 xCtrlAccess->enableControl( _nExtendedControlId, _bEnable );
387 bIsEnabled = _bEnable;
389 catch( const IllegalArgumentException& )
391 OSL_FAIL( "FileDialogHelper_Impl::updateExtendedControl: caught an exception!" );
394 return bIsEnabled;
397 bool FileDialogHelper_Impl::CheckFilterOptionsCapability( const SfxFilter* _pFilter )
399 bool bResult = false;
401 if( mxFilterCFG.is() && _pFilter )
403 try {
404 Sequence < PropertyValue > aProps;
405 Any aAny = mxFilterCFG->getByName( _pFilter->GetName() );
406 if ( aAny >>= aProps )
408 OUString aServiceName;
409 sal_Int32 nPropertyCount = aProps.getLength();
410 for( sal_Int32 nProperty=0; nProperty < nPropertyCount; ++nProperty )
412 if( aProps[nProperty].Name == "UIComponent" )
414 aProps[nProperty].Value >>= aServiceName;
415 if( !aServiceName.isEmpty() )
416 bResult = true;
421 catch( const Exception& )
426 return bResult;
429 bool FileDialogHelper_Impl::isInOpenMode() const
431 bool bRet = false;
433 switch ( m_nDialogType )
435 case FILEOPEN_SIMPLE:
436 case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE:
437 case FILEOPEN_PLAY:
438 case FILEOPEN_READONLY_VERSION:
439 case FILEOPEN_LINK_PREVIEW:
440 bRet = true;
443 return bRet;
446 void FileDialogHelper_Impl::updateFilterOptionsBox()
448 if ( !m_bHaveFilterOptions )
449 return;
451 updateExtendedControl(
452 ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS,
453 CheckFilterOptionsCapability( getCurentSfxFilter() )
457 void FileDialogHelper_Impl::updateExportButton()
459 uno::Reference < XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY );
460 if ( xCtrlAccess.is() )
462 OUString sEllipses( "..." );
463 OUString sOldLabel( xCtrlAccess->getLabel( CommonFilePickerElementIds::PUSHBUTTON_OK ) );
465 // initialize button label; we need the label with the mnemonic char
466 if ( maButtonLabel.isEmpty() || maButtonLabel.indexOf( MNEMONIC_CHAR ) == -1 )
468 // cut the ellipses, if necessary
469 sal_Int32 nIndex = sOldLabel.indexOf( sEllipses );
470 if ( -1 == nIndex )
471 nIndex = sOldLabel.getLength();
472 maButtonLabel = sOldLabel.copy( 0, nIndex );
475 OUString sLabel = maButtonLabel;
476 // filter with options -> append ellipses on export button label
477 if ( CheckFilterOptionsCapability( getCurentSfxFilter() ) )
478 sLabel += "...";
480 if ( sOldLabel != sLabel )
484 xCtrlAccess->setLabel( CommonFilePickerElementIds::PUSHBUTTON_OK, sLabel );
486 catch( const IllegalArgumentException& )
488 SAL_WARN( "sfx.dialog", "FileDialogHelper_Impl::updateExportButton: caught an exception!" );
494 void FileDialogHelper_Impl::updateSelectionBox()
496 if ( !mbHasSelectionBox )
497 return;
499 // Does the selection box exist?
500 bool bSelectionBoxFound = false;
501 uno::Reference< XControlInformation > xCtrlInfo( mxFileDlg, UNO_QUERY );
502 if ( xCtrlInfo.is() )
504 Sequence< OUString > aCtrlList = xCtrlInfo->getSupportedControls();
505 sal_uInt32 nCount = aCtrlList.getLength();
506 for ( sal_uInt32 nCtrl = 0; nCtrl < nCount; ++nCtrl )
507 if ( aCtrlList[ nCtrl ] == "SelectionBox" )
509 bSelectionBoxFound = true;
510 break;
514 if ( bSelectionBoxFound )
516 const SfxFilter* pFilter = getCurentSfxFilter();
517 mbSelectionFltrEnabled = updateExtendedControl(
518 ExtendedFilePickerElementIds::CHECKBOX_SELECTION,
519 ( mbSelectionEnabled && pFilter && ( pFilter->GetFilterFlags() & SfxFilterFlags::SUPPORTSSELECTION ) ) );
520 uno::Reference< XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY );
521 xCtrlAccess->setValue( ExtendedFilePickerElementIds::CHECKBOX_SELECTION, 0, makeAny( mbSelection ) );
525 void FileDialogHelper_Impl::enablePasswordBox( bool bInit )
527 if ( ! mbHasPassword )
528 return;
530 bool bWasEnabled = mbIsPwdEnabled;
532 const SfxFilter* pCurrentFilter = getCurentSfxFilter();
533 mbIsPwdEnabled = updateExtendedControl(
534 ExtendedFilePickerElementIds::CHECKBOX_PASSWORD,
535 pCurrentFilter && ( pCurrentFilter->GetFilterFlags() & SfxFilterFlags::ENCRYPTION )
538 if( bInit )
540 // in case of inintialization previous state is not interesting
541 if( mbIsPwdEnabled )
543 uno::Reference< XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY );
544 if( mbPwdCheckBoxState )
545 xCtrlAccess->setValue( ExtendedFilePickerElementIds::CHECKBOX_PASSWORD, 0, makeAny( sal_True ) );
548 else if( !bWasEnabled && mbIsPwdEnabled )
550 uno::Reference< XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY );
551 if( mbPwdCheckBoxState )
552 xCtrlAccess->setValue( ExtendedFilePickerElementIds::CHECKBOX_PASSWORD, 0, makeAny( sal_True ) );
554 else if( bWasEnabled && !mbIsPwdEnabled )
556 // remember user settings until checkbox is enabled
557 uno::Reference< XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY );
558 Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::CHECKBOX_PASSWORD, 0 );
559 bool bPassWord = false;
560 mbPwdCheckBoxState = ( aValue >>= bPassWord ) && bPassWord;
561 xCtrlAccess->setValue( ExtendedFilePickerElementIds::CHECKBOX_PASSWORD, 0, makeAny( sal_False ) );
565 void FileDialogHelper_Impl::updatePreviewState( bool _bUpdatePreviewWindow )
567 if ( mbHasPreview )
569 uno::Reference< XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY );
571 // check, whether or not we have to display a preview
572 if ( xCtrlAccess.is() )
576 Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, 0 );
577 bool bShowPreview = false;
579 if ( aValue >>= bShowPreview )
581 mbShowPreview = bShowPreview;
583 // setShowState has currently no effect for the
584 // OpenOffice FilePicker (see svtools/source/filepicker/iodlg.cxx)
585 uno::Reference< XFilePreview > xFilePreview( mxFileDlg, UNO_QUERY );
586 if ( xFilePreview.is() )
587 xFilePreview->setShowState( mbShowPreview );
589 if ( _bUpdatePreviewWindow )
590 TimeOutHdl_Impl( NULL );
593 catch( const Exception& )
595 SAL_WARN( "sfx.dialog", "FileDialogHelper_Impl::updatePreviewState: caught an exception!" );
601 void FileDialogHelper_Impl::updateVersions()
603 Sequence < OUString > aEntries;
604 Sequence < OUString > aPathSeq = mxFileDlg->getFiles();
606 if ( aPathSeq.getLength() == 1 )
608 INetURLObject aObj( aPathSeq[0] );
610 if ( ( aObj.GetProtocol() == INetProtocol::File ) &&
611 ( utl::UCBContentHelper::IsDocument( aObj.GetMainURL( INetURLObject::NO_DECODE ) ) ) )
615 uno::Reference< embed::XStorage > xStorage = ::comphelper::OStorageHelper::GetStorageFromURL(
616 aObj.GetMainURL( INetURLObject::NO_DECODE ),
617 embed::ElementModes::READ );
619 DBG_ASSERT( xStorage.is(), "The method must return the storage or throw an exception!" );
620 if ( !xStorage.is() )
621 throw uno::RuntimeException();
623 uno::Sequence < util::RevisionTag > xVersions = SfxMedium::GetVersionList( xStorage );
625 aEntries.realloc( xVersions.getLength() + 1 );
626 aEntries[0] = SfxResId( STR_SFX_FILEDLG_ACTUALVERSION ).toString();
628 for ( sal_Int32 i=0; i<xVersions.getLength(); i++ )
629 aEntries[ i + 1 ] = xVersions[i].Identifier;
631 catch( const uno::Exception& )
637 uno::Reference < XFilePickerControlAccess > xDlg( mxFileDlg, UNO_QUERY );
638 Any aValue;
642 xDlg->setValue( ExtendedFilePickerElementIds::LISTBOX_VERSION,
643 ControlActions::DELETE_ITEMS, aValue );
645 catch( const IllegalArgumentException& ){}
647 sal_Int32 nCount = aEntries.getLength();
649 if ( nCount )
653 aValue <<= aEntries;
654 xDlg->setValue( ExtendedFilePickerElementIds::LISTBOX_VERSION,
655 ControlActions::ADD_ITEMS, aValue );
657 Any aPos;
658 aPos <<= (sal_Int32) 0;
659 xDlg->setValue( ExtendedFilePickerElementIds::LISTBOX_VERSION,
660 ControlActions::SET_SELECT_ITEM, aPos );
662 catch( const IllegalArgumentException& ){}
666 IMPL_LINK_NOARG_TYPED(FileDialogHelper_Impl, TimeOutHdl_Impl, Idle *, void)
668 if ( !mbHasPreview )
669 return;
671 maGraphic.Clear();
673 Any aAny;
674 uno::Reference < XFilePreview > xFilePicker( mxFileDlg, UNO_QUERY );
676 if ( ! xFilePicker.is() )
677 return;
679 Sequence < OUString > aPathSeq = mxFileDlg->getFiles();
681 if ( mbShowPreview && ( aPathSeq.getLength() == 1 ) )
683 OUString aURL = aPathSeq[0];
685 if ( ERRCODE_NONE == getGraphic( aURL, maGraphic ) )
687 // changed the code slightly;
688 // before: the bitmap was scaled and
689 // surrounded a white frame
690 // now: the bitmap will only be scaled
691 // and the filepicker implementation
692 // is responsible for placing it at its
693 // proper position and painting a frame
695 Bitmap aBmp = maGraphic.GetBitmap();
696 if ( !aBmp.IsEmpty() )
698 // scale the bitmap to the correct size
699 sal_Int32 nOutWidth = xFilePicker->getAvailableWidth();
700 sal_Int32 nOutHeight = xFilePicker->getAvailableHeight();
701 sal_Int32 nBmpWidth = aBmp.GetSizePixel().Width();
702 sal_Int32 nBmpHeight = aBmp.GetSizePixel().Height();
704 double nXRatio = (double) nOutWidth / nBmpWidth;
705 double nYRatio = (double) nOutHeight / nBmpHeight;
707 if ( nXRatio < nYRatio )
708 aBmp.Scale( nXRatio, nXRatio );
709 else
710 aBmp.Scale( nYRatio, nYRatio );
712 // Convert to true color, to allow CopyPixel
713 aBmp.Convert( BMP_CONVERSION_24BIT );
715 // and copy it into the Any
716 SvMemoryStream aData;
718 WriteDIB(aBmp, aData, false, true);
720 const Sequence < sal_Int8 > aBuffer(
721 static_cast< const sal_Int8* >(aData.GetData()),
722 aData.GetEndOfData() );
724 aAny <<= aBuffer;
731 SolarMutexReleaser aReleaseForCallback;
732 // clear the preview window
733 xFilePicker->setImage( FilePreviewImageFormats::BITMAP, aAny );
735 catch( const IllegalArgumentException& )
740 ErrCode FileDialogHelper_Impl::getGraphic( const OUString& rURL,
741 Graphic& rGraphic ) const
743 if ( utl::UCBContentHelper::IsFolder( rURL ) )
744 return ERRCODE_IO_NOTAFILE;
746 if ( !mpGraphicFilter )
747 return ERRCODE_IO_NOTSUPPORTED;
749 // select graphic filter from dialog filter selection
750 OUString aCurFilter( getFilter() );
752 sal_uInt16 nFilter = !aCurFilter.isEmpty() && mpGraphicFilter->GetImportFormatCount()
753 ? mpGraphicFilter->GetImportFormatNumber( aCurFilter )
754 : GRFILTER_FORMAT_DONTKNOW;
756 INetURLObject aURLObj( rURL );
758 if ( aURLObj.HasError() || INetProtocol::NotValid == aURLObj.GetProtocol() )
760 aURLObj.SetSmartProtocol( INetProtocol::File );
761 aURLObj.SetSmartURL( rURL );
764 ErrCode nRet = ERRCODE_NONE;
766 GraphicFilterImportFlags nFilterImportFlags = GraphicFilterImportFlags::SetLogsizeForJpeg;
767 // non-local?
768 if ( INetProtocol::File != aURLObj.GetProtocol() )
770 SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( rURL, StreamMode::READ );
772 if( pStream )
773 nRet = mpGraphicFilter->ImportGraphic( rGraphic, rURL, *pStream, nFilter, NULL, nFilterImportFlags );
774 else
775 nRet = mpGraphicFilter->ImportGraphic( rGraphic, aURLObj, nFilter, NULL, nFilterImportFlags );
776 delete pStream;
778 else
780 nRet = mpGraphicFilter->ImportGraphic( rGraphic, aURLObj, nFilter, NULL, nFilterImportFlags );
783 return nRet;
786 ErrCode FileDialogHelper_Impl::getGraphic( Graphic& rGraphic ) const
788 ErrCode nRet = ERRCODE_NONE;
790 // rhbz#1079672 do not return maGraphic, it need not be the selected file
792 OUString aPath;;
793 Sequence<OUString> aPathSeq = mxFileDlg->getFiles();
795 if (aPathSeq.getLength() == 1)
797 aPath = aPathSeq[0];
800 if (!aPath.isEmpty())
801 nRet = getGraphic(aPath, rGraphic);
802 else
803 nRet = ERRCODE_IO_GENERAL;
805 return nRet;
808 static bool lcl_isSystemFilePicker( const uno::Reference< XFilePicker >& _rxFP )
812 uno::Reference< XServiceInfo > xSI( _rxFP, UNO_QUERY );
813 if ( !xSI.is() )
814 return true;
815 return xSI->supportsService( "com.sun.star.ui.dialogs.SystemFilePicker" );
817 catch( const Exception& )
820 return false;
823 enum open_or_save_t {OPEN, SAVE, UNDEFINED};
824 static open_or_save_t lcl_OpenOrSave(sal_Int16 const nDialogType)
826 switch (nDialogType)
828 case FILEOPEN_SIMPLE:
829 case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE:
830 case FILEOPEN_PLAY:
831 case FILEOPEN_READONLY_VERSION:
832 case FILEOPEN_LINK_PREVIEW:
833 return OPEN;
834 case FILESAVE_SIMPLE:
835 case FILESAVE_AUTOEXTENSION_PASSWORD:
836 case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS:
837 case FILESAVE_AUTOEXTENSION_SELECTION:
838 case FILESAVE_AUTOEXTENSION_TEMPLATE:
839 case FILESAVE_AUTOEXTENSION:
840 return SAVE;
841 default:
842 assert(false); // invalid dialog type
844 return UNDEFINED;
847 // FileDialogHelper_Impl
849 FileDialogHelper_Impl::FileDialogHelper_Impl(
850 FileDialogHelper* _pAntiImpl,
851 sal_Int16 nDialogType,
852 sal_Int64 nFlags,
853 sal_Int16 nDialog,
854 vcl::Window* _pPreferredParentWindow,
855 const OUString& sStandardDir,
856 const ::com::sun::star::uno::Sequence< OUString >& rBlackList
858 :m_nDialogType ( nDialogType )
859 ,meContext ( FileDialogHelper::UNKNOWN_CONTEXT )
861 const char* pServiceName=0;
862 if ( nDialog == SFX2_IMPL_DIALOG_SYSTEM )
863 pServiceName = FILE_OPEN_SERVICE_NAME_OOO;
864 else if ( nDialog == SFX2_IMPL_DIALOG_OOO )
865 pServiceName = FILE_OPEN_SERVICE_NAME_OOO;
866 else
867 pServiceName = "com.sun.star.ui.dialogs.FilePicker";
868 OUString aService = OUString::createFromAscii( pServiceName );
870 uno::Reference< XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
872 // create the file open dialog
873 // the flags can be SFXWB_INSERT or SFXWB_MULTISELECTION
875 mpPreferredParentWindow = _pPreferredParentWindow;
876 mpAntiImpl = _pAntiImpl;
877 mnError = ERRCODE_NONE;
878 mbHasAutoExt = false;
879 mbHasPassword = false;
880 m_bHaveFilterOptions = false;
881 mbIsPwdEnabled = true;
882 mbHasVersions = false;
883 mbHasPreview = false;
884 mbShowPreview = false;
885 mbAddGraphicFilter = SFXWB_GRAPHIC == (nFlags & SFXWB_GRAPHIC);
886 mbDeleteMatcher = false;
887 mbInsert = SFXWB_INSERT == ( nFlags & SFXWB_INSERT );
888 mbExport = SFXWB_EXPORT == ( nFlags & SFXWB_EXPORT );
889 mbIsSaveDlg = false;
890 mbIsSaveACopyDlg = SFXWB_SAVEACOPY == ( nFlags & SFXWB_SAVEACOPY );
891 mbPwdCheckBoxState = false;
892 mbSelection = false;
893 mbSelectionEnabled = true;
894 mbHasSelectionBox = false;
895 mbSelectionFltrEnabled = false;
897 // default settings
898 m_nDontFlags = SFX_FILTER_NOTINSTALLED | SfxFilterFlags::INTERNAL | SfxFilterFlags::NOTINFILEDLG;
899 if (OPEN == lcl_OpenOrSave(m_nDialogType))
900 m_nMustFlags = SfxFilterFlags::IMPORT;
901 else
902 m_nMustFlags = SfxFilterFlags::EXPORT;
905 mpMatcher = NULL;
906 mpGraphicFilter = NULL;
907 mnPostUserEventId = 0;
909 // create the picker component
910 mxFileDlg.set(xFactory->createInstance( aService ), css::uno::UNO_QUERY);
911 mbSystemPicker = lcl_isSystemFilePicker( mxFileDlg );
913 uno::Reference< XFilePickerNotifier > xNotifier( mxFileDlg, UNO_QUERY );
914 uno::Reference< XInitialization > xInit( mxFileDlg, UNO_QUERY );
916 if ( ! mxFileDlg.is() || ! xNotifier.is() )
918 mnError = ERRCODE_ABORT;
919 return;
923 if ( xInit.is() )
925 sal_Int16 nTemplateDescription = TemplateDescription::FILEOPEN_SIMPLE;
927 switch ( m_nDialogType )
929 case FILEOPEN_SIMPLE:
930 nTemplateDescription = TemplateDescription::FILEOPEN_SIMPLE;
931 break;
933 case FILESAVE_SIMPLE:
934 nTemplateDescription = TemplateDescription::FILESAVE_SIMPLE;
935 mbIsSaveDlg = true;
936 break;
938 case FILESAVE_AUTOEXTENSION_PASSWORD:
939 nTemplateDescription = TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD;
940 mbHasPassword = true;
941 mbHasAutoExt = true;
942 mbIsSaveDlg = true;
943 break;
945 case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS:
946 nTemplateDescription = TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS;
947 mbHasPassword = true;
949 m_bHaveFilterOptions = true;
950 if( xFactory.is() )
952 mxFilterCFG = uno::Reference< XNameAccess >(
953 xFactory->createInstance( "com.sun.star.document.FilterFactory" ),
954 UNO_QUERY );
957 mbHasAutoExt = true;
958 mbIsSaveDlg = true;
959 break;
961 case FILESAVE_AUTOEXTENSION_SELECTION:
962 nTemplateDescription = TemplateDescription::FILESAVE_AUTOEXTENSION_SELECTION;
963 mbHasAutoExt = true;
964 mbIsSaveDlg = true;
965 mbHasSelectionBox = true;
966 if ( mbExport && !mxFilterCFG.is() && xFactory.is() )
968 mxFilterCFG = uno::Reference< XNameAccess >(
969 xFactory->createInstance( "com.sun.star.document.FilterFactory" ),
970 UNO_QUERY );
972 break;
974 case FILESAVE_AUTOEXTENSION_TEMPLATE:
975 nTemplateDescription = TemplateDescription::FILESAVE_AUTOEXTENSION_TEMPLATE;
976 mbHasAutoExt = true;
977 mbIsSaveDlg = true;
978 break;
980 case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE:
981 nTemplateDescription = TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE;
982 mbHasPreview = true;
984 // aPreviewTimer
985 maPreviewIdle.SetPriority( SchedulerPriority::LOWEST );
986 maPreviewIdle.SetIdleHdl( LINK( this, FileDialogHelper_Impl, TimeOutHdl_Impl ) );
987 break;
989 case FILEOPEN_PLAY:
990 nTemplateDescription = TemplateDescription::FILEOPEN_PLAY;
991 break;
993 case FILEOPEN_READONLY_VERSION:
994 nTemplateDescription = TemplateDescription::FILEOPEN_READONLY_VERSION;
995 mbHasVersions = true;
996 break;
998 case FILEOPEN_LINK_PREVIEW:
999 nTemplateDescription = TemplateDescription::FILEOPEN_LINK_PREVIEW;
1000 mbHasPreview = true;
1001 // aPreviewTimer
1002 maPreviewIdle.SetPriority( SchedulerPriority::LOWEST );
1003 maPreviewIdle.SetIdleHdl( LINK( this, FileDialogHelper_Impl, TimeOutHdl_Impl ) );
1004 break;
1006 case FILESAVE_AUTOEXTENSION:
1007 nTemplateDescription = TemplateDescription::FILESAVE_AUTOEXTENSION;
1008 mbHasAutoExt = true;
1009 mbIsSaveDlg = true;
1010 break;
1012 default:
1013 SAL_WARN( "sfx.dialog", "FileDialogHelper::ctor with unknown type" );
1014 break;
1017 Sequence < Any > aInitArguments( !mpPreferredParentWindow ? 3 : 4 );
1019 // This is a hack. We currently know that the internal file picker implementation
1020 // supports the extended arguments as specified below.
1021 // TODO:
1022 // a) adjust the service description so that it includes the TemplateDescription and ParentWindow args
1023 // b) adjust the implementation of the system file picker to that it recognizes it
1024 if ( mbSystemPicker )
1026 aInitArguments[0] <<= nTemplateDescription;
1028 else
1030 aInitArguments[0] <<= NamedValue(
1031 OUString( "TemplateDescription" ),
1032 makeAny( nTemplateDescription )
1035 OUString sStandardDirTemp = sStandardDir;
1037 aInitArguments[1] <<= NamedValue(
1038 OUString( "StandardDir" ),
1039 makeAny( sStandardDirTemp )
1042 aInitArguments[2] <<= NamedValue(
1043 OUString( "BlackList" ),
1044 makeAny( rBlackList )
1048 if ( mpPreferredParentWindow )
1049 aInitArguments[3] <<= NamedValue(
1050 OUString( "ParentWindow" ),
1051 makeAny( VCLUnoHelper::GetInterface( mpPreferredParentWindow ) )
1057 xInit->initialize( aInitArguments );
1059 catch( const Exception& )
1061 OSL_FAIL( "FileDialogHelper_Impl::FileDialogHelper_Impl: could not initialize the picker!" );
1066 // set multiselection mode
1067 if ( nFlags & SFXWB_MULTISELECTION )
1068 mxFileDlg->setMultiSelectionMode( sal_True );
1070 if (mbAddGraphicFilter) // generate graphic filter only on demand
1072 addGraphicFilter();
1075 // Export dialog
1076 if ( mbExport )
1078 mxFileDlg->setTitle( SfxResId( STR_SFX_EXPLORERFILE_EXPORT ).toString() );
1079 try {
1080 com::sun::star::uno::Reference < XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY_THROW );
1081 xCtrlAccess->enableControl( ExtendedFilePickerElementIds::LISTBOX_FILTER_SELECTOR, sal_True );
1083 catch( const Exception & ) { }
1086 // Save a copy dialog
1087 if ( mbIsSaveACopyDlg )
1089 mxFileDlg->setTitle( SfxResId( STR_PB_SAVEACOPY ).toString() );
1092 // the "insert file" dialog needs another title
1093 if ( mbInsert )
1095 mxFileDlg->setTitle( SfxResId( STR_SFX_EXPLORERFILE_INSERT ).toString() );
1096 uno::Reference < XFilePickerControlAccess > xExtDlg( mxFileDlg, UNO_QUERY );
1097 if ( xExtDlg.is() )
1101 xExtDlg->setLabel( CommonFilePickerElementIds::PUSHBUTTON_OK,
1102 SfxResId( STR_SFX_EXPLORERFILE_BUTTONINSERT ).toString() );
1104 catch( const IllegalArgumentException& ){}
1108 // add the event listener
1109 xNotifier->addFilePickerListener( this );
1112 FileDialogHelper_Impl::~FileDialogHelper_Impl()
1114 // Remove user event if we haven't received it yet
1115 if ( mnPostUserEventId )
1116 Application::RemoveUserEvent( mnPostUserEventId );
1117 mnPostUserEventId = 0;
1119 delete mpGraphicFilter;
1121 if ( mbDeleteMatcher )
1122 delete mpMatcher;
1124 maPreviewIdle.SetIdleHdl( Link<Idle *, void>() );
1126 ::comphelper::disposeComponent( mxFileDlg );
1129 void FileDialogHelper_Impl::setControlHelpIds( const sal_Int16* _pControlId, const char** _pHelpId )
1131 DBG_ASSERT( _pControlId && _pHelpId, "FileDialogHelper_Impl::setControlHelpIds: invalid array pointers!" );
1132 if ( !_pControlId || !_pHelpId )
1133 return;
1135 // forward these ids to the file picker
1138 const OUString sHelpIdPrefix( INET_HID_SCHEME );
1139 // the ids for the single controls
1140 uno::Reference< XFilePickerControlAccess > xControlAccess( mxFileDlg, UNO_QUERY );
1141 if ( xControlAccess.is() )
1143 while ( *_pControlId )
1145 DBG_ASSERT( INetURLObject( OStringToOUString( *_pHelpId, RTL_TEXTENCODING_UTF8 ) ).GetProtocol() == INetProtocol::NotValid, "Wrong HelpId!" );
1146 OUString sId( sHelpIdPrefix );
1147 sId += OUString( *_pHelpId, strlen( *_pHelpId ), RTL_TEXTENCODING_UTF8 );
1148 xControlAccess->setValue( *_pControlId, ControlActions::SET_HELP_URL, makeAny( sId ) );
1150 ++_pControlId; ++_pHelpId;
1154 catch( const Exception& )
1156 OSL_FAIL( "FileDialogHelper_Impl::setControlHelpIds: caught an exception while setting the help ids!" );
1160 IMPL_LINK_NOARG( FileDialogHelper_Impl, InitControls )
1162 mnPostUserEventId = 0;
1163 enablePasswordBox( true );
1164 updateFilterOptionsBox( );
1165 updateSelectionBox( );
1167 return 0L;
1170 void FileDialogHelper_Impl::preExecute()
1172 loadConfig( );
1173 setDefaultValues( );
1174 updatePreviewState( false );
1176 implInitializeFileName( );
1178 #if !(defined(MACOSX) && defined(MACOSX)) && !defined(WNT)
1179 // allow for dialog implementations which need to be executed before they return valid values for
1180 // current filter and such
1182 // On Vista (at least SP1) it's the same as on MacOSX, the modal dialog won't let message pass
1183 // through before it returns from execution
1184 mnPostUserEventId = Application::PostUserEvent( LINK( this, FileDialogHelper_Impl, InitControls ) );
1185 #else
1186 // However, the Mac OS X implementation's pickers run modally in execute and so the event doesn't
1187 // get through in time... so we call the methods directly
1188 enablePasswordBox( true );
1189 updateFilterOptionsBox( );
1190 updateSelectionBox( );
1191 #endif
1194 void FileDialogHelper_Impl::postExecute( sal_Int16 _nResult )
1196 if ( ExecutableDialogResults::CANCEL != _nResult )
1197 saveConfig();
1200 void FileDialogHelper_Impl::implInitializeFileName( )
1202 if ( !maFileName.isEmpty() )
1204 INetURLObject aObj( maPath );
1205 aObj.Append( maFileName );
1207 // in case we're operating as save dialog, and "auto extension" is checked,
1208 // cut the extension from the name
1209 if ( mbIsSaveDlg && mbHasAutoExt )
1213 bool bAutoExtChecked = false;
1215 uno::Reference < XFilePickerControlAccess > xControlAccess( mxFileDlg, UNO_QUERY );
1216 if ( xControlAccess.is()
1217 && ( xControlAccess->getValue( ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, 0 )
1218 >>= bAutoExtChecked
1222 if ( bAutoExtChecked )
1223 { // cut the extension
1224 aObj.removeExtension( );
1225 mxFileDlg->setDefaultName( aObj.GetName( INetURLObject::DECODE_WITH_CHARSET ) );
1229 catch( const Exception& )
1231 OSL_FAIL( "FileDialogHelper_Impl::implInitializeFileName: could not ask for the auto-extension current-value!" );
1237 sal_Int16 FileDialogHelper_Impl::implDoExecute()
1239 preExecute();
1241 sal_Int16 nRet = ExecutableDialogResults::CANCEL;
1243 //On MacOSX the native file picker has to run in the primordial thread because of drawing issues
1244 //On Linux the native gtk file picker, when backed by gnome-vfs2, needs to be run in the same
1245 //primordial thread as the ucb gnome-vfs2 provider was initialized in.
1250 #ifdef WNT
1251 if ( mbSystemPicker )
1253 SolarMutexReleaser aSolarMutex;
1254 nRet = mxFileDlg->execute();
1256 else
1257 #endif
1258 nRet = mxFileDlg->execute();
1260 catch( const Exception& )
1262 SAL_WARN( "sfx.dialog", "FileDialogHelper_Impl::implDoExecute: caught an exception!" );
1266 postExecute( nRet );
1268 return nRet;
1271 void FileDialogHelper_Impl::implStartExecute()
1273 DBG_ASSERT( mxFileDlg.is(), "invalid file dialog" );
1275 preExecute();
1277 if ( mbSystemPicker )
1280 else
1284 uno::Reference< XAsynchronousExecutableDialog > xAsyncDlg( mxFileDlg, UNO_QUERY );
1285 if ( xAsyncDlg.is() )
1286 xAsyncDlg->startExecuteModal( this );
1288 catch( const Exception& )
1290 SAL_WARN( "sfx.dialog", "FileDialogHelper_Impl::implDoExecute: caught an exception!" );
1295 void lcl_saveLastURLs(std::vector<OUString>& rpURLList,
1296 ::std::vector< OUString >& lLastURLs )
1298 lLastURLs.clear();
1299 for(std::vector<OUString>::iterator i = rpURLList.begin(); i != rpURLList.end(); ++i)
1300 lLastURLs.push_back(*i);
1303 void FileDialogHelper_Impl::implGetAndCacheFiles(const uno::Reference< XInterface >& xPicker, std::vector<OUString>& rpURLList, const SfxFilter* pFilter)
1305 rpURLList.clear();
1307 OUString sExtension;
1308 if (pFilter)
1310 sExtension = pFilter->GetDefaultExtension ();
1311 sExtension = comphelper::string::remove(sExtension, '*');
1312 sExtension = comphelper::string::remove(sExtension, '.');
1315 // a) the new way (optional!)
1316 uno::Reference< XFilePicker2 > xPickNew(xPicker, UNO_QUERY);
1317 if (xPickNew.is())
1319 Sequence< OUString > lFiles = xPickNew->getSelectedFiles();
1320 ::sal_Int32 nFiles = lFiles.getLength();
1321 for(sal_Int32 i = 0; i < nFiles; ++i)
1322 rpURLList.push_back(lFiles[i]);
1325 // b) the olde way ... non optional.
1326 else
1328 uno::Reference< XFilePicker > xPickOld(xPicker, UNO_QUERY_THROW);
1329 Sequence< OUString > lFiles = xPickOld->getFiles();
1330 ::sal_Int32 nFiles = lFiles.getLength();
1331 if ( nFiles == 1 )
1333 rpURLList.push_back(lFiles[0]);
1335 else if ( nFiles > 1 )
1337 INetURLObject aPath( lFiles[0] );
1338 aPath.setFinalSlash();
1340 for (::sal_Int32 i = 1; i < nFiles; i++)
1342 if (i == 1)
1343 aPath.Append( lFiles[i] );
1344 else
1345 aPath.setName( lFiles[i] );
1347 rpURLList.push_back(aPath.GetMainURL(INetURLObject::NO_DECODE));
1352 lcl_saveLastURLs(rpURLList, mlLastURLs);
1355 ErrCode FileDialogHelper_Impl::execute( std::vector<OUString>& rpURLList,
1356 SfxItemSet *& rpSet,
1357 OUString& rFilter )
1359 // rFilter is a pure output parameter, it shouldn't be used for anything else
1360 // changing this would surely break code
1361 // rpSet is in/out parameter, usually just a media-descriptor that can be changed by dialog
1363 uno::Reference< XFilePickerControlAccess > xCtrlAccess( mxFileDlg, UNO_QUERY );
1365 // retrieves parameters from rpSet
1366 // for now only Password is used
1367 if ( rpSet )
1369 // check password checkbox if the document had password before
1370 if( mbHasPassword )
1372 SFX_ITEMSET_ARG( rpSet, pPassItem, SfxBoolItem, SID_PASSWORDINTERACTION, false );
1373 mbPwdCheckBoxState = ( pPassItem != NULL && pPassItem->GetValue() );
1375 // in case the document has password to modify, the dialog should be shown
1376 SFX_ITEMSET_ARG( rpSet, pPassToModifyItem, SfxUnoAnyItem, SID_MODIFYPASSWORDINFO, false );
1377 mbPwdCheckBoxState |= ( pPassToModifyItem && pPassToModifyItem->GetValue().hasValue() );
1380 SFX_ITEMSET_ARG( rpSet, pSelectItem, SfxBoolItem, SID_SELECTION, false );
1381 if ( pSelectItem )
1382 mbSelection = pSelectItem->GetValue();
1383 else
1384 mbSelectionEnabled = false;
1386 // the password will be set in case user decide so
1387 rpSet->ClearItem( SID_PASSWORDINTERACTION );
1388 rpSet->ClearItem( SID_PASSWORD );
1389 rpSet->ClearItem( SID_ENCRYPTIONDATA );
1390 rpSet->ClearItem( SID_RECOMMENDREADONLY );
1391 rpSet->ClearItem( SID_MODIFYPASSWORDINFO );
1395 if ( mbHasPassword && !mbPwdCheckBoxState )
1397 SvtSecurityOptions aSecOpt;
1398 mbPwdCheckBoxState = (
1399 aSecOpt.IsOptionSet( SvtSecurityOptions::E_DOCWARN_RECOMMENDPASSWORD ) );
1402 rpURLList.clear();
1404 if ( ! mxFileDlg.is() )
1405 return ERRCODE_ABORT;
1407 if ( ExecutableDialogResults::CANCEL != implDoExecute() )
1409 // create an itemset if there is no
1410 if( !rpSet )
1411 rpSet = new SfxAllItemSet( SfxGetpApp()->GetPool() );
1413 // the item should remain only if it was set by the dialog
1414 rpSet->ClearItem( SID_SELECTION );
1416 if( mbExport && mbHasSelectionBox )
1420 Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::CHECKBOX_SELECTION, 0 );
1421 bool bSelection = false;
1422 if ( aValue >>= bSelection )
1423 rpSet->Put( SfxBoolItem( SID_SELECTION, bSelection ) );
1425 catch( const IllegalArgumentException& )
1427 OSL_FAIL( "FileDialogHelper_Impl::execute: caught an IllegalArgumentException!" );
1432 // set the read-only flag. When inserting a file, this flag is always set
1433 if ( mbInsert )
1434 rpSet->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
1435 else
1437 if ( ( FILEOPEN_READONLY_VERSION == m_nDialogType ) && xCtrlAccess.is() )
1441 Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::CHECKBOX_READONLY, 0 );
1442 bool bReadOnly = false;
1443 if ( ( aValue >>= bReadOnly ) && bReadOnly )
1444 rpSet->Put( SfxBoolItem( SID_DOC_READONLY, bReadOnly ) );
1446 catch( const IllegalArgumentException& )
1448 OSL_FAIL( "FileDialogHelper_Impl::execute: caught an IllegalArgumentException!" );
1452 if ( mbHasVersions && xCtrlAccess.is() )
1456 Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::LISTBOX_VERSION,
1457 ControlActions::GET_SELECTED_ITEM_INDEX );
1458 sal_Int32 nVersion = 0;
1459 if ( ( aValue >>= nVersion ) && nVersion > 0 )
1460 // open a special version; 0 == current version
1461 rpSet->Put( SfxInt16Item( SID_VERSION, (short)nVersion ) );
1463 catch( const IllegalArgumentException& ){}
1466 // set the filter
1467 getRealFilter( rFilter );
1469 const SfxFilter* pCurrentFilter = getCurentSfxFilter();
1471 // fill the rpURLList
1472 implGetAndCacheFiles( mxFileDlg, rpURLList, pCurrentFilter );
1473 if ( rpURLList.empty() )
1474 return ERRCODE_ABORT;
1476 // check, whether or not we have to display a password box
1477 if ( pCurrentFilter && mbHasPassword && mbIsPwdEnabled && xCtrlAccess.is() )
1481 Any aValue = xCtrlAccess->getValue( ExtendedFilePickerElementIds::CHECKBOX_PASSWORD, 0 );
1482 bool bPassWord = false;
1483 if ( ( aValue >>= bPassWord ) && bPassWord )
1485 // ask for a password
1486 OUString aDocName(rpURLList[0]);
1487 ErrCode errCode = RequestPassword(pCurrentFilter, aDocName, rpSet);
1488 if (errCode != ERRCODE_NONE)
1489 return errCode;
1492 catch( const IllegalArgumentException& ){}
1495 SaveLastUsedFilter();
1496 return ERRCODE_NONE;
1498 else
1499 return ERRCODE_ABORT;
1502 ErrCode FileDialogHelper_Impl::execute()
1504 if ( ! mxFileDlg.is() )
1505 return ERRCODE_ABORT;
1507 sal_Int16 nRet = implDoExecute();
1509 maPath = mxFileDlg->getDisplayDirectory();
1511 if ( ExecutableDialogResults::CANCEL == nRet )
1512 return ERRCODE_ABORT;
1513 else
1515 return ERRCODE_NONE;
1519 OUString FileDialogHelper_Impl::getPath() const
1521 OUString aPath;
1523 if ( mxFileDlg.is() )
1524 aPath = mxFileDlg->getDisplayDirectory();
1526 if ( aPath.isEmpty() )
1527 aPath = maPath;
1529 return aPath;
1532 OUString FileDialogHelper_Impl::getFilter() const
1534 OUString aFilter = getCurrentFilterUIName();
1536 if( aFilter.isEmpty() )
1537 aFilter = maCurFilter;
1539 return aFilter;
1542 void FileDialogHelper_Impl::getRealFilter( OUString& _rFilter ) const
1544 _rFilter = getCurrentFilterUIName();
1546 if ( _rFilter.isEmpty() )
1547 _rFilter = maCurFilter;
1549 if ( !_rFilter.isEmpty() && mpMatcher )
1551 const SfxFilter* pFilter =
1552 mpMatcher->GetFilter4UIName( _rFilter, m_nMustFlags, m_nDontFlags );
1553 _rFilter = pFilter ? pFilter->GetFilterName() : OUString("");
1557 void FileDialogHelper_Impl::verifyPath()
1559 #ifdef UNX
1560 // lp#905355, fdo#43895
1561 // Check that the file has read only permission and is in /tmp -- this is
1562 // the case if we have opened the file from the web with firefox only.
1563 if (maFileName.isEmpty()) {
1564 return;
1566 INetURLObject url(maPath);
1567 if (url.GetProtocol() != INetProtocol::File
1568 || url.getName(0, true, INetURLObject::DECODE_WITH_CHARSET) != "tmp")
1570 return;
1572 if (maFileName.indexOf('/') != -1) {
1573 SAL_WARN("sfx.dialog", maFileName << " contains /");
1574 return;
1576 url.insertName(
1577 maFileName, false, INetURLObject::LAST_SEGMENT, true,
1578 INetURLObject::ENCODE_ALL);
1579 OUString sysPathU;
1580 osl::FileBase::RC e = osl::FileBase::getSystemPathFromFileURL(
1581 url.GetMainURL(INetURLObject::NO_DECODE), sysPathU);
1582 if (e != osl::FileBase::E_None) {
1583 SAL_WARN(
1584 "sfx.dialog",
1585 "getSystemPathFromFileURL("
1586 << url.GetMainURL(INetURLObject::NO_DECODE) << ") failed with "
1587 << +e);
1588 return;
1590 OString sysPathC;
1591 if (!sysPathU.convertToString(
1592 &sysPathC, osl_getThreadTextEncoding(),
1593 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
1594 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
1596 SAL_WARN(
1597 "sfx.dialog",
1598 "convertToString(" << sysPathU << ") failed for encoding "
1599 << +osl_getThreadTextEncoding());
1600 return;
1602 struct stat aFileStat;
1603 if (stat(sysPathC.getStr(), &aFileStat) == -1) {
1604 SAL_WARN(
1605 "sfx.dialog",
1606 "stat(" << sysPathC.getStr() << ") failed with errno " << errno);
1607 return;
1609 if ((aFileStat.st_mode & (S_IRWXO | S_IRWXG | S_IRWXU)) == S_IRUSR) {
1610 maPath = SvtPathOptions().GetWorkPath();
1611 mxFileDlg->setDisplayDirectory( maPath );
1613 #endif
1616 void FileDialogHelper_Impl::displayFolder( const OUString& _rPath )
1618 if ( _rPath.isEmpty() )
1619 // nothing to do
1620 return;
1622 maPath = _rPath;
1623 if ( mxFileDlg.is() )
1627 mxFileDlg->setDisplayDirectory( maPath );
1628 verifyPath();
1630 catch( const IllegalArgumentException& )
1632 OSL_FAIL( "FileDialogHelper_Impl::displayFolder: caught an exception!" );
1637 void FileDialogHelper_Impl::setFileName( const OUString& _rFile )
1639 maFileName = _rFile;
1640 if ( mxFileDlg.is() )
1644 mxFileDlg->setDefaultName( maFileName );
1645 verifyPath();
1647 catch( const IllegalArgumentException& )
1649 OSL_FAIL( "FileDialogHelper_Impl::setFileName: caught an exception!" );
1654 void FileDialogHelper_Impl::setFilter( const OUString& rFilter )
1656 DBG_ASSERT( rFilter.indexOf(':') == -1, "Old filter name used!");
1658 maCurFilter = rFilter;
1660 if ( !rFilter.isEmpty() && mpMatcher )
1662 const SfxFilter* pFilter = mpMatcher->GetFilter4FilterName(
1663 rFilter, m_nMustFlags, m_nDontFlags );
1664 if ( pFilter )
1665 maCurFilter = pFilter->GetUIName();
1668 uno::Reference< XFilterManager > xFltMgr( mxFileDlg, UNO_QUERY );
1670 if ( !maCurFilter.isEmpty() && xFltMgr.is() )
1674 xFltMgr->setCurrentFilter( maCurFilter );
1676 catch( const IllegalArgumentException& ){}
1680 void FileDialogHelper_Impl::createMatcher( const OUString& rFactory )
1682 if (mbDeleteMatcher)
1683 delete mpMatcher;
1685 mpMatcher = new SfxFilterMatcher( SfxObjectShell::GetServiceNameFromFactory(rFactory) );
1686 mbDeleteMatcher = true;
1689 void FileDialogHelper_Impl::addFilters( const OUString& rFactory,
1690 SfxFilterFlags nMust,
1691 SfxFilterFlags nDont )
1693 uno::Reference< XFilterManager > xFltMgr( mxFileDlg, UNO_QUERY );
1695 if ( ! xFltMgr.is() )
1696 return;
1698 if (mbDeleteMatcher)
1699 delete mpMatcher;
1701 // we still need a matcher to convert UI names to filter names
1702 if ( rFactory.isEmpty() )
1704 SfxApplication *pSfxApp = SfxGetpApp();
1705 mpMatcher = &pSfxApp->GetFilterMatcher();
1706 mbDeleteMatcher = false;
1708 else
1710 mpMatcher = new SfxFilterMatcher( rFactory );
1711 mbDeleteMatcher = true;
1714 uno::Reference< XMultiServiceFactory > xSMGR = ::comphelper::getProcessServiceFactory();
1715 uno::Reference< XContainerQuery > xFilterCont(
1716 xSMGR->createInstance("com.sun.star.document.FilterFactory"),
1717 UNO_QUERY);
1718 if ( ! xFilterCont.is() )
1719 return;
1721 m_nMustFlags |= nMust;
1722 m_nDontFlags |= nDont;
1724 // create the list of filters
1725 OUStringBuffer sQuery(256);
1726 sQuery.append("getSortedFilterList()");
1727 sQuery.append(":module=");
1728 sQuery.append(rFactory); // use long name here !
1729 sQuery.append(":iflags=");
1730 sQuery.append(OUString::number(static_cast<sal_Int32>(m_nMustFlags)));
1731 sQuery.append(":eflags=");
1732 sQuery.append(OUString::number(static_cast<sal_Int32>(m_nDontFlags)));
1734 uno::Reference< XEnumeration > xResult;
1737 xResult = xFilterCont->createSubSetEnumerationByQuery(sQuery.makeStringAndClear());
1739 catch( const uno::Exception& )
1741 SAL_WARN( "sfx.dialog", "Could not get filters from the configuration!" );
1744 TSortedFilterList aIter (xResult);
1746 // append the filters
1747 OUString sFirstFilter;
1748 if (OPEN == lcl_OpenOrSave(m_nDialogType))
1749 ::sfx2::appendFiltersForOpen( aIter, xFltMgr, sFirstFilter, *this );
1750 else if ( mbExport )
1751 ::sfx2::appendExportFilters( aIter, xFltMgr, sFirstFilter, *this );
1752 else
1753 ::sfx2::appendFiltersForSave( aIter, xFltMgr, sFirstFilter, *this, rFactory );
1755 // set our initial selected filter (if we do not already have one)
1756 if ( maSelectFilter.isEmpty() )
1757 maSelectFilter = sFirstFilter;
1760 void FileDialogHelper_Impl::addFilter( const OUString& rFilterName,
1761 const OUString& rExtension )
1763 uno::Reference< XFilterManager > xFltMgr( mxFileDlg, UNO_QUERY );
1765 if ( ! xFltMgr.is() )
1766 return;
1770 xFltMgr->appendFilter( rFilterName, rExtension );
1772 if ( maSelectFilter.isEmpty() )
1773 maSelectFilter = rFilterName;
1775 catch( const IllegalArgumentException& )
1777 SAL_WARN( "sfx.dialog", "Could not append Filter" << rFilterName );
1781 void FileDialogHelper_Impl::addGraphicFilter()
1783 uno::Reference< XFilterManager > xFltMgr( mxFileDlg, UNO_QUERY );
1785 if ( ! xFltMgr.is() )
1786 return;
1788 // create the list of filters
1789 mpGraphicFilter = new GraphicFilter;
1790 sal_uInt16 i, j, nCount = mpGraphicFilter->GetImportFormatCount();
1792 // compute the extension string for all known import filters
1793 OUString aExtensions;
1795 for ( i = 0; i < nCount; i++ )
1797 j = 0;
1798 OUString sWildcard;
1799 while( true )
1801 sWildcard = mpGraphicFilter->GetImportWildcard( i, j++ );
1802 if ( sWildcard.isEmpty() )
1803 break;
1804 if ( aExtensions.indexOf( sWildcard ) == -1 )
1806 if ( !aExtensions.isEmpty() )
1807 aExtensions += ";";
1808 aExtensions += sWildcard;
1813 #if defined(WNT)
1814 if ( aExtensions.getLength() > 240 )
1815 aExtensions = FILEDIALOG_FILTER_ALL;
1816 #endif
1817 bool bIsInOpenMode = isInOpenMode();
1821 OUString aAllFilterName = SfxResId( STR_SFX_IMPORT_ALL ).toString();
1822 aAllFilterName = ::sfx2::addExtension( aAllFilterName, aExtensions, bIsInOpenMode, *this );
1824 xFltMgr->appendFilter( aAllFilterName, aExtensions );
1825 maSelectFilter = aAllFilterName;
1827 catch( const IllegalArgumentException& )
1829 SAL_WARN( "sfx.dialog", "Could not append Filter" );
1832 // Now add the filter
1833 for ( i = 0; i < nCount; i++ )
1835 OUString aName = mpGraphicFilter->GetImportFormatName( i );
1836 OUString aExt;
1837 j = 0;
1838 OUString sWildcard;
1839 while( true )
1841 sWildcard = mpGraphicFilter->GetImportWildcard( i, j++ );
1842 if ( sWildcard.isEmpty() )
1843 break;
1844 if ( aExt.indexOf( sWildcard ) == -1 )
1846 if ( !aExt.isEmpty() )
1847 aExt += ";";
1848 aExt += sWildcard;
1851 aName = ::sfx2::addExtension( aName, aExt, bIsInOpenMode, *this );
1854 xFltMgr->appendFilter( aName, aExt );
1856 catch( const IllegalArgumentException& )
1858 SAL_WARN( "sfx.dialog", "Could not append Filter" );
1863 #define GRF_CONFIG_STR " "
1864 #define STD_CONFIG_STR "1 "
1866 static void SetToken( OUString& rOrigStr, sal_Int32 nToken, sal_Unicode cTok, const OUString& rStr)
1868 const sal_Unicode* pStr = rOrigStr.getStr();
1869 sal_Int32 nLen = rOrigStr.getLength();
1870 sal_Int32 nTok = 0;
1871 sal_Int32 nFirstChar = 0;
1872 sal_Int32 i = nFirstChar;
1874 // Determine token position and length
1875 pStr += i;
1876 while ( i < nLen )
1878 // Increase token count if match
1879 if ( *pStr == cTok )
1881 ++nTok;
1883 if ( nTok == nToken )
1884 nFirstChar = i+1;
1885 else
1887 if ( nTok > nToken )
1888 break;
1892 ++pStr,
1893 ++i;
1896 if ( nTok >= nToken )
1897 rOrigStr = rOrigStr.replaceAt( nFirstChar, i-nFirstChar, rStr );
1901 void FileDialogHelper_Impl::saveConfig()
1903 uno::Reference < XFilePickerControlAccess > xDlg( mxFileDlg, UNO_QUERY );
1904 Any aValue;
1906 if ( ! xDlg.is() )
1907 return;
1909 if ( mbHasPreview )
1911 SvtViewOptions aDlgOpt( E_DIALOG, IMPGRF_CONFIGNAME );
1912 OUString aUserData(GRF_CONFIG_STR);
1916 aValue = xDlg->getValue( ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, 0 );
1917 bool bValue = false;
1918 aValue >>= bValue;
1919 SetToken( aUserData, 1, ' ', OUString::number( (sal_Int32) bValue ) );
1921 INetURLObject aObj( getPath() );
1923 if ( aObj.GetProtocol() == INetProtocol::File )
1924 SetToken( aUserData, 2, ' ', aObj.GetMainURL( INetURLObject::NO_DECODE ) );
1926 OUString aFilter = getFilter();
1927 aFilter = EncodeSpaces_Impl( aFilter );
1928 SetToken( aUserData, 3, ' ', aFilter );
1930 aDlgOpt.SetUserItem( USERITEM_NAME, makeAny( aUserData ) );
1932 catch( const IllegalArgumentException& ){}
1934 else
1936 bool bWriteConfig = false;
1937 SvtViewOptions aDlgOpt( E_DIALOG, IODLG_CONFIGNAME );
1938 OUString aUserData(STD_CONFIG_STR);
1940 if ( aDlgOpt.Exists() )
1942 Any aUserItem = aDlgOpt.GetUserItem( USERITEM_NAME );
1943 OUString aTemp;
1944 if ( aUserItem >>= aTemp )
1945 aUserData = aTemp;
1948 if ( mbHasAutoExt )
1952 aValue = xDlg->getValue( ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, 0 );
1953 bool bAutoExt = true;
1954 aValue >>= bAutoExt;
1955 SetToken( aUserData, 0, ' ', OUString::number( (sal_Int32) bAutoExt ) );
1956 bWriteConfig = true;
1958 catch( const IllegalArgumentException& ){}
1961 if ( ! mbIsSaveDlg )
1963 OUString aPath = getPath();
1964 if ( !aPath.isEmpty() &&
1965 utl::LocalFileHelper::IsLocalFile( aPath ) )
1967 SetToken( aUserData, 1, ' ', aPath );
1968 bWriteConfig = true;
1972 if( mbHasSelectionBox && mbSelectionFltrEnabled )
1976 aValue = xDlg->getValue( ExtendedFilePickerElementIds::CHECKBOX_SELECTION, 0 );
1977 bool bSelection = true;
1978 aValue >>= bSelection;
1979 if ( comphelper::string::getTokenCount(aUserData, ' ') < 3 )
1980 aUserData += " ";
1981 SetToken( aUserData, 2, ' ', OUString::number( (sal_Int32) bSelection ) );
1982 bWriteConfig = true;
1984 catch( const IllegalArgumentException& ){}
1987 if ( bWriteConfig )
1988 aDlgOpt.SetUserItem( USERITEM_NAME, makeAny( OUString( aUserData ) ) );
1991 SfxApplication *pSfxApp = SfxGetpApp();
1992 pSfxApp->SetLastDir_Impl( getPath() );
1995 namespace
1997 static OUString getInitPath( const OUString& _rFallback, const sal_Int32 _nFallbackToken )
1999 SfxApplication *pSfxApp = SfxGetpApp();
2000 OUString sPath = pSfxApp->GetLastDir_Impl();
2002 if ( sPath.isEmpty() )
2003 sPath = _rFallback.getToken( _nFallbackToken, ' ' );
2005 // check if the path points to a valid (accessible) directory
2006 bool bValid = false;
2007 if ( !sPath.isEmpty() )
2009 OUString sPathCheck( sPath );
2010 if ( sPathCheck[ sPathCheck.getLength() - 1 ] != '/' )
2011 sPathCheck += "/";
2012 sPathCheck += ".";
2015 ::ucbhelper::Content aContent( sPathCheck, uno::Reference< ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2016 bValid = aContent.isFolder();
2018 catch( const Exception& ) {}
2021 if ( !bValid )
2022 sPath.clear();
2024 return sPath;
2028 void FileDialogHelper_Impl::loadConfig()
2030 uno::Reference < XFilePickerControlAccess > xDlg( mxFileDlg, UNO_QUERY );
2031 Any aValue;
2033 if ( ! xDlg.is() )
2034 return;
2036 if ( mbHasPreview )
2038 SvtViewOptions aViewOpt( E_DIALOG, IMPGRF_CONFIGNAME );
2039 OUString aUserData;
2041 if ( aViewOpt.Exists() )
2043 Any aUserItem = aViewOpt.GetUserItem( USERITEM_NAME );
2044 OUString aTemp;
2045 if ( aUserItem >>= aTemp )
2046 aUserData = aTemp;
2049 if ( !aUserData.isEmpty() )
2053 // respect the last "insert as link" state
2054 bool bLink = aUserData.getToken( 0, ' ' ).toInt32();
2055 aValue <<= bLink;
2056 xDlg->setValue( ExtendedFilePickerElementIds::CHECKBOX_LINK, 0, aValue );
2058 // respect the last "show preview" state
2059 bool bShowPreview = aUserData.getToken( 1, ' ' ).toInt32();
2060 aValue <<= bShowPreview;
2061 xDlg->setValue( ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, 0, aValue );
2063 if ( maPath.isEmpty() )
2064 displayFolder( getInitPath( aUserData, 2 ) );
2066 if ( maCurFilter.isEmpty() )
2068 OUString aFilter = aUserData.getToken( 3, ' ' );
2069 aFilter = DecodeSpaces_Impl( aFilter );
2070 setFilter( aFilter );
2073 // set the member so we know that we have to show the preview
2074 mbShowPreview = bShowPreview;
2076 catch( const IllegalArgumentException& ){}
2079 if ( maPath.isEmpty() )
2080 displayFolder( SvtPathOptions().GetGraphicPath() );
2082 else
2084 SvtViewOptions aViewOpt( E_DIALOG, IODLG_CONFIGNAME );
2085 OUString aUserData;
2087 if ( aViewOpt.Exists() )
2089 Any aUserItem = aViewOpt.GetUserItem( USERITEM_NAME );
2090 OUString aTemp;
2091 if ( aUserItem >>= aTemp )
2092 aUserData = aTemp;
2095 if ( aUserData.isEmpty() )
2096 aUserData = STD_CONFIG_STR;
2098 if ( maPath.isEmpty() )
2099 displayFolder( getInitPath( aUserData, 1 ) );
2101 if ( mbHasAutoExt )
2103 sal_Int32 nFlag = aUserData.getToken( 0, ' ' ).toInt32();
2104 aValue <<= (bool) nFlag;
2107 xDlg->setValue( ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, 0, aValue );
2109 catch( const IllegalArgumentException& ){}
2112 if( mbHasSelectionBox )
2114 sal_Int32 nFlag = aUserData.getToken( 2, ' ' ).toInt32();
2115 aValue <<= (bool) nFlag;
2118 xDlg->setValue( ExtendedFilePickerElementIds::CHECKBOX_SELECTION, 0, aValue );
2120 catch( const IllegalArgumentException& ){}
2123 if ( maPath.isEmpty() )
2124 displayFolder( SvtPathOptions().GetWorkPath() );
2128 void FileDialogHelper_Impl::setDefaultValues()
2130 // when no filter is set, we set the curentFilter to <all>
2131 if ( maCurFilter.isEmpty() && !maSelectFilter.isEmpty() )
2133 uno::Reference< XFilterManager > xFltMgr( mxFileDlg, UNO_QUERY );
2136 xFltMgr->setCurrentFilter( maSelectFilter );
2138 catch( const IllegalArgumentException& )
2142 // when no path is set, we use the standard 'work' folder
2143 if ( maPath.isEmpty() )
2145 OUString aWorkFolder = SvtPathOptions().GetWorkPath();
2148 mxFileDlg->setDisplayDirectory( aWorkFolder );
2150 catch( const Exception& )
2152 OSL_FAIL( "FileDialogHelper_Impl::setDefaultValues: caught an exception while setting the display directory!" );
2157 bool FileDialogHelper_Impl::isShowFilterExtensionEnabled() const
2159 return !maFilters.empty();
2162 void FileDialogHelper_Impl::addFilterPair( const OUString& rFilter,
2163 const OUString& rFilterWithExtension )
2165 maFilters.push_back( FilterPair( rFilter, rFilterWithExtension ) );
2169 OUString FileDialogHelper_Impl::getFilterName( const OUString& rFilterWithExtension ) const
2171 OUString sRet;
2172 for( ::std::vector< FilterPair >::const_iterator pIter = maFilters.begin(); pIter != maFilters.end(); ++pIter )
2174 if ( (*pIter).Second == rFilterWithExtension )
2176 sRet = (*pIter).First;
2177 break;
2180 return sRet;
2183 OUString FileDialogHelper_Impl::getFilterWithExtension( const OUString& rFilter ) const
2185 OUString sRet;
2186 for( ::std::vector< FilterPair >::const_iterator pIter = maFilters.begin(); pIter != maFilters.end(); ++pIter )
2188 if ( (*pIter).First == rFilter )
2190 sRet = (*pIter).Second;
2191 break;
2194 return sRet;
2197 void FileDialogHelper_Impl::SetContext( FileDialogHelper::Context _eNewContext )
2199 meContext = _eNewContext;
2201 const OUString* pConfigId = GetLastFilterConfigId( _eNewContext );
2202 if( pConfigId )
2203 LoadLastUsedFilter( *pConfigId );
2206 // FileDialogHelper
2208 FileDialogHelper::FileDialogHelper(
2209 sal_Int16 nDialogType,
2210 sal_Int64 nFlags,
2211 const OUString& rFact,
2212 SfxFilterFlags nMust,
2213 SfxFilterFlags nDont )
2214 : m_nError(0)
2216 mpImp = new FileDialogHelper_Impl( this, nDialogType, nFlags );
2217 mxImp = mpImp;
2219 // create the list of filters
2220 mpImp->addFilters(
2221 SfxObjectShell::GetServiceNameFromFactory(rFact), nMust, nDont );
2224 FileDialogHelper::FileDialogHelper(
2225 sal_Int16 nDialogType,
2226 sal_Int64 nFlags,
2227 const OUString& rFact,
2228 sal_Int16 nDialog,
2229 SfxFilterFlags nMust,
2230 SfxFilterFlags nDont,
2231 const OUString& rStandardDir,
2232 const ::com::sun::star::uno::Sequence< OUString >& rBlackList)
2233 : m_nError(0)
2235 mpImp = new FileDialogHelper_Impl( this, nDialogType, nFlags, nDialog, NULL, rStandardDir, rBlackList );
2236 mxImp = mpImp;
2238 // create the list of filters
2239 mpImp->addFilters(
2240 SfxObjectShell::GetServiceNameFromFactory(rFact), nMust, nDont );
2243 FileDialogHelper::FileDialogHelper(
2244 sal_Int16 nDialogType,
2245 sal_Int64 nFlags,
2246 vcl::Window* _pPreferredParent )
2247 : m_nError(0)
2249 mpImp = new FileDialogHelper_Impl( this, nDialogType, nFlags, SFX2_IMPL_DIALOG_CONFIG, _pPreferredParent );
2250 mxImp = mpImp;
2253 FileDialogHelper::FileDialogHelper(
2254 sal_Int16 nDialogType,
2255 sal_Int64 nFlags,
2256 const OUString& aFilterUIName,
2257 const OUString& aExtName,
2258 const OUString& rStandardDir,
2259 const ::com::sun::star::uno::Sequence< OUString >& rBlackList,
2260 vcl::Window* _pPreferredParent )
2261 : m_nError(0)
2263 mpImp = new FileDialogHelper_Impl( this, nDialogType, nFlags, SFX2_IMPL_DIALOG_CONFIG, _pPreferredParent,rStandardDir, rBlackList );
2264 mxImp = mpImp;
2266 // the wildcard here is expected in form "*.extension"
2267 OUString aWildcard;
2268 if ( aExtName.indexOf( (sal_Unicode)'*' ) != 0 )
2270 if ( !aExtName.isEmpty() && aExtName.indexOf( (sal_Unicode)'.' ) != 0 )
2271 aWildcard = "*.";
2272 else
2273 aWildcard = "*";
2276 aWildcard += aExtName;
2278 OUString const aUIString = ::sfx2::addExtension( aFilterUIName,
2279 aWildcard, (OPEN == lcl_OpenOrSave(mpImp->m_nDialogType)), *mpImp);
2280 AddFilter( aUIString, aWildcard );
2283 FileDialogHelper::~FileDialogHelper()
2285 mpImp->dispose();
2286 mxImp.clear();
2289 void FileDialogHelper::CreateMatcher( const OUString& rFactory )
2291 mpImp->createMatcher( SfxObjectShell::GetServiceNameFromFactory(rFactory) );
2294 void FileDialogHelper::SetControlHelpIds( const sal_Int16* _pControlId, const char** _pHelpId )
2296 mpImp->setControlHelpIds( _pControlId, _pHelpId );
2299 void FileDialogHelper::SetContext( Context _eNewContext )
2301 mpImp->SetContext( _eNewContext );
2304 IMPL_LINK_NOARG(FileDialogHelper, ExecuteSystemFilePicker)
2306 m_nError = mpImp->execute();
2307 if ( m_aDialogClosedLink.IsSet() )
2308 m_aDialogClosedLink.Call( this );
2310 return 0L;
2313 // rDirPath has to be a directory
2314 ErrCode FileDialogHelper::Execute( std::vector<OUString>& rpURLList,
2315 SfxItemSet *& rpSet,
2316 OUString& rFilter,
2317 const OUString& rDirPath )
2319 SetDisplayFolder( rDirPath );
2320 return mpImp->execute( rpURLList, rpSet, rFilter );
2324 ErrCode FileDialogHelper::Execute()
2326 return mpImp->execute();
2329 ErrCode FileDialogHelper::Execute( SfxItemSet *& rpSet,
2330 OUString& rFilter )
2332 ErrCode nRet;
2333 std::vector<OUString> rURLList;
2334 nRet = mpImp->execute(rURLList, rpSet, rFilter);
2335 return nRet;
2338 void FileDialogHelper::StartExecuteModal( const Link<>& rEndDialogHdl )
2340 m_aDialogClosedLink = rEndDialogHdl;
2341 m_nError = ERRCODE_NONE;
2342 if ( mpImp->isSystemFilePicker() )
2343 Application::PostUserEvent( LINK( this, FileDialogHelper, ExecuteSystemFilePicker ) );
2344 else
2345 mpImp->implStartExecute();
2349 short FileDialogHelper::GetDialogType() const
2351 return mpImp ? mpImp->m_nDialogType : 0;
2354 bool FileDialogHelper::IsPasswordEnabled() const
2356 return mpImp && mpImp->isPasswordEnabled();
2359 OUString FileDialogHelper::GetRealFilter() const
2361 OUString sFilter;
2362 if ( mpImp )
2363 mpImp->getRealFilter( sFilter );
2364 return sFilter;
2367 void FileDialogHelper::SetTitle( const OUString& rNewTitle )
2369 if ( mpImp->mxFileDlg.is() )
2370 mpImp->mxFileDlg->setTitle( rNewTitle );
2373 OUString FileDialogHelper::GetPath() const
2375 OUString aPath;
2377 if ( mpImp->mlLastURLs.size() > 0)
2378 return mpImp->mlLastURLs[0];
2380 if ( mpImp->mxFileDlg.is() )
2382 Sequence < OUString > aPathSeq = mpImp->mxFileDlg->getFiles();
2384 if ( aPathSeq.getLength() == 1 )
2386 aPath = aPathSeq[0];
2390 return aPath;
2393 Sequence < OUString > FileDialogHelper::GetMPath() const
2395 if ( mpImp->mlLastURLs.size() > 0)
2396 return comphelper::containerToSequence(mpImp->mlLastURLs);
2398 if ( mpImp->mxFileDlg.is() )
2399 return mpImp->mxFileDlg->getFiles();
2400 else
2402 Sequence < OUString > aEmpty;
2403 return aEmpty;
2407 Sequence< OUString > FileDialogHelper::GetSelectedFiles() const
2409 // a) the new way (optional!)
2410 uno::Sequence< OUString > aResultSeq;
2411 uno::Reference< XFilePicker2 > xPickNew(mpImp->mxFileDlg, UNO_QUERY);
2412 if (xPickNew.is())
2414 aResultSeq = xPickNew->getSelectedFiles();
2416 // b) the olde way ... non optional.
2417 else
2419 uno::Reference< XFilePicker > xPickOld(mpImp->mxFileDlg, UNO_QUERY_THROW);
2420 Sequence< OUString > lFiles = xPickOld->getFiles();
2421 ::sal_Int32 nFiles = lFiles.getLength();
2422 if ( nFiles > 1 )
2424 aResultSeq = Sequence< OUString >( nFiles-1 );
2426 INetURLObject aPath( lFiles[0] );
2427 aPath.setFinalSlash();
2429 for (::sal_Int32 i = 1; i < nFiles; i++)
2431 if (i == 1)
2432 aPath.Append( lFiles[i] );
2433 else
2434 aPath.setName( lFiles[i] );
2436 aResultSeq[i-1] = aPath.GetMainURL( INetURLObject::NO_DECODE );
2439 else
2440 aResultSeq = lFiles;
2443 return aResultSeq;
2446 OUString FileDialogHelper::GetDisplayDirectory() const
2448 return mpImp->getPath();
2451 OUString FileDialogHelper::GetCurrentFilter() const
2453 return mpImp->getFilter();
2456 ErrCode FileDialogHelper::GetGraphic( Graphic& rGraphic ) const
2458 return mpImp->getGraphic( rGraphic );
2461 static int impl_isFolder( const OUString& rPath )
2465 ::ucbhelper::Content aContent(
2466 rPath, uno::Reference< ucb::XCommandEnvironment > (),
2467 comphelper::getProcessComponentContext() );
2468 if ( aContent.isFolder() )
2469 return 1;
2471 return 0;
2473 catch ( const Exception & )
2477 return -1;
2480 void FileDialogHelper::SetDisplayDirectory( const OUString& _rPath )
2482 if ( _rPath.isEmpty() )
2483 return;
2485 // if the given path isn't a folder, we cut off the last part
2486 // and take it as filename and the rest of the path should be
2487 // the folder
2489 INetURLObject aObj( _rPath );
2491 OUString sFileName = aObj.GetName( INetURLObject::DECODE_WITH_CHARSET );
2492 aObj.removeSegment();
2493 OUString sPath = aObj.GetMainURL( INetURLObject::NO_DECODE );
2495 int nIsFolder = impl_isFolder( _rPath );
2496 if ( nIsFolder == 0 ||
2497 ( nIsFolder == -1 && impl_isFolder( sPath ) == 1 ) )
2499 mpImp->setFileName( sFileName );
2500 mpImp->displayFolder( sPath );
2502 else
2504 INetURLObject aObjPathName( _rPath );
2505 OUString sFolder( aObjPathName.GetMainURL( INetURLObject::NO_DECODE ) );
2506 if ( sFolder.isEmpty() )
2508 // _rPath is not a valid path -> fallback to home directory
2509 osl::Security aSecurity;
2510 aSecurity.getHomeDir( sFolder );
2512 mpImp->displayFolder( sFolder );
2516 void FileDialogHelper::SetDisplayFolder( const OUString& _rURL )
2518 mpImp->displayFolder( _rURL );
2521 void FileDialogHelper::SetFileName( const OUString& _rFileName )
2523 mpImp->setFileName( _rFileName );
2526 void FileDialogHelper::AddFilter( const OUString& rFilterName,
2527 const OUString& rExtension )
2529 mpImp->addFilter( rFilterName, rExtension );
2532 void FileDialogHelper::SetCurrentFilter( const OUString& rFilter )
2534 OUString sFilter( rFilter );
2535 if ( mpImp->isShowFilterExtensionEnabled() )
2536 sFilter = mpImp->getFilterWithExtension( rFilter );
2537 mpImp->setFilter( sFilter );
2540 uno::Reference < XFilePicker > FileDialogHelper::GetFilePicker() const
2542 return mpImp->mxFileDlg;
2545 // XFilePickerListener Methods
2546 void SAL_CALL FileDialogHelper::FileSelectionChanged( const FilePickerEvent& aEvent )
2548 mpImp->handleFileSelectionChanged( aEvent );
2551 void SAL_CALL FileDialogHelper::DirectoryChanged( const FilePickerEvent& aEvent )
2553 mpImp->handleDirectoryChanged( aEvent );
2556 OUString SAL_CALL FileDialogHelper::HelpRequested( const FilePickerEvent& aEvent )
2558 return sfx2::FileDialogHelper_Impl::handleHelpRequested( aEvent );
2561 void SAL_CALL FileDialogHelper::ControlStateChanged( const FilePickerEvent& aEvent )
2563 mpImp->handleControlStateChanged( aEvent );
2566 void SAL_CALL FileDialogHelper::DialogSizeChanged()
2568 mpImp->handleDialogSizeChanged();
2571 void SAL_CALL FileDialogHelper::DialogClosed( const DialogClosedEvent& _rEvent )
2573 m_nError = ( RET_OK == _rEvent.DialogResult ) ? ERRCODE_NONE : ERRCODE_ABORT;
2574 if ( m_aDialogClosedLink.IsSet() )
2575 m_aDialogClosedLink.Call( this );
2578 ErrCode FileOpenDialog_Impl( sal_Int16 nDialogType,
2579 sal_Int64 nFlags,
2580 const OUString& rFact,
2581 std::vector<OUString>& rpURLList,
2582 OUString& rFilter,
2583 SfxItemSet *& rpSet,
2584 const OUString* pPath,
2585 sal_Int16 nDialog,
2586 const OUString& rStandardDir,
2587 const ::com::sun::star::uno::Sequence< OUString >& rBlackList )
2589 ErrCode nRet;
2590 FileDialogHelper aDialog( nDialogType, nFlags,
2591 rFact, nDialog, SfxFilterFlags::NONE, SfxFilterFlags::NONE, rStandardDir, rBlackList );
2593 OUString aPath;
2594 if ( pPath )
2595 aPath = *pPath;
2597 nRet = aDialog.Execute( rpURLList, rpSet, rFilter, aPath );
2598 DBG_ASSERT( rFilter.indexOf(": ") == -1, "Old filter name used!");
2600 return nRet;
2603 ErrCode RequestPassword(const SfxFilter* pCurrentFilter, OUString& aURL, SfxItemSet* pSet)
2605 uno::Reference < task::XInteractionHandler2 > xInteractionHandler = task::InteractionHandler::createWithParent( ::comphelper::getProcessComponentContext(), 0 );
2606 // TODO: need a save way to distinguish MS filters from other filters
2607 // for now MS-filters are the only alien filters that support encryption
2608 bool bMSType = !pCurrentFilter->IsOwnFormat();
2609 ::comphelper::DocPasswordRequestType eType = bMSType ?
2610 ::comphelper::DocPasswordRequestType_MS :
2611 ::comphelper::DocPasswordRequestType_STANDARD;
2613 ::rtl::Reference< ::comphelper::DocPasswordRequest > pPasswordRequest( new ::comphelper::DocPasswordRequest( eType, ::com::sun::star::task::PasswordRequestMode_PASSWORD_CREATE, aURL, bool( pCurrentFilter->GetFilterFlags() & SfxFilterFlags::PASSWORDTOMODIFY ) ) );
2615 uno::Reference< com::sun::star::task::XInteractionRequest > rRequest( pPasswordRequest.get() );
2616 xInteractionHandler->handle( rRequest );
2617 if ( pPasswordRequest->isPassword() )
2619 if ( pPasswordRequest->getPassword().getLength() )
2621 // TODO/LATER: The filters should show the password dialog themself in future
2622 if ( bMSType )
2624 // Check if filter supports OOXML encryption
2625 if ( lclSupportsOOXMLEncryption( pCurrentFilter->GetFilterName() ) )
2627 ::comphelper::SequenceAsHashMap aHashData;
2628 aHashData[ OUString( "OOXPassword" ) ] <<= pPasswordRequest->getPassword();
2629 pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aHashData.getAsConstNamedValueList() ) ) );
2631 else
2633 uno::Sequence< sal_Int8 > aUniqueID = ::comphelper::DocPasswordHelper::GenerateRandomByteSequence( 16 );
2634 uno::Sequence< sal_Int8 > aEncryptionKey = ::comphelper::DocPasswordHelper::GenerateStd97Key( pPasswordRequest->getPassword(), aUniqueID );
2636 if ( aEncryptionKey.getLength() )
2638 ::comphelper::SequenceAsHashMap aHashData;
2639 aHashData[ OUString( "STD97EncryptionKey" ) ] <<= aEncryptionKey;
2640 aHashData[ OUString( "STD97UniqueID" ) ] <<= aUniqueID;
2642 pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aHashData.getAsConstNamedValueList() ) ) );
2644 else
2646 return ERRCODE_IO_NOTSUPPORTED;
2650 else
2652 pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( ::comphelper::OStorageHelper::CreatePackageEncryptionData( pPasswordRequest->getPassword() ) ) ) );
2656 if ( pPasswordRequest->getRecommendReadOnly() )
2657 pSet->Put( SfxBoolItem( SID_RECOMMENDREADONLY, true ) );
2659 if ( bMSType )
2661 // the empty password has 0 as Hash
2662 sal_Int32 nHash = SfxMedium::CreatePasswordToModifyHash( pPasswordRequest->getPasswordToModify(), OUString( "com.sun.star.text.TextDocument" ).equals( pCurrentFilter->GetServiceName() ) );
2663 if ( nHash )
2664 pSet->Put( SfxUnoAnyItem( SID_MODIFYPASSWORDINFO, uno::makeAny( nHash ) ) );
2666 else
2668 uno::Sequence< beans::PropertyValue > aModifyPasswordInfo = ::comphelper::DocPasswordHelper::GenerateNewModifyPasswordInfo( pPasswordRequest->getPasswordToModify() );
2669 if ( aModifyPasswordInfo.getLength() )
2670 pSet->Put( SfxUnoAnyItem( SID_MODIFYPASSWORDINFO, uno::makeAny( aModifyPasswordInfo ) ) );
2673 else
2674 return ERRCODE_ABORT;
2675 return ERRCODE_NONE;
2678 OUString EncodeSpaces_Impl( const OUString& rSource )
2680 OUString sRet( rSource );
2681 sRet = sRet.replaceAll( " ", "%20" );
2682 return sRet;
2685 OUString DecodeSpaces_Impl( const OUString& rSource )
2687 OUString sRet( rSource );
2688 sRet = sRet.replaceAll( "%20", " " );
2689 return sRet;
2692 } // end of namespace sfx2
2694 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */