Bug 1833450 - [3/4] Windows nsFilePicker: convert to use IPC-able Command structs r=gstoll,handyman

Convert `nsFilePicker` to use the `Command` structs introduced in the
first commit in this patchset. No functional changes -- this should be a
straight reorganization of internal code.

Additionally, remove from `WinUtils` the now-unused function
`GetShellItemPath`, whose functionality has been moved into `Command`'s
associated functions' translation unit. (This function was added to
WinUtils in 2012 as part of supporting the Windows Vista file picker
(bug 718374). It's not overtly filepicker-specific, but in the past
eleven years, no other code has ever used it.)

Differential Revision: https://phabricator.services.mozilla.com/D178204
This commit is contained in:
Ray Kraesig 2023-05-18 22:29:53 +00:00
Родитель 7e4941fcde
Коммит d65140658c
3 изменённых файлов: 86 добавлений и 166 удалений

Просмотреть файл

@ -1225,16 +1225,6 @@ int32_t FaviconHelper::GetICOCacheSecondsTimeout() {
return icoReCacheSecondsTimeout;
}
/* static */
bool WinUtils::GetShellItemPath(IShellItem* aItem, nsString& aResultString) {
NS_ENSURE_TRUE(aItem, false);
LPWSTR str = nullptr;
if (FAILED(aItem->GetDisplayName(SIGDN_FILESYSPATH, &str))) return false;
aResultString.Assign(str);
CoTaskMemFree(str);
return !aResultString.IsEmpty();
}
/* static */
LayoutDeviceIntRegion WinUtils::ConvertHRGNToRegion(HRGN aRgn) {
NS_ASSERTION(aRgn, "Don't pass NULL region here");

Просмотреть файл

@ -466,16 +466,6 @@ class WinUtils {
static bool GetIsMouseFromTouch(EventMessage aEventType);
/**
* GetShellItemPath return the file or directory path of a shell item.
* Internally calls IShellItem's GetDisplayName.
*
* aItem the shell item containing the path.
* aResultString the resulting string path.
* returns true if a path was retreived.
*/
static bool GetShellItemPath(IShellItem* aItem, nsString& aResultString);
/**
* ConvertHRGNToRegion converts a Windows HRGN to an LayoutDeviceIntRegion.
*

Просмотреть файл

@ -25,6 +25,8 @@
#include "WinUtils.h"
#include "nsPIDOMWindow.h"
#include "mozilla/widget/filedialog/WinFileDialogCommands.h"
using mozilla::UniquePtr;
using namespace mozilla::widget;
@ -95,67 +97,40 @@ bool nsFilePicker::ShowFolderPicker(const nsString& aInitialDir) {
return false;
}
// options
FILEOPENDIALOGOPTIONS fos = FOS_PICKFOLDERS;
HRESULT hr = dialog->SetOptions(fos);
if (FAILED(hr)) {
return false;
}
// initial strings
hr = dialog->SetTitle(mTitle.get());
if (FAILED(hr)) {
return false;
}
namespace fd = ::mozilla::widget::filedialog;
nsTArray<fd::Command> commands = {
fd::SetOptions(FOS_PICKFOLDERS),
fd::SetTitle(mTitle),
};
if (!mOkButtonLabel.IsEmpty()) {
hr = dialog->SetOkButtonLabel(mOkButtonLabel.get());
if (FAILED(hr)) {
commands.AppendElement(fd::SetOkButtonLabel(mOkButtonLabel));
}
if (!aInitialDir.IsEmpty()) {
commands.AppendElement(fd::SetFolder(aInitialDir));
}
{
if (NS_FAILED(fd::ApplyCommands(dialog, commands))) {
return false;
}
ScopedRtlShimWindow shim(mParentWidget.get());
mozilla::BackgroundHangMonitor().NotifyWait();
if (FAILED(dialog->Show(shim.get()))) {
return false;
}
}
if (!aInitialDir.IsEmpty()) {
RefPtr<IShellItem> folder;
if (SUCCEEDED(SHCreateItemFromParsingName(aInitialDir.get(), nullptr,
IID_IShellItem,
getter_AddRefs(folder)))) {
hr = dialog->SetFolder(folder);
if (FAILED(hr)) {
return false;
}
}
}
ScopedRtlShimWindow shim(mParentWidget.get());
// display
mozilla::BackgroundHangMonitor().NotifyWait();
RefPtr<IShellItem> item;
if (FAILED(dialog->Show(shim.get())) ||
FAILED(dialog->GetResult(getter_AddRefs(item))) || !item) {
auto result = fd::GetFolderResults(dialog.get());
if (result.isErr()) {
return false;
}
// results
// If the user chose a Win7 Library, resolve to the library's
// default save folder.
RefPtr<IShellItem> folderPath;
RefPtr<IShellLibrary> shellLib;
if (FAILED(CoCreateInstance(CLSID_ShellLibrary, nullptr, CLSCTX_INPROC_SERVER,
IID_IShellLibrary, getter_AddRefs(shellLib)))) {
return false;
}
if (shellLib && SUCCEEDED(shellLib->LoadLibraryFromItem(item, STGM_READ)) &&
SUCCEEDED(shellLib->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem,
getter_AddRefs(folderPath)))) {
item.swap(folderPath);
}
// get the folder's file system path
return WinUtils::GetShellItemPath(item, mUnicodeFile);
mUnicodeFile = result.unwrap();
return true;
}
/*
@ -187,50 +162,47 @@ bool nsFilePicker::ShowFilePicker(const nsString& aInitialDir) {
}
}
namespace fd = ::mozilla::widget::filedialog;
nsTArray<fd::Command> commands;
// options
{
FILEOPENDIALOGOPTIONS fos = 0;
fos |= FOS_SHAREAWARE | FOS_OVERWRITEPROMPT | FOS_FORCEFILESYSTEM;
FILEOPENDIALOGOPTIONS fos = 0;
fos |= FOS_SHAREAWARE | FOS_OVERWRITEPROMPT | FOS_FORCEFILESYSTEM;
// Handle add to recent docs settings
if (IsPrivacyModeEnabled() || !mAddToRecentDocs) {
fos |= FOS_DONTADDTORECENT;
}
// Handle add to recent docs settings
if (IsPrivacyModeEnabled() || !mAddToRecentDocs) {
fos |= FOS_DONTADDTORECENT;
}
// mode specific
switch (mMode) {
case modeOpen:
fos |= FOS_FILEMUSTEXIST;
break;
// mode specific
switch (mMode) {
case modeOpen:
fos |= FOS_FILEMUSTEXIST;
break;
case modeOpenMultiple:
fos |= FOS_FILEMUSTEXIST | FOS_ALLOWMULTISELECT;
break;
case modeOpenMultiple:
fos |= FOS_FILEMUSTEXIST | FOS_ALLOWMULTISELECT;
break;
case modeSave:
fos |= FOS_NOREADONLYRETURN;
// Don't follow shortcuts when saving a shortcut, this can be used
// to trick users (bug 271732)
if (IsDefaultPathLink()) fos |= FOS_NODEREFERENCELINKS;
break;
case modeSave:
fos |= FOS_NOREADONLYRETURN;
// Don't follow shortcuts when saving a shortcut, this can be used
// to trick users (bug 271732)
if (IsDefaultPathLink()) fos |= FOS_NODEREFERENCELINKS;
break;
case modeGetFolder:
MOZ_ASSERT(false, "file-picker opened in directory-picker mode");
return false;
}
case modeGetFolder:
MOZ_ASSERT(false, "file-picker opened in directory-picker mode");
return false;
}
HRESULT hr = dialog->SetOptions(fos);
if (FAILED(hr)) {
return false;
commands.AppendElement(fd::SetOptions(fos));
}
// initial strings
// title
hr = dialog->SetTitle(mTitle.get());
if (FAILED(hr)) {
return false;
}
commands.AppendElement(fd::SetTitle(mTitle));
// default filename
if (!mDefaultFilename.IsEmpty()) {
@ -239,10 +211,7 @@ bool nsFilePicker::ShowFilePicker(const nsString& aInitialDir) {
nsAutoString sanitizedFilename(mDefaultFilename);
sanitizedFilename.ReplaceChar('%', '_');
hr = dialog->SetFileName(sanitizedFilename.get());
if (FAILED(hr)) {
return false;
}
commands.AppendElement(fd::SetFileName(sanitizedFilename));
}
// default extension to append to new files
@ -251,49 +220,32 @@ bool nsFilePicker::ShowFilePicker(const nsString& aInitialDir) {
nsAutoString sanitizedExtension(mDefaultExtension);
sanitizedExtension.ReplaceChar('%', '_');
hr = dialog->SetDefaultExtension(sanitizedExtension.get());
if (FAILED(hr)) {
return false;
}
commands.AppendElement(fd::SetDefaultExtension(sanitizedExtension));
} else if (IsDefaultPathHtml()) {
hr = dialog->SetDefaultExtension(L"html");
if (FAILED(hr)) {
return false;
}
commands.AppendElement(fd::SetDefaultExtension(u"html"_ns));
}
// initial location
if (!aInitialDir.IsEmpty()) {
RefPtr<IShellItem> folder;
if (SUCCEEDED(SHCreateItemFromParsingName(aInitialDir.get(), nullptr,
IID_IShellItem,
getter_AddRefs(folder)))) {
hr = dialog->SetFolder(folder);
if (FAILED(hr)) {
return false;
}
}
commands.AppendElement(fd::SetFolder(aInitialDir));
}
// filter types and the default index
if (!mFilterList.IsEmpty()) {
std::vector<COMDLG_FILTERSPEC> filterSpecs;
nsTArray<fd::ComDlgFilterSpec> fileTypes;
for (auto const& filter : mFilterList) {
filterSpecs.push_back({filter.title.get(), filter.filter.get()});
}
hr = dialog->SetFileTypes(filterSpecs.size(), filterSpecs.data());
if (FAILED(hr)) {
return false;
}
hr = dialog->SetFileTypeIndex(mSelectedType);
if (FAILED(hr)) {
return false;
fileTypes.EmplaceBack(filter.title, filter.filter);
}
commands.AppendElement(fd::SetFileTypes(std::move(fileTypes)));
commands.AppendElement(fd::SetFileTypeIndex(mSelectedType));
}
// display
{
if (NS_FAILED(fd::ApplyCommands(dialog, commands))) {
return false;
}
ScopedRtlShimWindow shim(mParentWidget.get());
AutoWidgetPickerState awps(mParentWidget);
@ -304,44 +256,32 @@ bool nsFilePicker::ShowFilePicker(const nsString& aInitialDir) {
}
// results
auto result_ = fd::GetFileResults(dialog.get());
if (result_.isErr()) {
return false;
}
auto result = result_.unwrap();
// Remember what filter type the user selected
UINT filterIdxResult;
if (SUCCEEDED(dialog->GetFileTypeIndex(&filterIdxResult))) {
mSelectedType = (int16_t)filterIdxResult;
}
mSelectedType = result.selectedFileTypeIndex();
auto const& paths = result.paths();
// single selection
if (mMode != modeOpenMultiple) {
RefPtr<IShellItem> item;
if (FAILED(dialog->GetResult(getter_AddRefs(item))) || !item) return false;
return WinUtils::GetShellItemPath(item, mUnicodeFile);
if (!paths.IsEmpty()) {
MOZ_ASSERT(paths.Length() == 1);
mUnicodeFile = paths[0];
return true;
}
return false;
}
// multiple selection
RefPtr<IFileOpenDialog> openDlg;
dialog->QueryInterface(IID_IFileOpenDialog, getter_AddRefs(openDlg));
if (!openDlg) {
// should not happen
return false;
}
RefPtr<IShellItemArray> items;
if (FAILED(openDlg->GetResults(getter_AddRefs(items))) || !items) {
return false;
}
DWORD count = 0;
items->GetCount(&count);
for (unsigned int idx = 0; idx < count; idx++) {
RefPtr<IShellItem> item;
nsAutoString str;
if (SUCCEEDED(items->GetItemAt(idx, getter_AddRefs(item)))) {
if (!WinUtils::GetShellItemPath(item, str)) continue;
nsCOMPtr<nsIFile> file;
if (NS_SUCCEEDED(NS_NewLocalFile(str, false, getter_AddRefs(file)))) {
mFiles.AppendObject(file);
}
for (auto const& str : paths) {
nsCOMPtr<nsIFile> file;
if (NS_SUCCEEDED(NS_NewLocalFile(str, false, getter_AddRefs(file)))) {
mFiles.AppendObject(file);
}
}
return true;