diff --git a/dev/Common/TerminalVelocityFeatures-StoragePickers2.h b/dev/Common/TerminalVelocityFeatures-StoragePickers2.h new file mode 100644 index 0000000000..e44c4cfaa5 --- /dev/null +++ b/dev/Common/TerminalVelocityFeatures-StoragePickers2.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +// THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT IT + +// INPUT FILE: dev\Common\TerminalVelocityFeatures-StoragePickers2.xml +// OPTIONS: -Channel Experimental -Language C++ -Namespace Microsoft.Windows.Storage.Pickers -Path dev\Common\TerminalVelocityFeatures-StoragePickers2.xml -Output dev\Common\TerminalVelocityFeatures-StoragePickers2.h + +#if defined(__midlrt) +namespace features +{ + feature_name Feature_StoragePickers2 = { DisabledByDefault, FALSE }; +} +#endif // defined(__midlrt) + +// Feature constants +#define WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_STORAGE_PICKERS_FEATURE_STORAGEPICKERS2_ENABLED 1 + +#if defined(__cplusplus) + +namespace Microsoft::Windows::Storage::Pickers +{ + +__pragma(detect_mismatch("ODR_violation_WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_STORAGE_PICKERS_FEATURE_STORAGEPICKERS2_ENABLED_mismatch", "AlwaysEnabled")) +struct Feature_StoragePickers2 +{ + static constexpr bool IsEnabled() { return WINDOWSAPPRUNTIME_MICROSOFT_WINDOWS_STORAGE_PICKERS_FEATURE_STORAGEPICKERS2_ENABLED == 1; } +}; + +} // namespace Microsoft.Windows.Storage.Pickers + +#endif // defined(__cplusplus) diff --git a/dev/Common/TerminalVelocityFeatures-StoragePickers2.xml b/dev/Common/TerminalVelocityFeatures-StoragePickers2.xml new file mode 100644 index 0000000000..b878a8128f --- /dev/null +++ b/dev/Common/TerminalVelocityFeatures-StoragePickers2.xml @@ -0,0 +1,20 @@ + + + + + + + + + + Feature_StoragePickers2 + New functionalities in StoragePickers for the WindowsAppRuntime: SuggestedDefaultFolder, FileTypeChoices + AlwaysEnabled + + Preview + Stable + + + diff --git a/dev/Interop/StoragePickers/FileOpenPicker.cpp b/dev/Interop/StoragePickers/FileOpenPicker.cpp index 775e6411ab..b61792f9ac 100644 --- a/dev/Interop/StoragePickers/FileOpenPicker.cpp +++ b/dev/Interop/StoragePickers/FileOpenPicker.cpp @@ -10,6 +10,7 @@ #include #include #include "TerminalVelocityFeatures-StoragePickers.h" +#include "TerminalVelocityFeatures-StoragePickers2.h" #include "PickerCommon.h" #include "PickFileResult.h" #include "PickerLocalization.h" @@ -49,17 +50,46 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation PickerCommon::ValidateStringNoEmbeddedNulls(value); m_commitButtonText = value; } - winrt::Windows::Foundation::Collections::IVector FileOpenPicker::FileTypeFilter() + winrt::Windows::Foundation::Collections::IMap> FileOpenPicker::FileTypeChoices() + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + return m_fileTypeChoices; + } + winrt::Windows::Foundation::Collections::IVector FileOpenPicker::FileTypeFilter() { return m_fileTypeFilter; } + winrt::hstring FileOpenPicker::SuggestedFolder() + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + return m_suggestedFolder; + } + void FileOpenPicker::SuggestedFolder(winrt::hstring const& value) + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + PickerCommon::ValidateFolderPath(value, "SuggestedFolder"); + m_suggestedFolder = value; + } + winrt::hstring FileOpenPicker::SuggestedStartFolder() + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + return m_suggestedStartFolder; + } + void FileOpenPicker::SuggestedStartFolder(winrt::hstring const& value) + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + PickerCommon::ValidateFolderPath(value, "SuggestedStartFolder"); + m_suggestedStartFolder = value; + } void FileOpenPicker::CaptureParameters(PickerCommon::PickerParameters& parameters) { parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); parameters.CommitButtonText = m_commitButtonText; - parameters.PickerLocationId = m_suggestedStartLocation; - parameters.CaptureFilterSpec(m_fileTypeFilter.GetView()); + parameters.SuggestedFolder = m_suggestedFolder; + parameters.SuggestedStartLocation = m_suggestedStartLocation; + parameters.SuggestedStartFolder = m_suggestedStartFolder; + parameters.CaptureFilterSpecData(m_fileTypeFilter.GetView(), m_fileTypeChoices.GetView()); } winrt::Windows::Foundation::IAsyncOperation FileOpenPicker::PickSingleFileAsync() @@ -87,7 +117,6 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation auto dialog = create_instance(CLSID_FileOpenDialog, CLSCTX_INPROC_SERVER); parameters.ConfigureDialog(dialog); - check_hresult(dialog->SetFileTypeIndex(parameters.FileTypeFilterPara.size())); { auto hr = dialog->Show(parameters.HWnd); @@ -142,7 +171,6 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation auto dialog = create_instance(CLSID_FileOpenDialog, CLSCTX_INPROC_SERVER); parameters.ConfigureDialog(dialog); - check_hresult(dialog->SetFileTypeIndex(parameters.FileTypeFilterPara.size())); FILEOPENDIALOGOPTIONS dialogOptions; check_hresult(dialog->GetOptions(&dialogOptions)); diff --git a/dev/Interop/StoragePickers/FileOpenPicker.h b/dev/Interop/StoragePickers/FileOpenPicker.h index 47353b6310..c5ff80bc27 100644 --- a/dev/Interop/StoragePickers/FileOpenPicker.h +++ b/dev/Interop/StoragePickers/FileOpenPicker.h @@ -6,6 +6,7 @@ #include "PickerCommon.h" #include "StoragePickersTelemetryHelper.h" #include +#include "FileTypeChoicesMap.h" #include "FileTypeFilterVector.h" namespace winrt::Microsoft::Windows::Storage::Pickers::implementation @@ -23,7 +24,14 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation winrt::hstring CommitButtonText(); void CommitButtonText(winrt::hstring const& value); - winrt::Windows::Foundation::Collections::IVector FileTypeFilter(); + winrt::Windows::Foundation::Collections::IVector FileTypeFilter(); + winrt::Windows::Foundation::Collections::IMap> FileTypeChoices(); + + winrt::hstring SuggestedFolder(); + void SuggestedFolder(winrt::hstring const& value); + + winrt::hstring SuggestedStartFolder(); + void SuggestedStartFolder(winrt::hstring const& value); winrt::Windows::Foundation::IAsyncOperation PickSingleFileAsync(); winrt::Windows::Foundation::IAsyncOperation> PickMultipleFilesAsync(); @@ -34,7 +42,18 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation PickerLocationId m_suggestedStartLocation{ PickerLocationId::Unspecified }; winrt::hstring m_commitButtonText{}; - winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ make() }; + winrt::Windows::Foundation::Collections::IVector m_fileTypeFilter{ make() }; + winrt::Windows::Foundation::Collections::IMap> m_fileTypeChoices{ + []() + { + auto map = winrt::make_self(); + map->ForFeature_StoragePickers2 = true; + return map.as>>(); + }() + }; + + winrt::hstring m_suggestedFolder{}; + winrt::hstring m_suggestedStartFolder{}; StoragePickersTelemetryHelper m_telemetryHelper{}; diff --git a/dev/Interop/StoragePickers/FileSavePicker.cpp b/dev/Interop/StoragePickers/FileSavePicker.cpp index aa1f091b53..95e965be00 100644 --- a/dev/Interop/StoragePickers/FileSavePicker.cpp +++ b/dev/Interop/StoragePickers/FileSavePicker.cpp @@ -15,6 +15,7 @@ #include #include #include "TerminalVelocityFeatures-StoragePickers.h" +#include "TerminalVelocityFeatures-StoragePickers2.h" #include "PickerCommon.h" #include "PickerLocalization.h" #include "PickFileResult.h" @@ -63,10 +64,22 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation } void FileSavePicker::SuggestedFolder(hstring const& value) { - PickerCommon::ValidateSuggestedFolder(value); + PickerCommon::ValidateFolderPath(value, "SuggestedFolder"); m_suggestedFolder = value; } + hstring FileSavePicker::SuggestedStartFolder() + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + return m_suggestedStartFolder; + } + void FileSavePicker::SuggestedStartFolder(hstring const& value) + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + PickerCommon::ValidateFolderPath(value, "SuggestedStartFolder"); + m_suggestedStartFolder = value; + } + hstring FileSavePicker::SuggestedFileName() { return m_suggestedFileName; @@ -82,10 +95,13 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation { parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); parameters.CommitButtonText = m_commitButtonText; - parameters.PickerLocationId = m_suggestedStartLocation; parameters.SuggestedFileName = m_suggestedFileName; parameters.SuggestedFolder = m_suggestedFolder; - parameters.CaptureFilterSpec(m_fileTypeChoices.GetView()); + parameters.SuggestedStartLocation = m_suggestedStartLocation; + parameters.SuggestedStartFolder = m_suggestedStartFolder; + parameters.CaptureFilterSpecData( + winrt::Windows::Foundation::Collections::IVectorView{}, + m_fileTypeChoices.GetView()); } winrt::Windows::Foundation::IAsyncOperation FileSavePicker::PickSaveFileAsync() diff --git a/dev/Interop/StoragePickers/FileSavePicker.h b/dev/Interop/StoragePickers/FileSavePicker.h index 59a3eb977a..849c819819 100644 --- a/dev/Interop/StoragePickers/FileSavePicker.h +++ b/dev/Interop/StoragePickers/FileSavePicker.h @@ -29,6 +29,9 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation hstring SuggestedFolder(); void SuggestedFolder(hstring const& value); + hstring SuggestedStartFolder(); + void SuggestedStartFolder(hstring const& value); + hstring SuggestedFileName(); void SuggestedFileName(hstring const& value); @@ -41,6 +44,7 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation winrt::Windows::Foundation::Collections::IMap> m_fileTypeChoices{ make() }; hstring m_defaultFileExtension{}; hstring m_suggestedFolder{}; + hstring m_suggestedStartFolder{}; hstring m_suggestedFileName{}; StoragePickersTelemetryHelper m_telemetryHelper{}; diff --git a/dev/Interop/StoragePickers/FileTypeChoicesMap.cpp b/dev/Interop/StoragePickers/FileTypeChoicesMap.cpp index 3f04a4a373..0d8571ed8b 100644 --- a/dev/Interop/StoragePickers/FileTypeChoicesMap.cpp +++ b/dev/Interop/StoragePickers/FileTypeChoicesMap.cpp @@ -4,6 +4,7 @@ #include "pch.h" #include "FileTypeChoicesMap.h" #include "FileTypeFilterVector.h" +#include "TerminalVelocityFeatures-StoragePickers2.h" namespace winrt::Microsoft::Windows::Storage::Pickers::implementation { @@ -13,6 +14,11 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation bool FileTypeChoicesMap::Insert(hstring const& key, winrt::Windows::Foundation::Collections::IVector const& value) { + if (ForFeature_StoragePickers2) + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + } + // Create a new FileTypeFilterVector and copy all values from the input vector auto validatingVector = make(); diff --git a/dev/Interop/StoragePickers/FileTypeChoicesMap.h b/dev/Interop/StoragePickers/FileTypeChoicesMap.h index 0f1e2a1a87..1dc6143667 100644 --- a/dev/Interop/StoragePickers/FileTypeChoicesMap.h +++ b/dev/Interop/StoragePickers/FileTypeChoicesMap.h @@ -13,6 +13,8 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation { FileTypeChoicesMap(); + bool ForFeature_StoragePickers2{ false }; + // IMap> winrt::Windows::Foundation::Collections::IVector Lookup(hstring const& key) const; uint32_t Size() const; diff --git a/dev/Interop/StoragePickers/FolderPicker.cpp b/dev/Interop/StoragePickers/FolderPicker.cpp index c95a581607..5da7ab331e 100644 --- a/dev/Interop/StoragePickers/FolderPicker.cpp +++ b/dev/Interop/StoragePickers/FolderPicker.cpp @@ -9,6 +9,7 @@ #include #include #include "TerminalVelocityFeatures-StoragePickers.h" +#include "TerminalVelocityFeatures-StoragePickers2.h" #include "PickerCommon.h" #include "PickFolderResult.h" #include "PickerLocalization.h" @@ -47,15 +48,38 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation PickerCommon::ValidateStringNoEmbeddedNulls(value); m_commitButtonText = value; } + hstring FolderPicker::SuggestedFolder() + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + return m_suggestedFolder; + } + void FolderPicker::SuggestedFolder(hstring const& value) + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + PickerCommon::ValidateFolderPath(value, "SuggestedFolder"); + m_suggestedFolder = value; + } + hstring FolderPicker::SuggestedStartFolder() + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + return m_suggestedStartFolder; + } + void FolderPicker::SuggestedStartFolder(hstring const& value) + { + THROW_HR_IF(E_NOTIMPL, !::Microsoft::Windows::Storage::Pickers::Feature_StoragePickers2::IsEnabled()); + PickerCommon::ValidateFolderPath(value, "SuggestedStartFolder"); + m_suggestedStartFolder = value; + } void FolderPicker::CaptureParameters(PickerCommon::PickerParameters& parameters) { parameters.HWnd = winrt::Microsoft::UI::GetWindowFromWindowId(m_windowId); parameters.CommitButtonText = m_commitButtonText; - parameters.PickerLocationId = m_suggestedStartLocation; + parameters.SuggestedFolder = m_suggestedFolder; + parameters.SuggestedStartLocation = m_suggestedStartLocation; + parameters.SuggestedStartFolder = m_suggestedStartFolder; } - winrt::Windows::Foundation::IAsyncOperation FolderPicker::PickSingleFolderAsync() { // TODO: remove get strong reference when telementry is safe stop diff --git a/dev/Interop/StoragePickers/FolderPicker.h b/dev/Interop/StoragePickers/FolderPicker.h index f5e8f88136..49e7c4b1f7 100644 --- a/dev/Interop/StoragePickers/FolderPicker.h +++ b/dev/Interop/StoragePickers/FolderPicker.h @@ -21,6 +21,12 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation hstring CommitButtonText(); void CommitButtonText(hstring const& value); + hstring SuggestedFolder(); + void SuggestedFolder(hstring const& value); + + hstring SuggestedStartFolder(); + void SuggestedStartFolder(hstring const& value); + winrt::Windows::Foundation::IAsyncOperation PickSingleFolderAsync(); private: @@ -29,6 +35,8 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation PickerViewMode m_viewMode{ PickerViewMode::List }; PickerLocationId m_suggestedStartLocation{ PickerLocationId::Unspecified }; hstring m_commitButtonText{}; + hstring m_suggestedFolder{}; + hstring m_suggestedStartFolder{}; StoragePickersTelemetryHelper m_telemetryHelper{}; void CaptureParameters(PickerCommon::PickerParameters& parameters); diff --git a/dev/Interop/StoragePickers/Microsoft.Windows.Storage.Pickers.idl b/dev/Interop/StoragePickers/Microsoft.Windows.Storage.Pickers.idl index 895fb2c621..c71d622193 100644 --- a/dev/Interop/StoragePickers/Microsoft.Windows.Storage.Pickers.idl +++ b/dev/Interop/StoragePickers/Microsoft.Windows.Storage.Pickers.idl @@ -1,11 +1,13 @@ // Copyright (c) Microsoft Corporation and Contributors. // Licensed under the MIT License. +#include + namespace Microsoft.Windows.Storage.Pickers { - [contractversion(1.8)] + [contractversion(2.0)] apicontract StoragePickersContract {}; - + [contract(StoragePickersContract, 1.8)] enum PickerViewMode { @@ -41,8 +43,21 @@ namespace Microsoft.Windows.Storage.Pickers Microsoft.Windows.Storage.Pickers.PickerViewMode ViewMode; Microsoft.Windows.Storage.Pickers.PickerLocationId SuggestedStartLocation; String CommitButtonText; + + [contract(StoragePickersContract, 2.0)] + [feature(Feature_StoragePickers2)] + Windows.Foundation.Collections.IMap > FileTypeChoices{ get; }; + Windows.Foundation.Collections.IVector FileTypeFilter{ get; }; + [contract(StoragePickersContract, 2.0)] + [feature(Feature_StoragePickers2)] + String SuggestedFolder; + + [contract(StoragePickersContract, 2.0)] + [feature(Feature_StoragePickers2)] + String SuggestedStartFolder; + [remote_sync] Windows.Foundation.IAsyncOperation PickSingleFileAsync(); [remote_sync] Windows.Foundation.IAsyncOperation > PickMultipleFilesAsync(); } @@ -59,6 +74,10 @@ namespace Microsoft.Windows.Storage.Pickers String SuggestedFileName; String SuggestedFolder; + [contract(StoragePickersContract, 2.0)] + [feature(Feature_StoragePickers2)] + String SuggestedStartFolder; + [remote_sync] Windows.Foundation.IAsyncOperation PickSaveFileAsync(); } @@ -77,6 +96,14 @@ namespace Microsoft.Windows.Storage.Pickers Microsoft.Windows.Storage.Pickers.PickerLocationId SuggestedStartLocation; String CommitButtonText; + [contract(StoragePickersContract, 2.0)] + [feature(Feature_StoragePickers2)] + String SuggestedFolder; + + [contract(StoragePickersContract, 2.0)] + [feature(Feature_StoragePickers2)] + String SuggestedStartFolder; + [remote_sync] Windows.Foundation.IAsyncOperation PickSingleFolderAsync(); } } diff --git a/dev/Interop/StoragePickers/PickerCommon.cpp b/dev/Interop/StoragePickers/PickerCommon.cpp index dec7a50d3a..d5c003cc77 100644 --- a/dev/Interop/StoragePickers/PickerCommon.cpp +++ b/dev/Interop/StoragePickers/PickerCommon.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include namespace { @@ -224,7 +226,7 @@ namespace PickerCommon { ValidateStringNoEmbeddedNulls(suggestedFileName); } - void ValidateSuggestedFolder(winrt::hstring const& path) + void ValidateFolderPath(winrt::hstring const& path, std::string const& propertyName) { if (path.empty()) { @@ -237,13 +239,14 @@ namespace PickerCommon { auto pathObj = std::filesystem::path(path.c_str()); if (!pathObj.is_absolute()) { - throw std::invalid_argument("SuggestedFolder"); + throw std::invalid_argument(propertyName); } + // The method SHSimpleIDListFromPath does syntax check on the path string. wil::unique_cotaskmem_ptr pidl(SHSimpleIDListFromPath(path.c_str())); if (!pidl) { - throw std::invalid_argument("SuggestedFolder"); + throw std::invalid_argument(propertyName); } } @@ -278,6 +281,28 @@ namespace PickerCommon { return result; } + void PickerParameters::CaptureFilterSpecData( + winrt::Windows::Foundation::Collections::IVectorView fileTypeFilterView, + winrt::Windows::Foundation::Collections::IMapView> fileTypeChoicesView) + { + // The FileTypeChoices takes precedence over FileTypeFilter if both are provided. + if (fileTypeChoicesView && fileTypeChoicesView.Size() > 0) + { + CaptureFilterSpec(fileTypeChoicesView); + return; + } + + if (fileTypeFilterView && fileTypeFilterView.Size() > 0) + { + CaptureFilterSpec(fileTypeFilterView); + return; + } + + // Even if no filters provided, we still need to set filter to All Files *.* + auto emptyFilters = winrt::single_threaded_vector(); + CaptureFilterSpec(emptyFilters.GetView()); + } + /// /// Capture and processing pickers filter inputs and convert them into Common Item Dialog's accepting type, for FileOpenPicker /// @@ -330,6 +355,8 @@ namespace PickerCommon { { FileTypeFilterPara.push_back({ FileTypeFilterData.at(i * 2).c_str(), FileTypeFilterData.at(i * 2 + 1).c_str() }); } + + FocusLastFilter = true; } /// @@ -372,15 +399,41 @@ namespace PickerCommon { check_hresult(dialog->SetOkButtonLabel(CommitButtonText.c_str())); } - auto defaultFolder = GetKnownFolderFromId(PickerLocationId); - if (defaultFolder != nullptr) + winrt::com_ptr defaultFolder{}; + + // The SuggestedStartFolder takes precedence over SuggestedStartLocation if both are provided. + if (!IsHStringNullOrEmpty(SuggestedStartFolder)) + { + defaultFolder = TryParseFolderItem(SuggestedStartFolder); + } + + if (!defaultFolder) + { + defaultFolder = GetKnownFolderFromId(SuggestedStartLocation); + } + + if (defaultFolder) { check_hresult(dialog->SetDefaultFolder(defaultFolder.get())); } + // SuggestedFolder takes precedence over SuggestedStartFolder/SuggestedStartLocation if both are provided. + if (!IsHStringNullOrEmpty(SuggestedFolder)) + { + if (auto folderItem = TryParseFolderItem(SuggestedFolder)) + { + check_hresult(dialog->SetFolder(folderItem.get())); + } + } + if (FileTypeFilterPara.size() > 0) { check_hresult(dialog->SetFileTypes((UINT)FileTypeFilterPara.size(), FileTypeFilterPara.data())); + + if (FocusLastFilter) + { + check_hresult(dialog->SetFileTypeIndex(FileTypeFilterPara.size())); + } } } @@ -395,13 +448,5 @@ namespace PickerCommon { check_hresult(dialog->SetFileName(SuggestedFileName.c_str())); } - if (!PickerCommon::IsHStringNullOrEmpty(SuggestedFolder)) - { - winrt::com_ptr folderItem = TryParseFolderItem(SuggestedFolder); - if (folderItem) - { - check_hresult(dialog->SetFolder(folderItem.get())); - } - } } } diff --git a/dev/Interop/StoragePickers/PickerCommon.h b/dev/Interop/StoragePickers/PickerCommon.h index 124a9eb261..f2bc2045ab 100644 --- a/dev/Interop/StoragePickers/PickerCommon.h +++ b/dev/Interop/StoragePickers/PickerCommon.h @@ -26,26 +26,33 @@ namespace PickerCommon { void ValidateSuggestedStartLocation(winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId const& value); void ValidateSingleFileTypeFilterElement(winrt::hstring const& filter); void ValidateSuggestedFileName(winrt::hstring const& suggestedFileName); - void ValidateSuggestedFolder(winrt::hstring const& path); + void ValidateFolderPath(winrt::hstring const& path, std::string const& propertyName); struct PickerParameters { HWND HWnd{}; winrt::hstring CommitButtonText; - winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId PickerLocationId; + winrt::Microsoft::Windows::Storage::Pickers::PickerLocationId SuggestedStartLocation; std::vector FileTypeFilterData{}; std::vector FileTypeFilterPara{}; + bool FocusLastFilter{ false }; winrt::hstring AllFilesText{ L"All Files" }; // initialize to All Files as a default value, will be updated by localization winrt::hstring SuggestedFileName; winrt::hstring SuggestedFolder; + winrt::hstring SuggestedStartFolder; winrt::hstring FormatExtensionWithWildcard(winrt::hstring extension); winrt::hstring JoinExtensions(winrt::Windows::Foundation::Collections::IVectorView extensions); - void CaptureFilterSpec(winrt::Windows::Foundation::Collections::IVectorView filters); - void CaptureFilterSpec(winrt::Windows::Foundation::Collections::IMapView> filters); + void CaptureFilterSpecData( + winrt::Windows::Foundation::Collections::IVectorView fileTypeFilterView, + winrt::Windows::Foundation::Collections::IMapView> fileTypeChoicesView); void ConfigureDialog(winrt::com_ptr dialog); void ConfigureFileSaveDialog(winrt::com_ptr dialog); + + private: + void CaptureFilterSpec(winrt::Windows::Foundation::Collections::IVectorView filters); + void CaptureFilterSpec(winrt::Windows::Foundation::Collections::IMapView> filters); }; } diff --git a/test/StoragePickersTests/PickerCommonTests.cpp b/test/StoragePickersTests/PickerCommonTests.cpp index 29c870c7f8..555eec06a1 100644 --- a/test/StoragePickersTests/PickerCommonTests.cpp +++ b/test/StoragePickersTests/PickerCommonTests.cpp @@ -99,6 +99,7 @@ namespace Test::PickerCommonTests // Act. auto dialog = winrt::create_instance(CLSID_FileSaveDialog, CLSCTX_INPROC_SERVER); + parameters.ConfigureDialog(dialog.as()); parameters.ConfigureFileSaveDialog(dialog); // Assert. @@ -130,6 +131,7 @@ namespace Test::PickerCommonTests // Act. auto dialog = winrt::create_instance(CLSID_FileSaveDialog, CLSCTX_INPROC_SERVER); + parameters.ConfigureDialog(dialog.as()); parameters.ConfigureFileSaveDialog(dialog); // Assert. @@ -150,7 +152,7 @@ namespace Test::PickerCommonTests // Act. PickerParameters parameters{}; - parameters.CaptureFilterSpec(picker.FileTypeFilter().GetView()); + parameters.CaptureFilterSpecData(picker.FileTypeFilter().GetView(), nullptr); // Assert. VERIFY_ARE_EQUAL(parameters.FileTypeFilterPara.size(), 3); @@ -176,7 +178,7 @@ namespace Test::PickerCommonTests // Act. PickerParameters parameters{}; - parameters.CaptureFilterSpec(picker.FileTypeFilter().GetView()); + parameters.CaptureFilterSpecData(picker.FileTypeFilter().GetView(), nullptr); // Assert. VERIFY_ARE_EQUAL(parameters.FileTypeFilterPara.size(), 1); @@ -196,7 +198,7 @@ namespace Test::PickerCommonTests // Act. PickerParameters parameters{}; - parameters.CaptureFilterSpec(picker.FileTypeFilter().GetView()); + parameters.CaptureFilterSpecData(picker.FileTypeFilter().GetView(), nullptr); // Assert. VERIFY_ARE_EQUAL(parameters.FileTypeFilterPara.size(), 1); @@ -206,6 +208,34 @@ namespace Test::PickerCommonTests L"*"); } + TEST_METHOD(VerifyFilters_FileOpenPickerWhenFileTypeChoicesDefinedExpectMatchingSpec) + { + // Arrange. + winrt::Microsoft::UI::WindowId windowId{}; + winrt::Microsoft::Windows::Storage::Pickers::FileOpenPicker picker(windowId); + + picker.FileTypeChoices().Insert( + L"Documents", winrt::single_threaded_vector({ L".txt", L".doc", L".docx" })); + picker.FileTypeChoices().Insert( + L"Pictures", winrt::single_threaded_vector({ L".png", L".jpg", L".jpeg", L".bmp" })); + + // Act. + PickerParameters parameters{}; + parameters.CaptureFilterSpecData( + winrt::Windows::Foundation::Collections::IVectorView{}, + picker.FileTypeChoices().GetView()); + + // Assert. + VERIFY_ARE_EQUAL(parameters.FileTypeFilterPara.size(), 2); + + VERIFY_ARE_EQUAL( + std::wstring(parameters.FileTypeFilterPara[0].pszSpec), + L"*.txt;*.doc;*.docx"); + VERIFY_ARE_EQUAL( + std::wstring(parameters.FileTypeFilterPara[1].pszSpec), + L"*.png;*.jpg;*.jpeg;*.bmp"); + } + TEST_METHOD(VerifyFilters_FileSavePickerWhenFileTypeChoicesDefinedExpectMatchingSpec) { // Arrange. @@ -219,7 +249,9 @@ namespace Test::PickerCommonTests // Act. PickerParameters parameters{}; - parameters.CaptureFilterSpec(picker.FileTypeChoices().GetView()); + parameters.CaptureFilterSpecData( + winrt::Windows::Foundation::Collections::IVectorView{}, + picker.FileTypeChoices().GetView()); // Assert. VERIFY_ARE_EQUAL(parameters.FileTypeFilterPara.size(), 2); @@ -242,7 +274,9 @@ namespace Test::PickerCommonTests // Act. PickerParameters parameters{}; - parameters.CaptureFilterSpec(picker.FileTypeChoices().GetView()); + parameters.CaptureFilterSpecData( + winrt::Windows::Foundation::Collections::IVectorView{}, + picker.FileTypeChoices().GetView()); // Assert. VERIFY_ARE_EQUAL(parameters.FileTypeFilterPara.size(), 1); @@ -250,6 +284,9 @@ namespace Test::PickerCommonTests VERIFY_ARE_EQUAL( std::wstring(parameters.FileTypeFilterPara[0].pszSpec), L"*"); + VERIFY_ARE_EQUAL( + std::wstring(parameters.FileTypeFilterPara[0].pszName), + L"All Files"); } TEST_METHOD(VerifyFilters_FileSavePickerWhenAsteriskFileTypeChoicesDefinedExpectAsteriskSpec) @@ -265,7 +302,9 @@ namespace Test::PickerCommonTests // Act. PickerParameters parameters{}; - parameters.CaptureFilterSpec(picker.FileTypeChoices().GetView()); + parameters.CaptureFilterSpecData( + winrt::Windows::Foundation::Collections::IVectorView{}, + picker.FileTypeChoices().GetView()); // Assert. VERIFY_ARE_EQUAL(parameters.FileTypeFilterPara.size(), 1); @@ -628,6 +667,9 @@ namespace Test::PickerCommonTests { picker.SuggestedFolder(suggestedFolder); VERIFY_ARE_EQUAL(picker.SuggestedFolder(), suggestedFolder); + + picker.SuggestedStartFolder(suggestedFolder); + VERIFY_ARE_EQUAL(picker.SuggestedStartFolder(), suggestedFolder); } else { @@ -641,6 +683,17 @@ namespace Test::PickerCommonTests { // Expected exception for invalid suggested folder } + + try + { + picker.SuggestedStartFolder(suggestedFolder); + std::wstring errorMessage = L"Expected exception for invalid suggested start folder: " + std::wstring(suggestedFolder); + VERIFY_FAIL(errorMessage.c_str()); + } + catch (...) + { + // Expected exception for invalid suggested start folder + } } } } diff --git a/test/StoragePickersTests/StoragePickersTests.cpp b/test/StoragePickersTests/StoragePickersTests.cpp index 5c63b5a2d2..97721e7c2a 100644 --- a/test/StoragePickersTests/StoragePickersTests.cpp +++ b/test/StoragePickersTests/StoragePickersTests.cpp @@ -153,6 +153,17 @@ namespace Test::StoragePickersTests picker.FileTypeFilter().Append(L"*"); VERIFY_ARE_EQUAL(picker.FileTypeFilter().GetAt(0), L"*"); + + auto openPickerChoices = winrt::single_threaded_vector(); + openPickerChoices.Append(L".txt"); + picker.FileTypeChoices().Insert(L"Documents", openPickerChoices); + VERIFY_ARE_EQUAL(picker.FileTypeChoices().Lookup(L"Documents").GetAt(0), L".txt"); + + picker.SuggestedFolder(L"C:\\temp_fileopenpicker_ut_temp"); + VERIFY_ARE_EQUAL(picker.SuggestedFolder(), L"C:\\temp_fileopenpicker_ut_temp"); + + picker.SuggestedStartFolder(L"C:\\temp_fileopenpicker_ut_start"); + VERIFY_ARE_EQUAL(picker.SuggestedStartFolder(), L"C:\\temp_fileopenpicker_ut_start"); } TEST_METHOD(VerifyFileSavePickerOptionsAreReadCorrectly) @@ -174,6 +185,9 @@ namespace Test::StoragePickersTests filters.Append(L"*"); picker.FileTypeChoices().Insert(L"All Files", filters); VERIFY_ARE_EQUAL(picker.FileTypeChoices().Lookup(L"All Files").GetAt(0), L"*"); + + picker.SuggestedStartFolder(L"C:\\temp_filesavepicker_start"); + VERIFY_ARE_EQUAL(picker.SuggestedStartFolder(), L"C:\\temp_filesavepicker_start"); } TEST_METHOD(VerifyFolderPickerOptionsAreReadCorrectly) @@ -193,6 +207,12 @@ namespace Test::StoragePickersTests picker.CommitButtonText(L"commit"); VERIFY_ARE_EQUAL(picker.CommitButtonText(), L"commit"); + + picker.SuggestedFolder(L"C:\\temp_folderpicker_ut_temp"); + VERIFY_ARE_EQUAL(picker.SuggestedFolder(), L"C:\\temp_folderpicker_ut_temp"); + + picker.SuggestedStartFolder(L"C:\\temp_folderpicker_ut_start"); + VERIFY_ARE_EQUAL(picker.SuggestedStartFolder(), L"C:\\temp_folderpicker_ut_start"); } };