Fix typo
[LibreOffice.git] / fpicker / source / win32 / VistaFilePickerImpl.cxx
blob3ffe0883d1282551d65db1b73b7e39c7ef9edfa5
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 <sal/config.h>
22 #include <memory>
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"
43 #include <shlguid.h>
44 #include <shlobj.h>
46 static bool is_current_process_window(HWND hwnd)
48 DWORD pid;
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();
58 return hwnd_parent;
61 namespace {
63 bool createFolderItem(OUString const& url, sal::systools::COMReference<IShellItem>& folder)
65 OUString path;
66 if (osl::FileBase::getSystemPathFromFileURL(url, path)
67 != osl::FileBase::E_None)
69 return false;
71 HRESULT res = SHCreateItemFromParsingName(
72 o3tl::toW(path.getStr()), nullptr,
73 IID_PPV_ARGS(&folder));
74 return SUCCEEDED(res);
79 namespace fpicker{
80 namespace win32{
81 namespace vista{
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
104 public:
105 TDialogImplBase(IFileDialog* iDialog)
106 : m_iDialog(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;
116 if (m_iDialog.is())
118 if (bInExecute)
119 m_iDialog->GetCurrentSelection(&iItem);
120 else
121 m_iDialog->GetResult(&iItem);
123 void* iItems = nullptr;
124 if (iItem.is())
125 SHCreateShellItemArrayFromShellItem(iItem.get(), IID_IShellItemArray, &iItems);
126 return static_cast<IShellItemArray*>(iItems);
129 private:
130 TFileDialog m_iDialog;
133 namespace {
135 template <class ComPtrDialog, REFCLSID CLSID> class TDialogImpl : public TDialogImplBase
137 public:
138 TDialogImpl()
139 : TDialogImplBase(ComPtrDialog(CLSID).get())
144 class TOpenDialogImpl : public TDialogImpl<TFileOpenDialog, CLSID_FileOpenDialog>
146 public:
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;
152 if (!iDialog.is())
153 bGetResult = true;
154 else if (FAILED(bInExecute ? iDialog->GetSelectedItems(&iItems) : iDialog->GetResults(&iItems)))
155 bGetResult = true;
157 if (bGetResult)
158 iItems = TDialogImplBase::getResult(bInExecute);
160 return iItems;
166 using TSaveDialogImpl = TDialogImpl<TFileSaveDialog, CLSID_FileSaveDialog>;
167 using TFolderPickerDialogImpl = TDialogImpl<TFileOpenDialog, CLSID_FileOpenDialog>;
170 static OUString lcl_getURLFromShellItem (IShellItem* pItem)
172 sal::systools::CoTaskMemAllocated<wchar_t> pStr;
173 HRESULT hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pStr);
174 if (FAILED(hr))
176 // tdf#155176: One could think that querying SIGDN_URL would go first. But Windows uses
177 // current 8-bit codepage for the filenames, and URL-encodes those octets. So check it
178 // only after SIGDN_FILESYSPATH query failed (can it ever happen?)
179 if (SUCCEEDED(pItem->GetDisplayName(SIGDN_URL, &pStr)))
180 return OUString(o3tl::toU(pStr));
182 hr = pItem->GetDisplayName(SIGDN_PARENTRELATIVEPARSING, &pStr);
183 if (SUCCEEDED(hr))
185 GUID known_folder_id;
186 wchar_t* pStr2 = pStr;
187 if (pStr2[0] == ':' && pStr2[1] == ':' && pStr2[2] == '{')
188 pStr2 += 2;
189 hr = IIDFromString(pStr2, &known_folder_id);
190 if (SUCCEEDED(hr))
191 hr = SHGetKnownFolderPath(known_folder_id, 0, nullptr, &pStr);
195 // Default fallback
196 if (FAILED(hr))
197 hr = SHGetKnownFolderPath(FOLDERID_Documents, 0, nullptr, &pStr);
199 OUString sURL;
200 if (SUCCEEDED(hr))
201 ::osl::FileBase::getFileURLFromSystemPath(OUString(o3tl::toU(pStr)), sURL);
202 return sURL;
205 // Vista file picker shows the filter mask next to filter name in the list; so we need to remove the
206 // mask from the filter name to avoid duplicating masks
207 static OUString lcl_AdjustFilterName(const OUString& sName)
209 const sal_Int32 idx = sName.indexOf("(.");
210 return (idx > 0) ? OUString(o3tl::trim(sName.subView(0, idx))) : sName;
213 // rvStrings holds the OUStrings, pointers to which data are stored in returned COMDLG_FILTERSPEC
214 static ::std::vector<COMDLG_FILTERSPEC> lcl_buildFilterList(CFilterContainer& rContainer,
215 std::vector<OUString>& rvStrings)
217 ::std::vector< COMDLG_FILTERSPEC > lList ;
218 CFilterContainer::FILTER_ENTRY_T aFilter;
220 rContainer.beginEnumFilter( );
221 while( rContainer.getNextFilter(aFilter) )
223 COMDLG_FILTERSPEC aSpec;
225 rvStrings.push_back(lcl_AdjustFilterName(aFilter.first)); // to avoid dangling pointer
226 aSpec.pszName = o3tl::toW(rvStrings.back().getStr());
227 aSpec.pszSpec = o3tl::toW(aFilter.second.getStr());
229 lList.push_back(aSpec);
232 return lList;
236 VistaFilePickerImpl::VistaFilePickerImpl()
237 : m_lFilters ()
238 , m_iEventHandler(new VistaFilePickerEventHandler(this))
239 , m_bInExecute (false)
240 , m_bWasExecuted (false)
241 , m_hParentWindow(nullptr)
242 , m_sDirectory ()
243 , m_sFilename ()
248 VistaFilePickerImpl::~VistaFilePickerImpl()
253 void VistaFilePickerImpl::doRequest(Request& rRequest)
257 switch(rRequest.getRequest())
259 case E_ADD_PICKER_LISTENER :
260 impl_sta_addFilePickerListener(rRequest);
261 break;
263 case E_REMOVE_PICKER_LISTENER :
264 impl_sta_removeFilePickerListener(rRequest);
265 break;
267 case E_APPEND_FILTER :
268 impl_sta_appendFilter(rRequest);
269 break;
271 case E_APPEND_FILTERGROUP :
272 impl_sta_appendFilterGroup(rRequest);
273 break;
275 case E_SET_CURRENT_FILTER :
276 impl_sta_setCurrentFilter(rRequest);
277 break;
279 case E_GET_CURRENT_FILTER :
280 impl_sta_getCurrentFilter(rRequest);
281 break;
283 case E_CREATE_OPEN_DIALOG :
284 impl_sta_CreateOpenDialog(rRequest);
285 break;
287 case E_CREATE_SAVE_DIALOG :
288 impl_sta_CreateSaveDialog(rRequest);
289 break;
291 case E_CREATE_FOLDER_PICKER:
292 impl_sta_CreateFolderPicker(rRequest);
293 break;
295 case E_SET_MULTISELECTION_MODE :
296 impl_sta_SetMultiSelectionMode(rRequest);
297 break;
299 case E_SET_TITLE :
300 impl_sta_SetTitle(rRequest);
301 break;
303 case E_SET_FILENAME:
304 impl_sta_SetFileName(rRequest);
305 break;
307 case E_SET_DIRECTORY :
308 impl_sta_SetDirectory(rRequest);
309 break;
311 case E_GET_DIRECTORY :
312 impl_sta_GetDirectory(rRequest);
313 break;
315 case E_SET_DEFAULT_NAME :
316 impl_sta_SetDefaultName(rRequest);
317 break;
319 case E_GET_SELECTED_FILES :
320 impl_sta_getSelectedFiles(rRequest);
321 break;
323 case E_SHOW_DIALOG_MODAL :
324 impl_sta_ShowDialogModal(rRequest);
325 break;
327 case E_SET_CONTROL_VALUE :
328 impl_sta_SetControlValue(rRequest);
329 break;
331 case E_GET_CONTROL_VALUE :
332 impl_sta_GetControlValue(rRequest);
333 break;
335 case E_SET_CONTROL_LABEL :
336 impl_sta_SetControlLabel(rRequest);
337 break;
339 case E_GET_CONTROL_LABEL :
340 impl_sta_GetControlLabel(rRequest);
341 break;
343 case E_ENABLE_CONTROL :
344 impl_sta_EnableControl(rRequest);
345 break;
347 // no default: let the compiler detect changes on enum ERequest !
350 catch(...)
355 void VistaFilePickerImpl::impl_sta_addFilePickerListener(Request& rRequest)
357 const css::uno::Reference< css::ui::dialogs::XFilePickerListener > xListener = rRequest.getArgumentOrDefault(PROP_PICKER_LISTENER, css::uno::Reference< css::ui::dialogs::XFilePickerListener >());
358 if ( ! xListener.is())
359 return;
361 if (m_iEventHandler.is())
363 auto* pHandlerImpl = static_cast<VistaFilePickerEventHandler*>(m_iEventHandler.get());
364 pHandlerImpl->addFilePickerListener(xListener);
369 void VistaFilePickerImpl::impl_sta_removeFilePickerListener(Request& rRequest)
371 const css::uno::Reference< css::ui::dialogs::XFilePickerListener > xListener = rRequest.getArgumentOrDefault(PROP_PICKER_LISTENER, css::uno::Reference< css::ui::dialogs::XFilePickerListener >());
372 if ( ! xListener.is())
373 return;
375 if (m_iEventHandler.is())
377 auto* pHandlerImpl = static_cast<VistaFilePickerEventHandler*>(m_iEventHandler.get());
378 pHandlerImpl->removeFilePickerListener(xListener);
383 void VistaFilePickerImpl::impl_sta_appendFilter(Request& rRequest)
385 const OUString sTitle = rRequest.getArgumentOrDefault(PROP_FILTER_TITLE, OUString());
386 const OUString sFilter = rRequest.getArgumentOrDefault(PROP_FILTER_VALUE, OUString());
388 m_lFilters.addFilter(sTitle, sFilter);
392 void VistaFilePickerImpl::impl_sta_appendFilterGroup(Request& rRequest)
394 const css::uno::Sequence< css::beans::StringPair > aFilterGroup =
395 rRequest.getArgumentOrDefault(PROP_FILTER_GROUP, css::uno::Sequence< css::beans::StringPair >());
397 if ( m_lFilters.numFilter() > 0 && aFilterGroup.getLength() > 0 )
398 m_lFilters.addFilter( STRING_SEPARATOR, "", true );
400 ::sal_Int32 c = aFilterGroup.getLength();
401 ::sal_Int32 i = 0;
402 for (i=0; i<c; ++i)
404 const css::beans::StringPair& rFilter = aFilterGroup[i];
405 m_lFilters.addFilter(rFilter.First, rFilter.Second);
410 void VistaFilePickerImpl::impl_sta_setCurrentFilter(Request& rRequest)
412 const OUString sTitle = rRequest.getArgumentOrDefault(PROP_FILTER_TITLE, OUString());
414 m_lFilters.setCurrentFilter(sTitle);
418 void VistaFilePickerImpl::impl_sta_getCurrentFilter(Request& rRequest)
420 TFileDialog iDialog = impl_getBaseDialogInterface();
421 if (!iDialog.is())
422 return;
424 UINT nIndex = UINT_MAX;
425 HRESULT hResult = iDialog->GetFileTypeIndex(&nIndex);
426 if (
427 ( FAILED(hResult) ) ||
428 ( nIndex == UINT_MAX ) // COM dialog sometimes return S_OK for empty filter lists .-(
430 return;
432 OUString sTitle;
433 ::sal_Int32 nRealIndex = nIndex-1; // COM dialog base on 1 ... filter container on 0 .-)
434 if (
435 (nRealIndex >= 0 ) &&
436 (m_lFilters.getFilterNameByIndex(nRealIndex, sTitle))
438 rRequest.setArgument(PROP_FILTER_TITLE, sTitle);
439 else if ( nRealIndex == -1 ) // Dialog not visible yet
441 sTitle = m_lFilters.getCurrentFilter();
442 rRequest.setArgument(PROP_FILTER_TITLE, sTitle);
447 template <class TDialogImplClass> void VistaFilePickerImpl::impl_sta_CreateDialog()
449 m_pDialog = std::make_shared<TDialogImplClass>();
453 void VistaFilePickerImpl::impl_sta_InitDialog(Request& rRequest, DWORD nOrFlags)
455 TFileDialog iDialog = impl_getBaseDialogInterface();
456 if (!iDialog.is())
457 return;
459 DWORD nFlags = 0;
460 iDialog->GetOptions ( &nFlags );
462 nFlags &= ~FOS_FORCESHOWHIDDEN;
463 nFlags |= FOS_PATHMUSTEXIST;
464 nFlags |= FOS_DONTADDTORECENT;
465 nFlags |= nOrFlags;
467 iDialog->SetOptions ( nFlags );
469 css::uno::Reference<css::awt::XWindow> xWindow = rRequest.getArgumentOrDefault(PROP_PARENT_WINDOW, css::uno::Reference<css::awt::XWindow>());
470 if(xWindow.is())
472 css::uno::Reference<css::awt::XSystemDependentWindowPeer> xSysDepWin(xWindow,css::uno::UNO_QUERY);
473 if(xSysDepWin.is()) {
474 css::uno::Sequence<sal_Int8> aProcessIdent(16);
475 rtl_getGlobalProcessId(reinterpret_cast<sal_uInt8*>(aProcessIdent.getArray()));
476 css::uno::Any aAny = xSysDepWin->getWindowHandle(aProcessIdent,css::lang::SystemDependent::SYSTEM_WIN32);
477 sal_Int64 tmp = 0;
478 aAny >>= tmp;
479 if(tmp != 0)
481 m_hParentWindow = reinterpret_cast<HWND>(tmp);
486 ::sal_Int32 nFeatures = rRequest.getArgumentOrDefault(PROP_FEATURES, ::sal_Int32(0));
487 ::sal_Int32 nTemplate = rRequest.getArgumentOrDefault(PROP_TEMPLATE_DESCR, ::sal_Int32(0));
488 impl_sta_enableFeatures(nFeatures, nTemplate);
490 if (m_iEventHandler.is())
492 auto* pHandlerImpl = static_cast<VistaFilePickerEventHandler*>(m_iEventHandler.get());
493 pHandlerImpl->startListening(iDialog);
498 void VistaFilePickerImpl::impl_sta_CreateOpenDialog(Request& rRequest)
500 impl_sta_CreateDialog<TOpenDialogImpl>();
501 impl_sta_InitDialog(rRequest, FOS_FILEMUSTEXIST | FOS_OVERWRITEPROMPT);
505 void VistaFilePickerImpl::impl_sta_CreateSaveDialog(Request& rRequest)
507 impl_sta_CreateDialog<TSaveDialogImpl>();
508 impl_sta_InitDialog(rRequest, FOS_FILEMUSTEXIST | FOS_OVERWRITEPROMPT);
512 void VistaFilePickerImpl::impl_sta_CreateFolderPicker(Request& rRequest)
514 impl_sta_CreateDialog<TFolderPickerDialogImpl>();
515 impl_sta_InitDialog(rRequest, FOS_PICKFOLDERS);
519 const ::sal_Int32 GROUP_VERSION = 1;
520 const ::sal_Int32 GROUP_TEMPLATE = 2;
521 const ::sal_Int32 GROUP_IMAGETEMPLATE = 3;
522 const ::sal_Int32 GROUP_CHECKBOXES = 4;
523 const ::sal_Int32 GROUP_IMAGEANCHOR = 5;
526 static void setLabelToControl(TFileDialogCustomize iCustom, sal_uInt16 nControlId)
528 OUString aLabel = CResourceProvider::getResString(nControlId);
529 aLabel = SOfficeToWindowsLabel(aLabel);
530 iCustom->SetControlLabel(nControlId, o3tl::toW(aLabel.getStr()) );
534 void VistaFilePickerImpl::impl_sta_enableFeatures(::sal_Int32 nFeatures, ::sal_Int32 nTemplate)
536 GUID aGUID = {};
537 switch (nTemplate)
539 case css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE :
540 case css::ui::dialogs::TemplateDescription::FILEOPEN_PREVIEW :
541 case css::ui::dialogs::TemplateDescription::FILESAVE_SIMPLE :
542 aGUID = CLIENTID_FILEDIALOG_SIMPLE;
543 break;
545 case css::ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION :
546 case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS :
547 aGUID = CLIENTID_FILEDIALOG_OPTIONS;
548 break;
550 case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD :
551 aGUID = CLIENTID_FILESAVE_PASSWORD;
552 break;
554 case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION :
555 case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_SELECTION :
556 aGUID = CLIENTID_FILESAVE_SELECTION;
557 break;
559 case css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_TEMPLATE :
560 aGUID = CLIENTID_FILESAVE_TEMPLATE;
561 break;
563 case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE :
564 aGUID = CLIENTID_FILEOPEN_LINK_TEMPLATE;
565 break;
567 case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR :
568 aGUID = CLIENTID_FILEOPEN_LINK_ANCHOR;
569 break;
571 case css::ui::dialogs::TemplateDescription::FILEOPEN_PLAY :
572 case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PLAY :
573 aGUID = CLIENTID_FILEOPEN_PLAY;
574 break;
576 case css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW :
577 aGUID = CLIENTID_FILEOPEN_LINK;
578 break;
580 TFileDialog iDialog = impl_getBaseDialogInterface();
581 if (iDialog.is())
582 iDialog->SetClientGuid ( aGUID );
584 TFileDialogCustomize iCustom = impl_getCustomizeInterface();
585 if (!iCustom.is())
586 return;
588 if ((nFeatures & FEATURE_VERSION) == FEATURE_VERSION)
590 iCustom->StartVisualGroup (GROUP_VERSION, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_VERSION).replaceFirst("~","").getStr()));
591 iCustom->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_VERSION);
592 iCustom->EndVisualGroup ();
593 iCustom->MakeProminent (GROUP_VERSION);
596 if ((nFeatures & FEATURE_TEMPLATE) == FEATURE_TEMPLATE)
598 iCustom->StartVisualGroup (GROUP_TEMPLATE, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_TEMPLATES).replaceFirst("~","").getStr()));
599 iCustom->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_TEMPLATE);
600 iCustom->EndVisualGroup ();
601 iCustom->MakeProminent (GROUP_TEMPLATE);
604 if ((nFeatures & FEATURE_IMAGETEMPLATE) == FEATURE_IMAGETEMPLATE)
606 iCustom->StartVisualGroup (GROUP_IMAGETEMPLATE, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_IMAGE_TEMPLATE).replaceFirst("~","").getStr()));
607 iCustom->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE);
608 iCustom->EndVisualGroup ();
609 iCustom->MakeProminent (GROUP_IMAGETEMPLATE);
612 if ((nFeatures & FEATURE_IMAGEANCHOR) == FEATURE_IMAGEANCHOR)
614 iCustom->StartVisualGroup (GROUP_IMAGEANCHOR, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_IMAGE_ANCHOR).replaceFirst("~","").getStr()));
615 iCustom->AddComboBox (css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR);
616 iCustom->EndVisualGroup ();
617 iCustom->MakeProminent (GROUP_IMAGEANCHOR);
620 iCustom->StartVisualGroup (GROUP_CHECKBOXES, L"");
622 sal_uInt16 nControlId(0);
623 if ((nFeatures & FEATURE_AUTOEXTENSION) == FEATURE_AUTOEXTENSION)
625 nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION;
626 iCustom->AddCheckButton (nControlId, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_AUTO_EXTENSION).replaceFirst("~","").getStr()), true);
627 setLabelToControl(iCustom, nControlId);
630 if ((nFeatures & FEATURE_PASSWORD) == FEATURE_PASSWORD)
632 nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PASSWORD;
633 iCustom->AddCheckButton (nControlId, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_PASSWORD).replaceFirst("~","").getStr()), false);
634 setLabelToControl(iCustom, nControlId);
637 if ((nFeatures & FEATURE_GPGPASSWORD) == FEATURE_GPGPASSWORD)
639 nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_GPGENCRYPTION;
640 iCustom->AddCheckButton (nControlId, L"GpgPassword", false);
641 setLabelToControl(iCustom, nControlId);
644 if ((nFeatures & FEATURE_GPGSIGN) == FEATURE_GPGSIGN)
646 nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_GPGSIGN;
647 iCustom->AddCheckButton (nControlId, L"GpgSign", false);
648 setLabelToControl(iCustom, nControlId);
651 if ((nFeatures & FEATURE_READONLY) == FEATURE_READONLY)
653 nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY;
654 iCustom->AddCheckButton (nControlId, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_READONLY).replaceFirst("~","").getStr()), false);
655 setLabelToControl(iCustom, nControlId);
658 if ((nFeatures & FEATURE_FILTEROPTIONS) == FEATURE_FILTEROPTIONS)
660 nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS;
661 iCustom->AddCheckButton (nControlId, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_FILTER_OPTIONS).replaceFirst("~","").getStr()), false);
662 setLabelToControl(iCustom, nControlId);
665 if ((nFeatures & FEATURE_LINK) == FEATURE_LINK)
667 nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK;
668 iCustom->AddCheckButton (nControlId, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_INSERT_AS_LINK).replaceFirst("~","").getStr()), false);
669 setLabelToControl(iCustom, nControlId);
672 if ((nFeatures & FEATURE_SELECTION) == FEATURE_SELECTION)
674 nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_SELECTION;
675 iCustom->AddCheckButton (nControlId, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_SELECTION).replaceFirst("~","").getStr()), false);
676 setLabelToControl(iCustom, nControlId);
679 /* can be ignored ... new COM dialog supports preview native now !
680 if ((nFeatures & FEATURE_PREVIEW) == FEATURE_PREVIEW)
681 iCustom->AddCheckButton (css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, L"Preview", false);
684 iCustom->EndVisualGroup();
686 if ((nFeatures & FEATURE_PLAY) == FEATURE_PLAY)
687 iCustom->AddPushButton (css::ui::dialogs::ExtendedFilePickerElementIds::PUSHBUTTON_PLAY, o3tl::toW(FpsResId(STR_SVT_FILEPICKER_PLAY).replaceFirst("~","").getStr()));
692 void VistaFilePickerImpl::impl_sta_SetMultiSelectionMode(Request& rRequest)
694 const bool bMultiSelection = rRequest.getArgumentOrDefault(PROP_MULTISELECTION_MODE, true);
696 TFileDialog iDialog = impl_getBaseDialogInterface();
697 if (!iDialog.is())
698 return;
700 DWORD nFlags = 0;
701 iDialog->GetOptions(&nFlags);
703 if (bMultiSelection)
704 nFlags |= FOS_ALLOWMULTISELECT;
705 else
706 nFlags &= ~FOS_ALLOWMULTISELECT;
708 iDialog->SetOptions ( nFlags );
712 void VistaFilePickerImpl::impl_sta_SetTitle(Request& rRequest)
714 OUString sTitle = rRequest.getArgumentOrDefault(PROP_TITLE, OUString());
716 TFileDialog iDialog = impl_getBaseDialogInterface();
717 if (!iDialog.is())
718 return;
720 iDialog->SetTitle(o3tl::toW(sTitle.getStr()));
724 void VistaFilePickerImpl::impl_sta_SetFileName(Request& rRequest)
726 OUString sFileName = rRequest.getArgumentOrDefault(PROP_FILENAME, OUString());
728 TFileDialog iDialog = impl_getBaseDialogInterface();
729 if (!iDialog.is())
730 return;
732 iDialog->SetFileName(o3tl::toW(sFileName.getStr()));
736 void VistaFilePickerImpl::impl_sta_SetDirectory(Request& rRequest)
738 OUString sDirectory = rRequest.getArgumentOrDefault(PROP_DIRECTORY, OUString());
740 if( !m_bInExecute)
742 // Vista stores last used folders for file dialogs
743 // so we don't want the application to change the folder
744 // in most cases.
745 // Store the requested folder in the meantime and decide later
746 // what to do
747 m_sDirectory = sDirectory;
750 TFileDialog iDialog = impl_getBaseDialogInterface();
751 if (!iDialog.is())
752 return;
754 sal::systools::COMReference<IShellItem> pFolder;
755 if ( !createFolderItem(sDirectory, pFolder) )
756 return;
758 iDialog->SetFolder(pFolder.get());
761 OUString VistaFilePickerImpl::GetDirectory()
763 TFileDialog iDialog = impl_getBaseDialogInterface();
764 if (!iDialog.is())
765 return OUString();
766 sal::systools::COMReference<IShellItem> pFolder;
767 HRESULT hResult = iDialog->GetFolder( &pFolder );
768 if ( FAILED(hResult) )
769 return OUString();
770 return lcl_getURLFromShellItem(pFolder.get());
773 void VistaFilePickerImpl::impl_sta_GetDirectory(Request& rRequest)
775 const OUString sFolder = m_sDirectory.isEmpty() ? GetDirectory() : m_sDirectory;
776 if (!sFolder.isEmpty())
777 rRequest.setArgument(PROP_DIRECTORY, sFolder);
780 void VistaFilePickerImpl::impl_sta_SetDefaultName(Request& rRequest)
782 OUString sFilename = rRequest.getArgumentOrDefault(PROP_FILENAME, OUString());
783 TFileDialog iDialog = impl_getBaseDialogInterface();
784 if (!iDialog.is())
785 return;
787 TFileDialogCustomize iCustom = impl_getCustomizeInterface();
788 if ( ! iCustom.is())
789 return;
791 // if we have the autoextension check box set, remove (or change ???) the extension of the filename
792 // so that the autoextension mechanism can do its job
793 BOOL bValue = FALSE;
794 HRESULT hResult = iCustom->GetCheckButtonState( css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, &bValue);
795 if ( FAILED(hResult) )
796 return;
797 if ( bValue )
799 sal_Int32 nSepPos = sFilename.lastIndexOf( '.' );
800 if ( -1 != nSepPos )
801 sFilename = sFilename.copy(0, nSepPos);
804 iDialog->SetFileName (o3tl::toW(sFilename.getStr()));
805 m_sFilename = sFilename;
809 void VistaFilePickerImpl::impl_sta_setFiltersOnDialog()
811 std::vector<OUString> vStrings; // to hold the adjusted filter names, pointers to which will be
812 // stored in lFilters
813 ::std::vector< COMDLG_FILTERSPEC > lFilters = lcl_buildFilterList(m_lFilters, vStrings);
814 OUString sCurrentFilter = m_lFilters.getCurrentFilter();
815 sal_Int32 nCurrentFilter = m_lFilters.getFilterPos(sCurrentFilter);
816 TFileDialog iDialog = impl_getBaseDialogInterface();
817 if (!iDialog.is())
818 return;
819 TFileDialogCustomize iCustomize = impl_getCustomizeInterface();
820 if (!iCustomize.is())
821 return;
823 if (lFilters.empty())
824 return;
826 COMDLG_FILTERSPEC *pFilt = lFilters.data();
827 iDialog->SetFileTypes(lFilters.size(), pFilt/*&lFilters[0]*/);
828 iDialog->SetFileTypeIndex(nCurrentFilter + 1);
830 BOOL bValue = FALSE;
831 HRESULT hResult = iCustomize->GetCheckButtonState( css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, &bValue);
832 if ( FAILED(hResult) )
833 return;
835 if ( bValue )
837 PCWSTR lpFilterExt = lFilters[0].pszSpec;
839 lpFilterExt = wcsrchr( lpFilterExt, '.' );
840 if ( lpFilterExt )
841 lpFilterExt++;
842 iDialog->SetDefaultExtension( lpFilterExt );
848 void VistaFilePickerImpl::impl_sta_getSelectedFiles(Request& rRequest)
850 if (m_pDialog == nullptr)
851 return;
853 // ask dialog for results
854 // we must react different if dialog is in execute or not .-(
855 sal::systools::COMReference<IShellItemArray> iItems = m_pDialog->getResult(m_bInExecute);
856 if (!iItems.is())
857 return;
859 // convert and pack results
860 std::vector< OUString > lFiles;
861 if (DWORD nCount; SUCCEEDED(iItems->GetCount(&nCount)))
863 for (DWORD i = 0; i < nCount; ++i)
865 if (sal::systools::COMReference<IShellItem> iItem;
866 SUCCEEDED(iItems->GetItemAt(i, &iItem)))
868 if (const OUString sURL = lcl_getURLFromShellItem(iItem.get()); !sURL.isEmpty())
869 lFiles.push_back(sURL);
874 rRequest.setArgument(PROP_SELECTED_FILES, comphelper::containerToSequence(lFiles));
878 void VistaFilePickerImpl::impl_sta_ShowDialogModal(Request& rRequest)
880 impl_sta_setFiltersOnDialog();
882 TFileDialog iDialog = impl_getBaseDialogInterface();
883 if (!iDialog.is())
884 return;
886 // it's important to know if we are showing the dialog.
887 // Some dialog interface methods can't be called then or some
888 // tasks must be done differently .-) (e.g. see impl_sta_getSelectedFiles())
889 m_bInExecute = true;
891 m_bWasExecuted = true;
893 // we set the directory only if we have a save dialog and a filename
894 // for the other cases, the file dialog remembers its last location
895 // according to its client guid.
896 if( m_sDirectory.getLength())
898 sal::systools::COMReference<IShellItem> pFolder;
899 if ( createFolderItem(m_sDirectory, pFolder) )
901 if (m_sFilename.getLength())
903 OUString aFileURL(m_sDirectory);
904 sal_Int32 nIndex = aFileURL.lastIndexOf('/');
905 if (nIndex != aFileURL.getLength()-1)
906 aFileURL += "/";
907 aFileURL += m_sFilename;
909 TFileDialogCustomize iCustom = impl_getCustomizeInterface();
910 if (!iCustom.is())
911 return;
913 BOOL bValue = FALSE;
914 HRESULT hResult = iCustom->GetCheckButtonState( css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, &bValue);
915 if ( bValue )
917 UINT nFileType;
918 hResult = iDialog->GetFileTypeIndex(&nFileType);
919 if ( SUCCEEDED(hResult) && nFileType > 0 )
921 // COM dialog base on 1 ... filter container on 0 .-)
922 ::size_t nRealIndex = nFileType-1;
923 OUString sFilter;
924 if (m_lFilters.getFilterByIndex(nRealIndex, sFilter))
926 const sal_Int32 idx = sFilter.indexOf('.');
927 if (idx >= 0)
928 aFileURL += sFilter.subView(idx);
933 // Check existence of file. Set folder only for this special case
934 OUString aSystemPath;
935 osl_getSystemPathFromFileURL( aFileURL.pData, &aSystemPath.pData );
937 WIN32_FIND_DATAW aFindFileData;
938 HANDLE hFind = FindFirstFileW( o3tl::toW(aSystemPath.getStr()), &aFindFileData );
939 if (hFind != INVALID_HANDLE_VALUE)
940 iDialog->SetFolder(pFolder.get());
941 else
942 hResult = iDialog->AddPlace(pFolder.get(), FDAP_TOP);
944 FindClose( hFind );
946 else
947 iDialog->AddPlace(pFolder.get(), FDAP_TOP);
951 HRESULT hResult = E_FAIL;
954 // tdf#146007: Make sure we don't hold solar mutex: COM may need to forward
955 // the execution to the main thread, and holding solar mutex could deadlock
956 SolarMutexReleaser r;
957 // show dialog and wait for user decision
958 hResult = iDialog->Show(m_hParentWindow ? m_hParentWindow
959 : choose_parent_window()); // parent window needed
961 catch(...)
964 m_bInExecute = false;
966 if (m_iEventHandler.is())
968 auto* pHandlerImpl = static_cast<VistaFilePickerEventHandler*>(m_iEventHandler.get());
969 pHandlerImpl->stopListening();
972 if ( FAILED(hResult) )
973 return;
975 impl_sta_getSelectedFiles(rRequest);
976 rRequest.setArgument(PROP_DIALOG_SHOW_RESULT, true);
980 TFileDialog VistaFilePickerImpl::impl_getBaseDialogInterface()
982 TFileDialog iDialog;
984 if (m_pDialog != nullptr)
985 iDialog = m_pDialog->getComPtr();
987 return iDialog;
991 TFileDialogCustomize VistaFilePickerImpl::impl_getCustomizeInterface()
993 if (m_pDialog != nullptr)
994 return { m_pDialog->getComPtr(), sal::systools::COM_QUERY_THROW };
996 return {};
1000 static void lcl_removeControlItemsWorkaround(const TFileDialogCustomize& iCustom ,
1001 ::sal_Int16 nControlId)
1003 (void)iCustom->SetSelectedControlItem(nControlId, 1000); // Don't care if this fails (useless?)
1004 DWORD i = 0;
1005 HRESULT hResult = S_OK;
1006 while ( SUCCEEDED(hResult) )
1007 hResult = iCustom->RemoveControlItem(nControlId, i++);
1011 void VistaFilePickerImpl::impl_sta_SetControlValue(Request& rRequest)
1013 ::sal_Int16 nId = rRequest.getArgumentOrDefault(PROP_CONTROL_ID , INVALID_CONTROL_ID );
1014 ::sal_Int16 nAction = rRequest.getArgumentOrDefault(PROP_CONTROL_ACTION, INVALID_CONTROL_ACTION);
1015 css::uno::Any aValue = rRequest.getValue(PROP_CONTROL_VALUE);
1017 // don't check for right values here ...
1018 // most parameters are optional !
1020 TFileDialogCustomize iCustom = impl_getCustomizeInterface();
1021 if ( ! iCustom.is())
1022 return;
1024 switch (nId)
1026 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION :
1027 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PASSWORD :
1028 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY :
1029 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS :
1030 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK :
1031 //case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PREVIEW : // can be ignored ... preview is supported native now !
1032 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_SELECTION :
1034 bool bValue = false;
1035 aValue >>= bValue;
1036 iCustom->SetCheckButtonState(nId, bValue);
1038 break;
1040 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_VERSION :
1041 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_TEMPLATE :
1042 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE :
1043 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR :
1045 HRESULT hResult;
1046 switch (nAction)
1048 case css::ui::dialogs::ControlActions::DELETE_ITEMS :
1050 hResult = iCustom->RemoveAllControlItems(nId);
1051 if ( FAILED(hResult) )
1052 lcl_removeControlItemsWorkaround(iCustom, nId);
1054 break;
1056 case css::ui::dialogs::ControlActions::ADD_ITEMS :
1058 aValue >>= m_lItems;
1059 for (::sal_Int32 i=0; i<m_lItems.getLength(); ++i)
1061 const OUString& sItem = m_lItems[i];
1062 hResult = iCustom->AddControlItem(nId, i, o3tl::toW(sItem.getStr()));
1065 break;
1067 case css::ui::dialogs::ControlActions::SET_SELECT_ITEM :
1069 ::sal_Int32 nItem = 0;
1070 aValue >>= nItem;
1071 hResult = iCustom->SetSelectedControlItem(nId, nItem);
1073 break;
1076 break;
1078 case css::ui::dialogs::ExtendedFilePickerElementIds::PUSHBUTTON_PLAY :
1081 break;
1086 void VistaFilePickerImpl::impl_sta_GetControlValue(Request& rRequest)
1088 ::sal_Int16 nId = rRequest.getArgumentOrDefault(PROP_CONTROL_ID , INVALID_CONTROL_ID );
1090 // don't check for right values here ...
1091 // most parameters are optional !
1093 TFileDialogCustomize iCustom = impl_getCustomizeInterface();
1094 if ( ! iCustom.is())
1095 return;
1097 css::uno::Any aValue;
1098 if( m_bWasExecuted )
1099 switch (nId)
1101 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PASSWORD :
1102 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_GPGENCRYPTION :
1103 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_GPGSIGN :
1104 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY :
1105 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS :
1106 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK :
1107 //case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PREVIEW : // can be ignored ... preview is supported native now !
1108 case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_SELECTION :
1110 BOOL bValue = FALSE;
1111 HRESULT hResult = iCustom->GetCheckButtonState(nId, &bValue);
1112 if ( SUCCEEDED(hResult) )
1113 aValue <<= bool(bValue);
1115 break;
1116 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_VERSION:
1117 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_TEMPLATE:
1118 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_TEMPLATE:
1119 case css::ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR:
1121 DWORD bValue = 0;
1122 HRESULT hResult = iCustom->GetSelectedControlItem(nId, &bValue);
1123 if ( SUCCEEDED(hResult) )
1125 const OUString& sItem = m_lItems[bValue];
1126 aValue <<= sItem;
1129 break;
1132 if (aValue.hasValue())
1133 rRequest.setArgument(PROP_CONTROL_VALUE, aValue);
1137 void VistaFilePickerImpl::impl_sta_SetControlLabel(Request& rRequest)
1139 ::sal_Int16 nId = rRequest.getArgumentOrDefault(PROP_CONTROL_ID , INVALID_CONTROL_ID );
1140 OUString sLabel = rRequest.getArgumentOrDefault(PROP_CONTROL_LABEL, OUString() );
1142 // don't check for right values here ...
1143 // most parameters are optional !
1145 TFileDialogCustomize iCustom = impl_getCustomizeInterface();
1146 if ( ! iCustom.is())
1147 return;
1148 iCustom->SetControlLabel (nId, o3tl::toW(sLabel.getStr()));
1152 void VistaFilePickerImpl::impl_sta_GetControlLabel(Request& /*rRequest*/)
1157 void VistaFilePickerImpl::impl_sta_EnableControl(Request& rRequest)
1159 ::sal_Int16 nId = rRequest.getArgumentOrDefault(PROP_CONTROL_ID , INVALID_CONTROL_ID );
1160 bool bEnabled = rRequest.getArgumentOrDefault(PROP_CONTROL_ENABLE, true);
1162 // don't check for right values here ...
1163 // most parameters are optional !
1165 TFileDialogCustomize iCustom = impl_getCustomizeInterface();
1166 if ( ! iCustom.is())
1167 return;
1169 CDCONTROLSTATEF eState = CDCS_VISIBLE;
1170 if (bEnabled)
1171 eState |= CDCS_ENABLED;
1172 else
1173 eState |= CDCS_INACTIVE;
1175 iCustom->SetControlState(nId, eState);
1178 void VistaFilePickerImpl::impl_SetDefaultExtension( const OUString& currentFilter )
1180 TFileDialog iDialog = impl_getBaseDialogInterface();
1181 if (!iDialog.is())
1182 return;
1184 if (currentFilter.getLength())
1186 OUString FilterExt;
1187 m_lFilters.getFilterByName(currentFilter, FilterExt);
1189 sal_Int32 posOfPoint = FilterExt.indexOf(L'.');
1190 const sal_Unicode* pFirstExtStart = FilterExt.getStr() + posOfPoint + 1;
1192 sal_Int32 posOfSemiColon = FilterExt.indexOf(L';') - 1;
1193 if (posOfSemiColon < 0)
1194 posOfSemiColon = FilterExt.getLength() - 1;
1196 FilterExt = OUString(pFirstExtStart, posOfSemiColon - posOfPoint);
1197 iDialog->SetDefaultExtension ( o3tl::toW(FilterExt.getStr()) );
1201 void VistaFilePickerImpl::onAutoExtensionChanged (bool bChecked)
1203 const OUString sFilter = m_lFilters.getCurrentFilter ();
1204 OUString sExt ;
1205 if (!m_lFilters.getFilterByName(sFilter, sExt))
1206 return;
1208 TFileDialog iDialog = impl_getBaseDialogInterface();
1209 if (!iDialog.is())
1210 return;
1212 PCWSTR pExt = nullptr;
1213 if ( bChecked )
1215 pExt = o3tl::toW(sExt.getStr());
1216 pExt = wcsrchr( pExt, '.' );
1217 if ( pExt )
1218 pExt++;
1220 iDialog->SetDefaultExtension( pExt );
1223 bool VistaFilePickerImpl::onFileTypeChanged( UINT /*nTypeIndex*/ )
1225 return true;
1228 void VistaFilePickerImpl::onDirectoryChanged()
1230 m_sDirectory = GetDirectory();
1233 } // namespace vista
1234 } // namespace win32
1235 } // namespace fpicker
1237 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */