1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
24 #include "VistaFilePickerImpl.hxx"
26 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
27 #include <com/sun/star/ui/dialogs/ControlActions.hpp>
28 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
29 #include <com/sun/star/beans/StringPair.hpp>
30 #include <com/sun/star/awt/XWindow.hpp>
31 #include <com/sun/star/awt/XSystemDependentWindowPeer.hpp>
32 #include <com/sun/star/lang/SystemDependent.hpp>
33 #include <comphelper/sequence.hxx>
34 #include <fpicker/strings.hrc>
35 #include <fpicker/fpsofficeResMgr.hxx>
36 #include <osl/file.hxx>
37 #include <rtl/process.h>
38 #include <o3tl/char16_t2wchar_t.hxx>
39 #include <o3tl/string_view.hxx>
40 #include <vcl/svapp.hxx>
41 #include "WinImplHelper.hxx"
46 static bool is_current_process_window(HWND hwnd
)
49 GetWindowThreadProcessId(hwnd
, &pid
);
50 return (pid
== GetCurrentProcessId());
53 static HWND
choose_parent_window()
55 HWND hwnd_parent
= GetForegroundWindow();
56 if (!is_current_process_window(hwnd_parent
))
57 hwnd_parent
= GetDesktopWindow();
63 bool createFolderItem(OUString
const& url
, sal::systools::COMReference
<IShellItem
>& folder
)
66 if (osl::FileBase::getSystemPathFromFileURL(url
, path
)
67 != osl::FileBase::E_None
)
71 HRESULT res
= SHCreateItemFromParsingName(
72 o3tl::toW(path
.getStr()), nullptr,
73 IID_PPV_ARGS(&folder
));
74 return SUCCEEDED(res
);
84 // types, const etcpp.
87 const ::sal_Int16 INVALID_CONTROL_ID
= -1;
88 const ::sal_Int16 INVALID_CONTROL_ACTION
= -1;
90 // Guids used for IFileDialog::SetClientGuid
91 const GUID CLIENTID_FILEDIALOG_SIMPLE
= {0xB8628FD3, 0xA3F5, 0x4845, 0x9B, 0x62, 0xD5, 0x1E, 0xDF, 0x97, 0xC4, 0x83};
92 const GUID CLIENTID_FILEDIALOG_OPTIONS
= {0x93ED486F, 0x0D04, 0x4807, 0x8C, 0x44, 0xAC, 0x26, 0xCB, 0x6C, 0x5D, 0x36};
93 const GUID CLIENTID_FILESAVE_PASSWORD
= {0xC12D4F4C, 0x4D41, 0x4D4F, 0x97, 0xEF, 0x87, 0xF9, 0x8D, 0xB6, 0x1E, 0xA6};
94 const GUID CLIENTID_FILESAVE_SELECTION
= {0x5B2482B3, 0x0358, 0x4E09, 0xAA, 0x64, 0x2B, 0x76, 0xB2, 0xA0, 0xDD, 0xFE};
95 const GUID CLIENTID_FILESAVE_TEMPLATE
= {0x9996D877, 0x20D5, 0x424B, 0x9C, 0x2E, 0xD3, 0xB6, 0x31, 0xEC, 0xF7, 0xCE};
96 const GUID CLIENTID_FILEOPEN_LINK_TEMPLATE
= {0x32237796, 0x1509, 0x49D1, 0xBB, 0x7E, 0x63, 0xAD, 0x36, 0xAE, 0x86, 0x8C};
97 const GUID CLIENTID_FILEOPEN_LINK_ANCHOR
= {0xBE3188CB, 0x399A, 0x45AE, 0x8F, 0x78, 0x75, 0x17, 0xAF, 0x26, 0x81, 0xEA};
98 const GUID CLIENTID_FILEOPEN_PLAY
= {0x32CFB147, 0xF5AE, 0x4F90, 0xA1, 0xF1, 0x81, 0x20, 0x72, 0xBB, 0x2F, 0xC5};
99 const GUID CLIENTID_FILEOPEN_LINK
= {0x39AC4BAE, 0x7D2D, 0x46BC, 0xBE, 0x2E, 0xF8, 0x8C, 0xB5, 0x65, 0x5E, 0x6A};
102 class TDialogImplBase
105 TDialogImplBase(IFileDialog
* iDialog
)
110 virtual ~TDialogImplBase() = default;
112 TFileDialog
getComPtr() { return m_iDialog
; }
113 virtual sal::systools::COMReference
<IShellItemArray
> getResult(bool bInExecute
)
115 sal::systools::COMReference
<IShellItem
> iItem
;
119 m_iDialog
->GetCurrentSelection(&iItem
);
121 m_iDialog
->GetResult(&iItem
);
123 void* iItems
= nullptr;
125 SHCreateShellItemArrayFromShellItem(iItem
.get(), IID_IShellItemArray
, &iItems
);
126 return static_cast<IShellItemArray
*>(iItems
);
130 TFileDialog m_iDialog
;
135 template <class ComPtrDialog
, REFCLSID CLSID
> class TDialogImpl
: public TDialogImplBase
139 : TDialogImplBase(ComPtrDialog(CLSID
).get())
144 class TOpenDialogImpl
: public TDialogImpl
<TFileOpenDialog
, CLSID_FileOpenDialog
>
147 sal::systools::COMReference
<IShellItemArray
> getResult(bool bInExecute
) override
149 sal::systools::COMReference
<IShellItemArray
> iItems
;
150 TFileOpenDialog
iDialog(getComPtr(), sal::systools::COM_QUERY_THROW
);
151 bool bGetResult
= false;
154 else if (FAILED(bInExecute
? iDialog
->GetSelectedItems(&iItems
) : iDialog
->GetResults(&iItems
)))
158 iItems
= TDialogImplBase::getResult(bInExecute
);
166 using TSaveDialogImpl
= TDialogImpl
<TFileSaveDialog
, CLSID_FileSaveDialog
>;
167 using TFolderPickerDialogImpl
= TDialogImpl
<TFileOpenDialog
, CLSID_FileOpenDialog
>;
170 static OUString
lcl_getURLFromShellItem (IShellItem
* pItem
)
172 LPWSTR pStr
= nullptr;
176 hr
= pItem
->GetDisplayName ( SIGDN_FILESYSPATH
, &pStr
);
179 ::osl::FileBase::getFileURLFromSystemPath( OUString(o3tl::toU(pStr
)), sURL
);
183 hr
= pItem
->GetDisplayName ( SIGDN_URL
, &pStr
);
186 sURL
= o3tl::toU(pStr
);
190 hr
= pItem
->GetDisplayName ( SIGDN_PARENTRELATIVEPARSING
, &pStr
);
193 GUID known_folder_id
;
194 std::wstring aStr
= pStr
;
195 CoTaskMemFree (pStr
);
197 if (0 == aStr
.compare(0, 3, L
"::{"))
198 aStr
= aStr
.substr(2);
199 hr
= IIDFromString(aStr
.c_str(), &known_folder_id
);
202 hr
= SHGetKnownFolderPath(known_folder_id
, 0, nullptr, &pStr
);
205 ::osl::FileBase::getFileURLFromSystemPath(OUString(o3tl::toU(pStr
)), sURL
);
212 hr
= SHGetKnownFolderPath(FOLDERID_Documents
, 0, nullptr, &pStr
);
214 ::osl::FileBase::getFileURLFromSystemPath(OUString(o3tl::toU(pStr
)), sURL
);
215 else // shouldn't happen...
219 CoTaskMemFree (pStr
);
224 // Vista file picker shows the filter mask next to filter name in the list; so we need to remove the
225 // mask from the filter name to avoid duplicating masks
226 static OUString
lcl_AdjustFilterName(const OUString
& sName
)
228 const sal_Int32 idx
= sName
.indexOf("(.");
229 return (idx
> 0) ? OUString(o3tl::trim(sName
.subView(0, idx
))) : sName
;
232 // rvStrings holds the OUStrings, pointers to which data are stored in returned COMDLG_FILTERSPEC
233 static ::std::vector
<COMDLG_FILTERSPEC
> lcl_buildFilterList(CFilterContainer
& rContainer
,
234 std::vector
<OUString
>& rvStrings
)
236 ::std::vector
< COMDLG_FILTERSPEC
> lList
;
237 CFilterContainer::FILTER_ENTRY_T aFilter
;
239 rContainer
.beginEnumFilter( );
240 while( rContainer
.getNextFilter(aFilter
) )
242 COMDLG_FILTERSPEC aSpec
;
244 rvStrings
.push_back(lcl_AdjustFilterName(aFilter
.first
)); // to avoid dangling pointer
245 aSpec
.pszName
= o3tl::toW(rvStrings
.back().getStr());
246 aSpec
.pszSpec
= o3tl::toW(aFilter
.second
.getStr());
248 lList
.push_back(aSpec
);
255 VistaFilePickerImpl::VistaFilePickerImpl()
257 , m_iEventHandler(new VistaFilePickerEventHandler(this))
258 , m_bInExecute (false)
259 , m_bWasExecuted (false)
260 , m_hParentWindow(nullptr)
267 VistaFilePickerImpl::~VistaFilePickerImpl()
272 void VistaFilePickerImpl::doRequest(Request
& rRequest
)
276 switch(rRequest
.getRequest())
278 case E_ADD_PICKER_LISTENER
:
279 impl_sta_addFilePickerListener(rRequest
);
282 case E_REMOVE_PICKER_LISTENER
:
283 impl_sta_removeFilePickerListener(rRequest
);
286 case E_APPEND_FILTER
:
287 impl_sta_appendFilter(rRequest
);
290 case E_APPEND_FILTERGROUP
:
291 impl_sta_appendFilterGroup(rRequest
);
294 case E_SET_CURRENT_FILTER
:
295 impl_sta_setCurrentFilter(rRequest
);
298 case E_GET_CURRENT_FILTER
:
299 impl_sta_getCurrentFilter(rRequest
);
302 case E_CREATE_OPEN_DIALOG
:
303 impl_sta_CreateOpenDialog(rRequest
);
306 case E_CREATE_SAVE_DIALOG
:
307 impl_sta_CreateSaveDialog(rRequest
);
310 case E_CREATE_FOLDER_PICKER
:
311 impl_sta_CreateFolderPicker(rRequest
);
314 case E_SET_MULTISELECTION_MODE
:
315 impl_sta_SetMultiSelectionMode(rRequest
);
319 impl_sta_SetTitle(rRequest
);
323 impl_sta_SetFileName(rRequest
);
326 case E_SET_DIRECTORY
:
327 impl_sta_SetDirectory(rRequest
);
330 case E_GET_DIRECTORY
:
331 impl_sta_GetDirectory(rRequest
);
334 case E_SET_DEFAULT_NAME
:
335 impl_sta_SetDefaultName(rRequest
);
338 case E_GET_SELECTED_FILES
:
339 impl_sta_getSelectedFiles(rRequest
);
342 case E_SHOW_DIALOG_MODAL
:
343 impl_sta_ShowDialogModal(rRequest
);
346 case E_SET_CONTROL_VALUE
:
347 impl_sta_SetControlValue(rRequest
);
350 case E_GET_CONTROL_VALUE
:
351 impl_sta_GetControlValue(rRequest
);
354 case E_SET_CONTROL_LABEL
:
355 impl_sta_SetControlLabel(rRequest
);
358 case E_GET_CONTROL_LABEL
:
359 impl_sta_GetControlLabel(rRequest
);
362 case E_ENABLE_CONTROL
:
363 impl_sta_EnableControl(rRequest
);
366 // no default: let the compiler detect changes on enum ERequest !
374 void VistaFilePickerImpl::impl_sta_addFilePickerListener(Request
& rRequest
)
376 const css::uno::Reference
< css::ui::dialogs::XFilePickerListener
> xListener
= rRequest
.getArgumentOrDefault(PROP_PICKER_LISTENER
, css::uno::Reference
< css::ui::dialogs::XFilePickerListener
>());
377 if ( ! xListener
.is())
380 if (m_iEventHandler
.is())
382 auto* pHandlerImpl
= static_cast<VistaFilePickerEventHandler
*>(m_iEventHandler
.get());
383 pHandlerImpl
->addFilePickerListener(xListener
);
388 void VistaFilePickerImpl::impl_sta_removeFilePickerListener(Request
& rRequest
)
390 const css::uno::Reference
< css::ui::dialogs::XFilePickerListener
> xListener
= rRequest
.getArgumentOrDefault(PROP_PICKER_LISTENER
, css::uno::Reference
< css::ui::dialogs::XFilePickerListener
>());
391 if ( ! xListener
.is())
394 if (m_iEventHandler
.is())
396 auto* pHandlerImpl
= static_cast<VistaFilePickerEventHandler
*>(m_iEventHandler
.get());
397 pHandlerImpl
->removeFilePickerListener(xListener
);
402 void VistaFilePickerImpl::impl_sta_appendFilter(Request
& rRequest
)
404 const OUString sTitle
= rRequest
.getArgumentOrDefault(PROP_FILTER_TITLE
, OUString());
405 const OUString sFilter
= rRequest
.getArgumentOrDefault(PROP_FILTER_VALUE
, OUString());
407 m_lFilters
.addFilter(sTitle
, sFilter
);
411 void VistaFilePickerImpl::impl_sta_appendFilterGroup(Request
& rRequest
)
413 const css::uno::Sequence
< css::beans::StringPair
> aFilterGroup
=
414 rRequest
.getArgumentOrDefault(PROP_FILTER_GROUP
, css::uno::Sequence
< css::beans::StringPair
>());
416 if ( m_lFilters
.numFilter() > 0 && aFilterGroup
.getLength() > 0 )
417 m_lFilters
.addFilter( STRING_SEPARATOR
, "", true );
419 ::sal_Int32 c
= aFilterGroup
.getLength();
423 const css::beans::StringPair
& rFilter
= aFilterGroup
[i
];
424 m_lFilters
.addFilter(rFilter
.First
, rFilter
.Second
);
429 void VistaFilePickerImpl::impl_sta_setCurrentFilter(Request
& rRequest
)
431 const OUString sTitle
= rRequest
.getArgumentOrDefault(PROP_FILTER_TITLE
, OUString());
433 m_lFilters
.setCurrentFilter(sTitle
);
437 void VistaFilePickerImpl::impl_sta_getCurrentFilter(Request
& rRequest
)
439 TFileDialog iDialog
= impl_getBaseDialogInterface();
443 UINT nIndex
= UINT_MAX
;
444 HRESULT hResult
= iDialog
->GetFileTypeIndex(&nIndex
);
446 ( FAILED(hResult
) ) ||
447 ( nIndex
== UINT_MAX
) // COM dialog sometimes return S_OK for empty filter lists .-(
452 ::sal_Int32 nRealIndex
= nIndex
-1; // COM dialog base on 1 ... filter container on 0 .-)
454 (nRealIndex
>= 0 ) &&
455 (m_lFilters
.getFilterNameByIndex(nRealIndex
, sTitle
))
457 rRequest
.setArgument(PROP_FILTER_TITLE
, sTitle
);
458 else if ( nRealIndex
== -1 ) // Dialog not visible yet
460 sTitle
= m_lFilters
.getCurrentFilter();
461 rRequest
.setArgument(PROP_FILTER_TITLE
, sTitle
);
466 template <class TDialogImplClass
> void VistaFilePickerImpl::impl_sta_CreateDialog()
468 m_pDialog
= std::make_shared
<TDialogImplClass
>();
472 void VistaFilePickerImpl::impl_sta_InitDialog(Request
& rRequest
, DWORD nOrFlags
)
474 TFileDialog iDialog
= impl_getBaseDialogInterface();
479 iDialog
->GetOptions ( &nFlags
);
481 nFlags
&= ~FOS_FORCESHOWHIDDEN
;
482 nFlags
|= FOS_PATHMUSTEXIST
;
483 nFlags
|= FOS_DONTADDTORECENT
;
486 iDialog
->SetOptions ( nFlags
);
488 css::uno::Reference
<css::awt::XWindow
> xWindow
= rRequest
.getArgumentOrDefault(PROP_PARENT_WINDOW
, css::uno::Reference
<css::awt::XWindow
>());
491 css::uno::Reference
<css::awt::XSystemDependentWindowPeer
> xSysDepWin(xWindow
,css::uno::UNO_QUERY
);
492 if(xSysDepWin
.is()) {
493 css::uno::Sequence
<sal_Int8
> aProcessIdent(16);
494 rtl_getGlobalProcessId(reinterpret_cast<sal_uInt8
*>(aProcessIdent
.getArray()));
495 css::uno::Any aAny
= xSysDepWin
->getWindowHandle(aProcessIdent
,css::lang::SystemDependent::SYSTEM_WIN32
);
500 m_hParentWindow
= reinterpret_cast<HWND
>(tmp
);
505 ::sal_Int32 nFeatures
= rRequest
.getArgumentOrDefault(PROP_FEATURES
, ::sal_Int32(0));
506 ::sal_Int32 nTemplate
= rRequest
.getArgumentOrDefault(PROP_TEMPLATE_DESCR
, ::sal_Int32(0));
507 impl_sta_enableFeatures(nFeatures
, nTemplate
);
509 if (m_iEventHandler
.is())
511 auto* pHandlerImpl
= static_cast<VistaFilePickerEventHandler
*>(m_iEventHandler
.get());
512 pHandlerImpl
->startListening(iDialog
);
517 void VistaFilePickerImpl::impl_sta_CreateOpenDialog(Request
& rRequest
)
519 impl_sta_CreateDialog
<TOpenDialogImpl
>();
520 impl_sta_InitDialog(rRequest
, FOS_FILEMUSTEXIST
| FOS_OVERWRITEPROMPT
);
524 void VistaFilePickerImpl::impl_sta_CreateSaveDialog(Request
& rRequest
)
526 impl_sta_CreateDialog
<TSaveDialogImpl
>();
527 impl_sta_InitDialog(rRequest
, FOS_FILEMUSTEXIST
| FOS_OVERWRITEPROMPT
);
531 void VistaFilePickerImpl::impl_sta_CreateFolderPicker(Request
& rRequest
)
533 impl_sta_CreateDialog
<TFolderPickerDialogImpl
>();
534 impl_sta_InitDialog(rRequest
, FOS_PICKFOLDERS
);
538 const ::sal_Int32 GROUP_VERSION
= 1;
539 const ::sal_Int32 GROUP_TEMPLATE
= 2;
540 const ::sal_Int32 GROUP_IMAGETEMPLATE
= 3;
541 const ::sal_Int32 GROUP_CHECKBOXES
= 4;
542 const ::sal_Int32 GROUP_IMAGEANCHOR
= 5;
545 static void setLabelToControl(TFileDialogCustomize iCustom
, sal_uInt16 nControlId
)
547 OUString aLabel
= CResourceProvider::getResString(nControlId
);
548 aLabel
= SOfficeToWindowsLabel(aLabel
);
549 iCustom
->SetControlLabel(nControlId
, o3tl::toW(aLabel
.getStr()) );
553 void VistaFilePickerImpl::impl_sta_enableFeatures(::sal_Int32 nFeatures
, ::sal_Int32 nTemplate
)
558 case css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE
:
559 case css::ui::dialogs::TemplateDescription::FILEOPEN_PREVIEW
:
560 case css::ui::dialogs::TemplateDescription::FILESAVE_SIMPLE
:
561 aGUID
= CLIENTID_FILEDIALOG_SIMPLE
;
564 case css::ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION
:
565 case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS
:
566 aGUID
= CLIENTID_FILEDIALOG_OPTIONS
;
569 case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD
:
570 aGUID
= CLIENTID_FILESAVE_PASSWORD
;
573 case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION
:
574 case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_SELECTION
:
575 aGUID
= CLIENTID_FILESAVE_SELECTION
;
578 case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_TEMPLATE
:
579 aGUID
= CLIENTID_FILESAVE_TEMPLATE
;
582 case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE
:
583 aGUID
= CLIENTID_FILEOPEN_LINK_TEMPLATE
;
586 case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR
:
587 aGUID
= CLIENTID_FILEOPEN_LINK_ANCHOR
;
590 case css::ui::dialogs::TemplateDescription::FILEOPEN_PLAY
:
591 case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PLAY
:
592 aGUID
= CLIENTID_FILEOPEN_PLAY
;
595 case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW
:
596 aGUID
= CLIENTID_FILEOPEN_LINK
;
599 TFileDialog iDialog
= impl_getBaseDialogInterface();
601 iDialog
->SetClientGuid ( aGUID
);
603 TFileDialogCustomize iCustom
= impl_getCustomizeInterface();
607 if ((nFeatures
& FEATURE_VERSION
) == FEATURE_VERSION
)
609 iCustom
->StartVisualGroup (GROUP_VERSION
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_VERSION
).replaceFirst("~","").getStr()));
610 iCustom
->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_VERSION
);
611 iCustom
->EndVisualGroup ();
612 iCustom
->MakeProminent (GROUP_VERSION
);
615 if ((nFeatures
& FEATURE_TEMPLATE
) == FEATURE_TEMPLATE
)
617 iCustom
->StartVisualGroup (GROUP_TEMPLATE
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_TEMPLATES
).replaceFirst("~","").getStr()));
618 iCustom
->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_TEMPLATE
);
619 iCustom
->EndVisualGroup ();
620 iCustom
->MakeProminent (GROUP_TEMPLATE
);
623 if ((nFeatures
& FEATURE_IMAGETEMPLATE
) == FEATURE_IMAGETEMPLATE
)
625 iCustom
->StartVisualGroup (GROUP_IMAGETEMPLATE
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_IMAGE_TEMPLATE
).replaceFirst("~","").getStr()));
626 iCustom
->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE
);
627 iCustom
->EndVisualGroup ();
628 iCustom
->MakeProminent (GROUP_IMAGETEMPLATE
);
631 if ((nFeatures
& FEATURE_IMAGEANCHOR
) == FEATURE_IMAGEANCHOR
)
633 iCustom
->StartVisualGroup (GROUP_IMAGEANCHOR
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_IMAGE_ANCHOR
).replaceFirst("~","").getStr()));
634 iCustom
->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR
);
635 iCustom
->EndVisualGroup ();
636 iCustom
->MakeProminent (GROUP_IMAGEANCHOR
);
639 iCustom
->StartVisualGroup (GROUP_CHECKBOXES
, L
"");
641 sal_uInt16
nControlId(0);
642 if ((nFeatures
& FEATURE_AUTOEXTENSION
) == FEATURE_AUTOEXTENSION
)
644 nControlId
= css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION
;
645 iCustom
->AddCheckButton (nControlId
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_AUTO_EXTENSION
).replaceFirst("~","").getStr()), true);
646 setLabelToControl(iCustom
, nControlId
);
649 if ((nFeatures
& FEATURE_PASSWORD
) == FEATURE_PASSWORD
)
651 nControlId
= css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PASSWORD
;
652 iCustom
->AddCheckButton (nControlId
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_PASSWORD
).replaceFirst("~","").getStr()), false);
653 setLabelToControl(iCustom
, nControlId
);
656 if ((nFeatures
& FEATURE_GPGPASSWORD
) == FEATURE_GPGPASSWORD
)
658 nControlId
= css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_GPGENCRYPTION
;
659 iCustom
->AddCheckButton (nControlId
, L
"GpgPassword", false);
660 setLabelToControl(iCustom
, nControlId
);
663 if ((nFeatures
& FEATURE_READONLY
) == FEATURE_READONLY
)
665 nControlId
= css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY
;
666 iCustom
->AddCheckButton (nControlId
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_READONLY
).replaceFirst("~","").getStr()), false);
667 setLabelToControl(iCustom
, nControlId
);
670 if ((nFeatures
& FEATURE_FILTEROPTIONS
) == FEATURE_FILTEROPTIONS
)
672 nControlId
= css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS
;
673 iCustom
->AddCheckButton (nControlId
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_FILTER_OPTIONS
).replaceFirst("~","").getStr()), false);
674 setLabelToControl(iCustom
, nControlId
);
677 if ((nFeatures
& FEATURE_LINK
) == FEATURE_LINK
)
679 nControlId
= css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK
;
680 iCustom
->AddCheckButton (nControlId
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_INSERT_AS_LINK
).replaceFirst("~","").getStr()), false);
681 setLabelToControl(iCustom
, nControlId
);
684 if ((nFeatures
& FEATURE_SELECTION
) == FEATURE_SELECTION
)
686 nControlId
= css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_SELECTION
;
687 iCustom
->AddCheckButton (nControlId
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_SELECTION
).replaceFirst("~","").getStr()), false);
688 setLabelToControl(iCustom
, nControlId
);
691 /* can be ignored ... new COM dialog supports preview native now !
692 if ((nFeatures & FEATURE_PREVIEW) == FEATURE_PREVIEW)
693 iCustom->AddCheckButton (css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, L"Preview", false);
696 iCustom
->EndVisualGroup();
698 if ((nFeatures
& FEATURE_PLAY
) == FEATURE_PLAY
)
699 iCustom
->AddPushButton (css::ui::dialogs::ExtendedFilePickerElementIds::PUSHBUTTON_PLAY
, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_PLAY
).replaceFirst("~","").getStr()));
704 void VistaFilePickerImpl::impl_sta_SetMultiSelectionMode(Request
& rRequest
)
706 const bool bMultiSelection
= rRequest
.getArgumentOrDefault(PROP_MULTISELECTION_MODE
, true);
708 TFileDialog iDialog
= impl_getBaseDialogInterface();
713 iDialog
->GetOptions(&nFlags
);
716 nFlags
|= FOS_ALLOWMULTISELECT
;
718 nFlags
&= ~FOS_ALLOWMULTISELECT
;
720 iDialog
->SetOptions ( nFlags
);
724 void VistaFilePickerImpl::impl_sta_SetTitle(Request
& rRequest
)
726 OUString sTitle
= rRequest
.getArgumentOrDefault(PROP_TITLE
, OUString());
728 TFileDialog iDialog
= impl_getBaseDialogInterface();
732 iDialog
->SetTitle(o3tl::toW(sTitle
.getStr()));
736 void VistaFilePickerImpl::impl_sta_SetFileName(Request
& rRequest
)
738 OUString sFileName
= rRequest
.getArgumentOrDefault(PROP_FILENAME
, OUString());
740 TFileDialog iDialog
= impl_getBaseDialogInterface();
744 iDialog
->SetFileName(o3tl::toW(sFileName
.getStr()));
748 void VistaFilePickerImpl::impl_sta_SetDirectory(Request
& rRequest
)
750 OUString sDirectory
= rRequest
.getArgumentOrDefault(PROP_DIRECTORY
, OUString());
754 // Vista stores last used folders for file dialogs
755 // so we don't want the application to change the folder
757 // Store the requested folder in the meantime and decide later
759 m_sDirectory
= sDirectory
;
762 TFileDialog iDialog
= impl_getBaseDialogInterface();
766 sal::systools::COMReference
<IShellItem
> pFolder
;
767 if ( !createFolderItem(sDirectory
, pFolder
) )
770 iDialog
->SetFolder(pFolder
.get());
773 OUString
VistaFilePickerImpl::GetDirectory()
775 TFileDialog iDialog
= impl_getBaseDialogInterface();
778 sal::systools::COMReference
<IShellItem
> pFolder
;
779 HRESULT hResult
= iDialog
->GetFolder( &pFolder
);
780 if ( FAILED(hResult
) )
782 return lcl_getURLFromShellItem(pFolder
.get());
785 void VistaFilePickerImpl::impl_sta_GetDirectory(Request
& rRequest
)
787 const OUString sFolder
= m_sDirectory
.isEmpty() ? GetDirectory() : m_sDirectory
;
788 if (!sFolder
.isEmpty())
789 rRequest
.setArgument(PROP_DIRECTORY
, sFolder
);
792 void VistaFilePickerImpl::impl_sta_SetDefaultName(Request
& rRequest
)
794 OUString sFilename
= rRequest
.getArgumentOrDefault(PROP_FILENAME
, OUString());
795 TFileDialog iDialog
= impl_getBaseDialogInterface();
799 TFileDialogCustomize iCustom
= impl_getCustomizeInterface();
803 // if we have the autoextension check box set, remove (or change ???) the extension of the filename
804 // so that the autoextension mechanism can do its job
806 HRESULT hResult
= iCustom
->GetCheckButtonState( css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION
, &bValue
);
807 if ( FAILED(hResult
) )
811 sal_Int32 nSepPos
= sFilename
.lastIndexOf( '.' );
813 sFilename
= sFilename
.copy(0, nSepPos
);
816 iDialog
->SetFileName (o3tl::toW(sFilename
.getStr()));
817 m_sFilename
= sFilename
;
821 void VistaFilePickerImpl::impl_sta_setFiltersOnDialog()
823 std::vector
<OUString
> vStrings
; // to hold the adjusted filter names, pointers to which will be
824 // stored in lFilters
825 ::std::vector
< COMDLG_FILTERSPEC
> lFilters
= lcl_buildFilterList(m_lFilters
, vStrings
);
826 OUString sCurrentFilter
= m_lFilters
.getCurrentFilter();
827 sal_Int32 nCurrentFilter
= m_lFilters
.getFilterPos(sCurrentFilter
);
828 TFileDialog iDialog
= impl_getBaseDialogInterface();
831 TFileDialogCustomize iCustomize
= impl_getCustomizeInterface();
832 if (!iCustomize
.is())
835 if (lFilters
.empty())
838 COMDLG_FILTERSPEC
*pFilt
= lFilters
.data();
839 iDialog
->SetFileTypes(lFilters
.size(), pFilt
/*&lFilters[0]*/);
840 iDialog
->SetFileTypeIndex(nCurrentFilter
+ 1);
843 HRESULT hResult
= iCustomize
->GetCheckButtonState( css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION
, &bValue
);
844 if ( FAILED(hResult
) )
849 PCWSTR lpFilterExt
= lFilters
[0].pszSpec
;
851 lpFilterExt
= wcsrchr( lpFilterExt
, '.' );
854 iDialog
->SetDefaultExtension( lpFilterExt
);
860 void VistaFilePickerImpl::impl_sta_getSelectedFiles(Request
& rRequest
)
862 if (m_pDialog
== nullptr)
865 // ask dialog for results
866 // we must react different if dialog is in execute or not .-(
867 sal::systools::COMReference
<IShellItemArray
> iItems
= m_pDialog
->getResult(m_bInExecute
);
871 // convert and pack results
872 std::vector
< OUString
> lFiles
;
873 if (DWORD nCount
; SUCCEEDED(iItems
->GetCount(&nCount
)))
875 for (DWORD i
= 0; i
< nCount
; ++i
)
877 if (sal::systools::COMReference
<IShellItem
> iItem
;
878 SUCCEEDED(iItems
->GetItemAt(i
, &iItem
)))
880 if (const OUString sURL
= lcl_getURLFromShellItem(iItem
.get()); !sURL
.isEmpty())
881 lFiles
.push_back(sURL
);
886 rRequest
.setArgument(PROP_SELECTED_FILES
, comphelper::containerToSequence(lFiles
));
890 void VistaFilePickerImpl::impl_sta_ShowDialogModal(Request
& rRequest
)
892 impl_sta_setFiltersOnDialog();
894 TFileDialog iDialog
= impl_getBaseDialogInterface();
898 // it's important to know if we are showing the dialog.
899 // Some dialog interface methods can't be called then or some
900 // tasks must be done differently .-) (e.g. see impl_sta_getSelectedFiles())
903 m_bWasExecuted
= true;
905 // we set the directory only if we have a save dialog and a filename
906 // for the other cases, the file dialog remembers its last location
907 // according to its client guid.
908 if( m_sDirectory
.getLength())
910 sal::systools::COMReference
<IShellItem
> pFolder
;
911 if ( createFolderItem(m_sDirectory
, pFolder
) )
913 if (m_sFilename
.getLength())
915 OUString
aFileURL(m_sDirectory
);
916 sal_Int32 nIndex
= aFileURL
.lastIndexOf('/');
917 if (nIndex
!= aFileURL
.getLength()-1)
919 aFileURL
+= m_sFilename
;
921 TFileDialogCustomize iCustom
= impl_getCustomizeInterface();
926 HRESULT hResult
= iCustom
->GetCheckButtonState( css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION
, &bValue
);
930 hResult
= iDialog
->GetFileTypeIndex(&nFileType
);
931 if ( SUCCEEDED(hResult
) && nFileType
> 0 )
933 // COM dialog base on 1 ... filter container on 0 .-)
934 ::size_t nRealIndex
= nFileType
-1;
936 if (m_lFilters
.getFilterByIndex(nRealIndex
, sFilter
))
938 const sal_Int32 idx
= sFilter
.indexOf('.');
940 aFileURL
+= sFilter
.subView(idx
);
945 // Check existence of file. Set folder only for this special case
946 OUString aSystemPath
;
947 osl_getSystemPathFromFileURL( aFileURL
.pData
, &aSystemPath
.pData
);
949 WIN32_FIND_DATAW aFindFileData
;
950 HANDLE hFind
= FindFirstFileW( o3tl::toW(aSystemPath
.getStr()), &aFindFileData
);
951 if (hFind
!= INVALID_HANDLE_VALUE
)
952 iDialog
->SetFolder(pFolder
.get());
954 hResult
= iDialog
->AddPlace(pFolder
.get(), FDAP_TOP
);
959 iDialog
->AddPlace(pFolder
.get(), FDAP_TOP
);
963 HRESULT hResult
= E_FAIL
;
966 // tdf#146007: Make sure we don't hold solar mutex: COM may need to forward
967 // the execution to the main thread, and holding solar mutex could deadlock
968 SolarMutexGuard g
; // First acquire, to avoid releaser failure
969 SolarMutexReleaser r
;
970 // show dialog and wait for user decision
971 hResult
= iDialog
->Show(m_hParentWindow
? m_hParentWindow
972 : choose_parent_window()); // parent window needed
977 m_bInExecute
= false;
979 if (m_iEventHandler
.is())
981 auto* pHandlerImpl
= static_cast<VistaFilePickerEventHandler
*>(m_iEventHandler
.get());
982 pHandlerImpl
->stopListening();
985 if ( FAILED(hResult
) )
988 impl_sta_getSelectedFiles(rRequest
);
989 rRequest
.setArgument(PROP_DIALOG_SHOW_RESULT
, true);
993 TFileDialog
VistaFilePickerImpl::impl_getBaseDialogInterface()
997 if (m_pDialog
!= nullptr)
998 iDialog
= m_pDialog
->getComPtr();
1004 TFileDialogCustomize
VistaFilePickerImpl::impl_getCustomizeInterface()
1006 if (m_pDialog
!= nullptr)
1007 return { m_pDialog
->getComPtr(), sal::systools::COM_QUERY_THROW
};
1013 static void lcl_removeControlItemsWorkaround(const TFileDialogCustomize
& iCustom
,
1014 ::sal_Int16 nControlId
)
1016 (void)iCustom
->SetSelectedControlItem(nControlId
, 1000); // Don't care if this fails (useless?)
1018 HRESULT hResult
= S_OK
;
1019 while ( SUCCEEDED(hResult
) )
1020 hResult
= iCustom
->RemoveControlItem(nControlId
, i
++);
1024 void VistaFilePickerImpl::impl_sta_SetControlValue(Request
& rRequest
)
1026 ::sal_Int16 nId
= rRequest
.getArgumentOrDefault(PROP_CONTROL_ID
, INVALID_CONTROL_ID
);
1027 ::sal_Int16 nAction
= rRequest
.getArgumentOrDefault(PROP_CONTROL_ACTION
, INVALID_CONTROL_ACTION
);
1028 css::uno::Any aValue
= rRequest
.getValue(PROP_CONTROL_VALUE
);
1030 // don't check for right values here ...
1031 // most parameters are optional !
1033 TFileDialogCustomize iCustom
= impl_getCustomizeInterface();
1034 if ( ! iCustom
.is())
1039 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION
:
1040 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PASSWORD
:
1041 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY
:
1042 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS
:
1043 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK
:
1044 //case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PREVIEW : // can be ignored ... preview is supported native now !
1045 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_SELECTION
:
1047 bool bValue
= false;
1049 iCustom
->SetCheckButtonState(nId
, bValue
);
1053 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_VERSION
:
1054 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_TEMPLATE
:
1055 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE
:
1056 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR
:
1061 case css::ui::dialogs::ControlActions::DELETE_ITEMS
:
1063 hResult
= iCustom
->RemoveAllControlItems(nId
);
1064 if ( FAILED(hResult
) )
1065 lcl_removeControlItemsWorkaround(iCustom
, nId
);
1069 case css::ui::dialogs::ControlActions::ADD_ITEMS
:
1071 aValue
>>= m_lItems
;
1072 for (::sal_Int32 i
=0; i
<m_lItems
.getLength(); ++i
)
1074 const OUString
& sItem
= m_lItems
[i
];
1075 hResult
= iCustom
->AddControlItem(nId
, i
, o3tl::toW(sItem
.getStr()));
1080 case css::ui::dialogs::ControlActions::SET_SELECT_ITEM
:
1082 ::sal_Int32 nItem
= 0;
1084 hResult
= iCustom
->SetSelectedControlItem(nId
, nItem
);
1091 case css::ui::dialogs::ExtendedFilePickerElementIds::PUSHBUTTON_PLAY
:
1099 void VistaFilePickerImpl::impl_sta_GetControlValue(Request
& rRequest
)
1101 ::sal_Int16 nId
= rRequest
.getArgumentOrDefault(PROP_CONTROL_ID
, INVALID_CONTROL_ID
);
1103 // don't check for right values here ...
1104 // most parameters are optional !
1106 TFileDialogCustomize iCustom
= impl_getCustomizeInterface();
1107 if ( ! iCustom
.is())
1110 css::uno::Any aValue
;
1111 if( m_bWasExecuted
)
1114 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PASSWORD
:
1115 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_GPGENCRYPTION
:
1116 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY
:
1117 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS
:
1118 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK
:
1119 //case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PREVIEW : // can be ignored ... preview is supported native now !
1120 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_SELECTION
:
1122 BOOL bValue
= FALSE
;
1123 HRESULT hResult
= iCustom
->GetCheckButtonState(nId
, &bValue
);
1124 if ( SUCCEEDED(hResult
) )
1125 aValue
<<= bool(bValue
);
1128 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_VERSION
:
1129 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_TEMPLATE
:
1130 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE
:
1131 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR
:
1134 HRESULT hResult
= iCustom
->GetSelectedControlItem(nId
, &bValue
);
1135 if ( SUCCEEDED(hResult
) )
1137 const OUString
& sItem
= m_lItems
[bValue
];
1138 aValue
<<= OUString(sItem
.getStr());
1144 if (aValue
.hasValue())
1145 rRequest
.setArgument(PROP_CONTROL_VALUE
, aValue
);
1149 void VistaFilePickerImpl::impl_sta_SetControlLabel(Request
& rRequest
)
1151 ::sal_Int16 nId
= rRequest
.getArgumentOrDefault(PROP_CONTROL_ID
, INVALID_CONTROL_ID
);
1152 OUString sLabel
= rRequest
.getArgumentOrDefault(PROP_CONTROL_LABEL
, OUString() );
1154 // don't check for right values here ...
1155 // most parameters are optional !
1157 TFileDialogCustomize iCustom
= impl_getCustomizeInterface();
1158 if ( ! iCustom
.is())
1160 iCustom
->SetControlLabel (nId
, o3tl::toW(sLabel
.getStr()));
1164 void VistaFilePickerImpl::impl_sta_GetControlLabel(Request
& /*rRequest*/)
1169 void VistaFilePickerImpl::impl_sta_EnableControl(Request
& rRequest
)
1171 ::sal_Int16 nId
= rRequest
.getArgumentOrDefault(PROP_CONTROL_ID
, INVALID_CONTROL_ID
);
1172 bool bEnabled
= rRequest
.getArgumentOrDefault(PROP_CONTROL_ENABLE
, true);
1174 // don't check for right values here ...
1175 // most parameters are optional !
1177 TFileDialogCustomize iCustom
= impl_getCustomizeInterface();
1178 if ( ! iCustom
.is())
1181 CDCONTROLSTATEF eState
= CDCS_VISIBLE
;
1183 eState
|= CDCS_ENABLED
;
1185 eState
|= CDCS_INACTIVE
;
1187 iCustom
->SetControlState(nId
, eState
);
1190 void VistaFilePickerImpl::impl_SetDefaultExtension( const OUString
& currentFilter
)
1192 TFileDialog iDialog
= impl_getBaseDialogInterface();
1196 if (currentFilter
.getLength())
1199 m_lFilters
.getFilterByName(currentFilter
, FilterExt
);
1201 sal_Int32 posOfPoint
= FilterExt
.indexOf(L
'.');
1202 const sal_Unicode
* pFirstExtStart
= FilterExt
.getStr() + posOfPoint
+ 1;
1204 sal_Int32 posOfSemiColon
= FilterExt
.indexOf(L
';') - 1;
1205 if (posOfSemiColon
< 0)
1206 posOfSemiColon
= FilterExt
.getLength() - 1;
1208 FilterExt
= OUString(pFirstExtStart
, posOfSemiColon
- posOfPoint
);
1209 iDialog
->SetDefaultExtension ( o3tl::toW(FilterExt
.getStr()) );
1213 void VistaFilePickerImpl::onAutoExtensionChanged (bool bChecked
)
1215 const OUString sFilter
= m_lFilters
.getCurrentFilter ();
1217 if (!m_lFilters
.getFilterByName(sFilter
, sExt
))
1220 TFileDialog iDialog
= impl_getBaseDialogInterface();
1224 PCWSTR pExt
= nullptr;
1227 pExt
= o3tl::toW(sExt
.getStr());
1228 pExt
= wcsrchr( pExt
, '.' );
1232 iDialog
->SetDefaultExtension( pExt
);
1235 bool VistaFilePickerImpl::onFileTypeChanged( UINT
/*nTypeIndex*/ )
1240 void VistaFilePickerImpl::onDirectoryChanged()
1242 m_sDirectory
= GetDirectory();
1245 } // namespace vista
1246 } // namespace win32
1247 } // namespace fpicker
1249 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */