-
Notifications
You must be signed in to change notification settings - Fork 348
Supplements Missing Functionalities for FileOpenPicker.FileTypeFilter and FileSavePicker.FilterTypeChoices #5358
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -118,9 +118,17 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation | |
|
||
if (!PickerCommon::IsHStringNullOrEmpty(defaultFileExtension)) | ||
{ | ||
check_hresult(dialog->SetDefaultExtension(defaultFileExtension.c_str())); | ||
// the default extension has a ".", like ".txt". remove the "." (a.k.a "txt") then set it to the dialog | ||
// otherwise, the diaplayed file name would have two "." | ||
check_hresult(dialog->SetDefaultExtension(defaultFileExtension.c_str() + 1)); | ||
} | ||
else | ||
{ | ||
check_hresult(dialog->SetDefaultExtension(L"")); | ||
} | ||
|
||
check_hresult(dialog->SetOptions(FOS_STRICTFILETYPES)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The UWP pickers didn't use FOS_STRICTFILETYPES, did they? I'm concerned that forcing strict on all apps may be undesirable. (For example, maybe the app likes ".jpg" but the user prefers ".jpeg" and wants to force that even if the app doesn't list that extension.) |
||
|
||
if (!PickerCommon::IsHStringNullOrEmpty(suggestedFileName)) | ||
{ | ||
check_hresult(dialog->SetFileName(suggestedFileName.c_str())); | ||
|
@@ -154,20 +162,6 @@ namespace winrt::Microsoft::Windows::Storage::Pickers::implementation | |
check_hresult(shellItem->GetDisplayName(SIGDN_NORMALDISPLAY, fileName.put())); | ||
std::wstring fileNameStr(fileName.get()); | ||
|
||
// Check if the file name has an extension | ||
if ((fileNameStr.find_last_of(L".") == std::wstring::npos) && (fileTypeChoices.Size() > 0)) | ||
{ | ||
// If the user defined file name doesn't have an extension, | ||
// automatically use the first extension from the first category in fileTypeChoices. | ||
auto firstCategory = fileTypeChoices.First().Current(); | ||
auto value = firstCategory.Value(); | ||
if (value.Size() > 0) | ||
{ | ||
auto firstExtension = value.GetAt(0); | ||
pathStr = pathStr + firstExtension; | ||
} | ||
} | ||
|
||
// Create a file. If the file already exists, | ||
// since common item dialog prompts to let user select cancel or override, thus we can safely truncate here. | ||
// Due to our design spec to align with UWP pickers, we need ensure existance of picked file. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -143,7 +143,7 @@ namespace PickerCommon { | |
} | ||
|
||
/// <summary> | ||
/// Capture and processing pickers filter inputs and convert them into Common Item Dialog's accepting type | ||
/// Capture and processing pickers filter inputs and convert them into Common Item Dialog's accepting type, for FileOpenPicker | ||
/// </summary> | ||
/// <param name="buffer">temp buffer to hold dynamically transformed strings</param> | ||
/// <param name="filters">winrt style filters</param> | ||
|
@@ -152,29 +152,54 @@ namespace PickerCommon { | |
/// </returns> | ||
std::vector<COMDLG_FILTERSPEC> CaptureFilterSpec(std::vector<winrt::hstring>& buffer, winrt::Windows::Foundation::Collections::IVectorView<winrt::hstring> filters) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
SUGGESTION: |
||
{ | ||
std::vector<COMDLG_FILTERSPEC> result(filters.Size()); | ||
int resultSize = filters.Size() + 1; | ||
buffer.clear(); | ||
buffer.reserve(filters.Size() * (size_t)2); | ||
buffer.reserve(resultSize * (size_t)2); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why the SUGGESTION:
If the compiler gives you warning about mixing unsigned values from .Size() and signed values from the constants you can make the constants unsigned e.g. |
||
|
||
std::wstring allFilesExtensionList; | ||
for (const auto& filter : filters) | ||
{ | ||
auto ext = FormatExtensionWithWildcard(filter); | ||
buffer.push_back(filter); | ||
buffer.push_back(ext); | ||
allFilesExtensionList += ext + L";"; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You worry about growing
SUGGESTION:
String+String creating a temporary's not perfectly efficient but not the worst thing in the world. Doing it in a loop gets more interesting as it magnifies the impact. And since you're already being somewhat meticulous elsewhere to efficiently minimize memory allocation (and deallocation) and copying data it seems worthy to do here too. |
||
for (size_t i = 0; i < filters.Size(); i++) | ||
|
||
if (!allFilesExtensionList.empty()) | ||
{ | ||
result.at(i) = { buffer.at(i * 2).c_str(), buffer.at(i * 2 + 1).c_str() }; | ||
allFilesExtensionList.pop_back(); // Remove the last semicolon | ||
} | ||
|
||
if (result.size() == 0) | ||
if (filters.Size() == 0) | ||
{ | ||
result.push_back({ L"All Files", L"*.*" }); | ||
// when filters not defined, set filter to All Files *.* | ||
buffer.push_back(L"All Files"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
buffer.push_back(L"*.*"); | ||
} | ||
else if (filters.Size() == 1 && allFilesExtensionList == L"*") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the app chose "" as the extension, it seems wrong for us to override that the be ".*" with the "All Files" name we chose. |
||
{ | ||
// when there're only one filter "*", set filter to All Files *.* (override the values pushed above) | ||
buffer[0] = L"All Files"; | ||
buffer[1] = L"*.*"; | ||
resultSize = 1; | ||
} | ||
else | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this new automatic "All Files" behavior something the UWP pickers do? Conceptually, the automatic behavior is nice, but I worry we might be forcing something on apps which don't want it or might have issues in some cases. Two potential problems I'm thinking of:
My feeling is that to handling (1) we might need an explicit API for the app to say if it wants an automatic "All Files", perhaps with an optional string if they want a different string used. Handling (2) likely requires extra de-duplicate code. |
||
buffer.push_back(L"All Files"); | ||
buffer.push_back(allFilesExtensionList.c_str()); | ||
} | ||
|
||
std::vector<COMDLG_FILTERSPEC> result(resultSize); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIT: ES.23: Prefer the {}-initializer syntax Same comment applies throughout |
||
for (size_t i = 0; i < resultSize; i++) | ||
{ | ||
result.at(i) = { buffer.at(i * 2).c_str(), buffer.at(i * 2 + 1).c_str() }; | ||
} | ||
|
||
return result; | ||
} | ||
|
||
/// <summary> | ||
/// Capture and processing pickers filter inputs and convert them into Common Item Dialog's accepting type | ||
/// Capture and processing pickers filter inputs and convert them into Common Item Dialog's accepting type, for FileSavePicker | ||
/// </summary> | ||
/// <param name="buffer">temp buffer to hold dynamically transformed strings</param> | ||
/// <param name="filters">winrt style filters</param> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a behavior difference between calling
dialog->SetDefaultExtension(L"")
and not calling SetDefaultExtension?