Commit cc859bf0 authored by Esmael El-Moslimany's avatar Esmael El-Moslimany Committed by Commit Bot

Extensions WebUI: add ui::SelectFileDialog::SELECT_EXISTING_FOLDER

Use SELECT_EXISTING_FOLDER when choosing an unpacked extension. Disable
folder creation for SELECT_EXISTING_FOLDER and SELECT_UPLOAD_FOLDER (for
all desktop platforms excluding kde). For GTK when selecting a folder,
show only folders.

Bug: 772180
Change-Id: I0f513180ff7f10b5af91e8c518b3d9fd4b0fc8f1
Reviewed-on: https://chromium-review.googlesource.com/1019732
Commit-Queue: Esmael El-Moslimany <aee@chromium.org>
Reviewed-by: default avatarThomas Anderson <thomasanderson@chromium.org>
Reviewed-by: default avatarNico Weber <thakis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#561344}
parent dc0d744a
......@@ -17,6 +17,7 @@ assert(is_linux, "This file should only be referenced on Linux")
group("gtk") {
visibility = [
"//chrome/test:interactive_ui_tests",
"//chrome/test:unit_tests",
"//examples:peerconnection_client",
"//gpu/gles2_conform_support:gles2_conform_test_windowless",
"//remoting/host",
......
......@@ -295,6 +295,11 @@ dbg_list="\
zlib1g-dbg
"
if package_exists libpixman-1-0-dbgsym; then
dbg_list="${dbg_list} libpixman-1-0-dbgsym"
elif package_exists libpixman-1-0-dbg; then
dbg_list="${dbg_list} libpixman-1-0-dbg"
fi
if package_exists libstdc++6-6-dbg; then
dbg_list="${dbg_list} libstdc++6-6-dbg"
elif package_exists libstdc++6-4.9-dbg; then
......
......@@ -1064,7 +1064,7 @@ ExtensionFunction::ResponseAction DeveloperPrivateLoadUnpackedFunction::Run() {
return RespondLater();
}
if (!ShowPicker(ui::SelectFileDialog::SELECT_FOLDER,
if (!ShowPicker(ui::SelectFileDialog::SELECT_EXISTING_FOLDER,
l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY),
ui::SelectFileDialog::FileTypeInfo(),
0 /* file_type_index */)) {
......
......@@ -135,6 +135,7 @@ void SelectFileDialogImplGTK::SelectFileImpl(
switch (type) {
case SELECT_FOLDER:
case SELECT_UPLOAD_FOLDER:
case SELECT_EXISTING_FOLDER:
dialog = CreateSelectFolderDialog(type, title_string, default_path,
owning_window);
break;
......@@ -257,7 +258,7 @@ void SelectFileDialogImplGTK::FileSelected(GtkWidget* dialog,
if (type_ == SELECT_SAVEAS_FILE) {
*last_saved_path_ = path.DirName();
} else if (type_ == SELECT_OPEN_FILE || type_ == SELECT_FOLDER ||
type_ == SELECT_UPLOAD_FOLDER) {
type_ == SELECT_UPLOAD_FOLDER || type_ == SELECT_EXISTING_FOLDER) {
*last_opened_path_ = path.DirName();
} else {
NOTREACHED();
......@@ -345,15 +346,24 @@ GtkWidget* SelectFileDialogImplGTK::CreateSelectFolderDialog(
GTK_RESPONSE_ACCEPT, nullptr);
G_GNUC_END_IGNORE_DEPRECATIONS;
SetGtkTransientForAura(dialog, parent);
GtkFileChooser* chooser = GTK_FILE_CHOOSER(dialog);
if (type == SELECT_UPLOAD_FOLDER || type == SELECT_EXISTING_FOLDER)
gtk_file_chooser_set_create_folders(chooser, FALSE);
if (!default_path.empty()) {
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
default_path.value().c_str());
gtk_file_chooser_set_filename(chooser, default_path.value().c_str());
} else if (!last_opened_path_->empty()) {
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
gtk_file_chooser_set_current_folder(chooser,
last_opened_path_->value().c_str());
}
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
GtkFileFilter* only_folders = gtk_file_filter_new();
gtk_file_filter_set_name(
only_folders,
l10n_util::GetStringUTF8(IDS_SELECT_FOLDER_DIALOG_TITLE).c_str());
gtk_file_filter_add_mime_type(only_folders, "application/x-directory");
gtk_file_filter_add_mime_type(only_folders, "inode/directory");
gtk_file_filter_add_mime_type(only_folders, "text/directory");
gtk_file_chooser_add_filter(chooser, only_folders);
gtk_file_chooser_set_select_multiple(chooser, FALSE);
g_signal_connect(dialog, "response",
G_CALLBACK(OnSelectSingleFolderDialogResponseThunk), this);
return dialog;
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/libgtkui/select_file_dialog_impl_gtk.h"
#include "base/run_loop.h"
#include "base/task_scheduler/task_scheduler.h"
#include "chrome/browser/ui/chrome_select_file_policy.h"
#include "chrome/browser/ui/libgtkui/gtk_ui.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::RunLoop;
using content::BrowserThread;
class SelectFileDialogImplGtkTest : public testing::Test {
public:
SelectFileDialogImplGtkTest() = default;
void SetUp() override {
gtk_ui_.reset(BuildGtkUi());
ui::ShellDialogLinux::SetInstance(gtk_ui_.get());
}
void TearDown() override {
ui::ShellDialogLinux::SetInstance(nullptr);
gtk_ui_.reset();
}
private:
std::unique_ptr<views::LinuxUI> gtk_ui_;
};
namespace libgtkui {
class FilePicker : public ui::SelectFileDialog::Listener {
public:
explicit FilePicker(ui::SelectFileDialog::Type type) {
select_file_dialog_ = ui::SelectFileDialog::Create(
this, std::make_unique<ChromeSelectFilePolicy>(nullptr));
ui::SelectFileDialog::FileTypeInfo file_types;
file_types.allowed_paths = ui::SelectFileDialog::FileTypeInfo::ANY_PATH;
const base::FilePath file_path;
select_file_dialog_->SelectFile(
type, base::string16(), file_path, &file_types, 0,
base::FilePath::StringType(), nullptr, nullptr);
}
~FilePicker() override {
SelectFileDialogImplGTK* file_dialog =
static_cast<SelectFileDialogImplGTK*>(select_file_dialog_.get());
while (!file_dialog->dialogs_.empty())
gtk_widget_destroy(*(file_dialog->dialogs_.begin()));
select_file_dialog_->ListenerDestroyed();
}
bool canCreateFolder() {
return gtk_file_chooser_get_create_folders(getChooser());
}
bool canSelectMultiple() {
return gtk_file_chooser_get_select_multiple(getChooser());
}
const gchar* getTitle() {
return gtk_window_get_title(
GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(getChooser()))));
}
// SelectFileDialog::Listener implementation.
void FileSelected(const base::FilePath& path,
int index,
void* params) override {}
private:
// Dialog box used for opening and saving files.
scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
GtkFileChooser* getChooser() {
auto* dialog =
static_cast<SelectFileDialogImplGTK*>(select_file_dialog_.get());
return GTK_FILE_CHOOSER(*(dialog->dialogs_.begin()));
}
DISALLOW_COPY_AND_ASSIGN(FilePicker);
};
// Glib runs glib_init() when it is loaded by dl, and in the process
// allocates some memory that is intentionally never freed.
// Targeted suppression of the memory leak was not possible.
#if defined(ADDRESS_SANITIZER)
#define MAYBE_SelectExistingFolder DISABLED_SelectExistingFolder
#define MAYBE_SelectUploadFolder DISABLED_SelectUploadFolder
#define MAYBE_SelectFolder DISABLED_SelectFolder
#else
#define MAYBE_SelectExistingFolder SelectExistingFolder
#define MAYBE_SelectUploadFolder SelectUploadFolder
#define MAYBE_SelectFolder SelectFolder
#endif
TEST_F(SelectFileDialogImplGtkTest, MAYBE_SelectExistingFolder) {
content::TestBrowserThreadBundle test_browser_thread_bundle_;
ScopedTestingLocalState local_state(TestingBrowserProcess::GetGlobal());
FilePicker file_picker(ui::SelectFileDialog::SELECT_EXISTING_FOLDER);
EXPECT_FALSE(file_picker.canSelectMultiple());
EXPECT_FALSE(file_picker.canCreateFolder());
EXPECT_STREQ("Select Folder", file_picker.getTitle());
base::TaskScheduler::GetInstance()->FlushForTesting();
RunLoop().RunUntilIdle();
}
TEST_F(SelectFileDialogImplGtkTest, MAYBE_SelectUploadFolder) {
content::TestBrowserThreadBundle test_browser_thread_bundle_;
ScopedTestingLocalState local_state(TestingBrowserProcess::GetGlobal());
FilePicker file_picker(ui::SelectFileDialog::SELECT_UPLOAD_FOLDER);
EXPECT_FALSE(file_picker.canSelectMultiple());
EXPECT_FALSE(file_picker.canCreateFolder());
EXPECT_STREQ("Select Folder to Upload", file_picker.getTitle());
base::TaskScheduler::GetInstance()->FlushForTesting();
RunLoop().RunUntilIdle();
}
TEST_F(SelectFileDialogImplGtkTest, MAYBE_SelectFolder) {
content::TestBrowserThreadBundle test_browser_thread_bundle_;
ScopedTestingLocalState local_state(TestingBrowserProcess::GetGlobal());
FilePicker file_picker(ui::SelectFileDialog::SELECT_FOLDER);
EXPECT_FALSE(file_picker.canSelectMultiple());
EXPECT_TRUE(file_picker.canCreateFolder());
EXPECT_STREQ("Select Folder", file_picker.getTitle());
base::TaskScheduler::GetInstance()->FlushForTesting();
RunLoop().RunUntilIdle();
}
} // namespace libgtkui
......@@ -261,6 +261,7 @@ void SelectFileDialogImplKDE::SelectFileImpl(
switch (type) {
case SELECT_FOLDER:
case SELECT_UPLOAD_FOLDER:
case SELECT_EXISTING_FOLDER:
CreateSelectFolderDialog(type, title_string, default_path,
window_xid, params);
return;
......@@ -372,7 +373,8 @@ void SelectFileDialogImplKDE::FileSelected(const base::FilePath& path,
*last_saved_path_ = path.DirName();
else if (type_ == SELECT_OPEN_FILE)
*last_opened_path_ = path.DirName();
else if (type_ == SELECT_FOLDER || type_ == SELECT_UPLOAD_FOLDER)
else if (type_ == SELECT_FOLDER || type_ == SELECT_UPLOAD_FOLDER ||
type_ == SELECT_EXISTING_FOLDER)
*last_opened_path_ = path;
else
NOTREACHED();
......
......@@ -3691,7 +3691,9 @@ test("unit_tests") {
"../browser/password_manager/native_backend_kwallet_x_unittest.cc",
"../browser/shell_integration_linux_unittest.cc",
"../browser/ui/input_method/input_method_engine_unittest.cc",
"../browser/ui/libgtkui/select_file_dialog_impl_gtk_unittest.cc",
]
deps += [ "//build/config/linux/gtk" ]
}
if (is_android || is_chromeos) {
......
......@@ -39,6 +39,9 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog
// specifically for "upload".
SELECT_UPLOAD_FOLDER,
// Like SELECT_FOLDER, but folder creation is disabled, if possible.
SELECT_EXISTING_FOLDER,
// For saving into a file, allowing a nonexistent file to be selected.
SELECT_SAVEAS_FILE,
......
......@@ -143,11 +143,9 @@ void SelectFileDialogImpl::SelectFileImpl(
const base::FilePath::StringType& default_extension,
gfx::NativeWindow owning_window,
void* params) {
DCHECK(type == SELECT_FOLDER ||
type == SELECT_UPLOAD_FOLDER ||
type == SELECT_OPEN_FILE ||
type == SELECT_OPEN_MULTI_FILE ||
type == SELECT_SAVEAS_FILE);
DCHECK(type == SELECT_FOLDER || type == SELECT_UPLOAD_FOLDER ||
type == SELECT_EXISTING_FOLDER || type == SELECT_OPEN_FILE ||
type == SELECT_OPEN_MULTI_FILE || type == SELECT_SAVEAS_FILE);
parents_.insert(owning_window);
// Note: we need to retain the dialog as owning_window can be null.
......@@ -177,7 +175,8 @@ void SelectFileDialogImpl::SelectFileImpl(
}
base::scoped_nsobject<ExtensionDropdownHandler> handler;
if (type != SELECT_FOLDER && type != SELECT_UPLOAD_FOLDER) {
if (type != SELECT_FOLDER && type != SELECT_UPLOAD_FOLDER &&
type != SELECT_EXISTING_FOLDER) {
if (file_types) {
handler = SelectFileDialogImpl::SetAccessoryView(
dialog, file_types, file_type_index, default_extension);
......@@ -217,10 +216,16 @@ void SelectFileDialogImpl::SelectFileImpl(
else
[open_dialog setAllowsMultipleSelection:NO];
if (type == SELECT_FOLDER || type == SELECT_UPLOAD_FOLDER) {
if (type == SELECT_FOLDER || type == SELECT_UPLOAD_FOLDER ||
type == SELECT_EXISTING_FOLDER) {
[open_dialog setCanChooseFiles:NO];
[open_dialog setCanChooseDirectories:YES];
[open_dialog setCanCreateDirectories:YES];
if (type == SELECT_FOLDER)
[open_dialog setCanCreateDirectories:YES];
else
[open_dialog setCanCreateDirectories:NO];
NSString *prompt = (type == SELECT_UPLOAD_FOLDER)
? l10n_util::GetNSString(IDS_SELECT_UPLOAD_FOLDER_BUTTON_TITLE)
: l10n_util::GetNSString(IDS_SELECT_FOLDER_BUTTON_TITLE);
......
......@@ -370,8 +370,8 @@ TEST_F(SelectFileDialogMacTest, SelectionType) {
std::string prompt;
} test_cases[] = {
{SelectFileDialog::SELECT_FOLDER, PICK_DIRS | CREATE_DIRS, "Select"},
{SelectFileDialog::SELECT_UPLOAD_FOLDER, PICK_DIRS | CREATE_DIRS,
"Upload"},
{SelectFileDialog::SELECT_UPLOAD_FOLDER, PICK_DIRS, "Upload"},
{SelectFileDialog::SELECT_EXISTING_FOLDER, PICK_DIRS, "Select"},
{SelectFileDialog::SELECT_SAVEAS_FILE, HAS_ACCESSORY_VIEW | CREATE_DIRS,
"Save"},
{SelectFileDialog::SELECT_OPEN_FILE, HAS_ACCESSORY_VIEW | PICK_FILES,
......
......@@ -373,7 +373,8 @@ void SelectFileDialogImpl::ExecuteSelectFile(
base::FilePath path = params.default_path;
bool success = false;
unsigned filter_index = params.file_type_index;
if (params.type == SELECT_FOLDER || params.type == SELECT_UPLOAD_FOLDER) {
if (params.type == SELECT_FOLDER || params.type == SELECT_UPLOAD_FOLDER ||
params.type == SELECT_EXISTING_FOLDER) {
success = RunSelectFolderDialog(params, &path);
} else if (params.type == SELECT_SAVEAS_FILE) {
std::wstring path_as_wstring = path.value();
......@@ -561,8 +562,10 @@ bool SelectFileDialogImpl::RunSelectFolderDialog(
dialog_options.default_path = path->value().c_str();
if (params.type == SELECT_UPLOAD_FOLDER) {
dialog_options.is_upload = true;
browse_info.ulFlags |= BIF_NONEWFOLDERBUTTON;
}
if (params.type == SELECT_UPLOAD_FOLDER ||
params.type == SELECT_EXISTING_FOLDER)
browse_info.ulFlags |= BIF_NONEWFOLDERBUTTON;
if (dialog_options.is_upload || dialog_options.default_path) {
browse_info.lParam = reinterpret_cast<LPARAM>(&dialog_options);
browse_info.lpfn = &BrowseCallbackProc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment