|
@@ -14,10 +14,25 @@ It also:
|
|
|
This may be partially upstreamed to Chromium in the future.
|
|
|
|
|
|
diff --git a/ui/gtk/select_file_dialog_linux_gtk.cc b/ui/gtk/select_file_dialog_linux_gtk.cc
|
|
|
-index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a846f0d923 100644
|
|
|
+index b83f0177a2adb0a19be49684f865941e6708f626..a8c7032cfc122b97665c41da9e1191e747b95a33 100644
|
|
|
--- a/ui/gtk/select_file_dialog_linux_gtk.cc
|
|
|
+++ b/ui/gtk/select_file_dialog_linux_gtk.cc
|
|
|
-@@ -407,9 +407,11 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper(
|
|
|
+@@ -259,8 +259,12 @@ void SelectFileDialogLinuxGtk::SelectFileImpl(
|
|
|
+ case SELECT_EXISTING_FOLDER:
|
|
|
+ dialog = CreateSelectFolderDialog(type, title_string, default_path,
|
|
|
+ owning_window);
|
|
|
+- connect("response",
|
|
|
+- &SelectFileDialogLinuxGtk::OnSelectSingleFolderDialogResponse);
|
|
|
++ if (allow_multiple_selection())
|
|
|
++ connect("response",
|
|
|
++ &SelectFileDialogLinuxGtk::OnSelectMultiFolderDialogResponse);
|
|
|
++ else
|
|
|
++ connect("response",
|
|
|
++ &SelectFileDialogLinuxGtk::OnSelectSingleFolderDialogResponse);
|
|
|
+ break;
|
|
|
+ case SELECT_OPEN_FILE:
|
|
|
+ dialog = CreateFileOpenDialog(title_string, default_path, owning_window);
|
|
|
+@@ -407,9 +411,11 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper(
|
|
|
const std::string& title,
|
|
|
const base::FilePath& default_path,
|
|
|
gfx::NativeWindow parent) {
|
|
@@ -30,7 +45,7 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
|
|
|
SetGtkTransientForAura(dialog, parent);
|
|
|
AddFilters(GTK_FILE_CHOOSER(dialog));
|
|
|
|
|
|
-@@ -425,6 +427,7 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper(
|
|
|
+@@ -425,6 +431,7 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper(
|
|
|
GtkFileChooserSetCurrentFolder(GTK_FILE_CHOOSER(dialog),
|
|
|
*last_opened_path());
|
|
|
}
|
|
@@ -38,7 +53,7 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
|
|
|
return dialog;
|
|
|
}
|
|
|
|
|
|
-@@ -440,11 +443,15 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
|
|
|
+@@ -440,11 +447,15 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
|
|
|
? l10n_util::GetStringUTF8(IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE)
|
|
|
: l10n_util::GetStringUTF8(IDS_SELECT_FOLDER_DIALOG_TITLE);
|
|
|
}
|
|
@@ -59,7 +74,7 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
|
|
|
|
|
|
GtkWidget* dialog = GtkFileChooserDialogNew(
|
|
|
title_string.c_str(), nullptr, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
|
|
|
-@@ -466,7 +473,8 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
|
|
|
+@@ -466,7 +477,8 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
|
|
|
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);
|
|
@@ -69,7 +84,7 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
|
|
|
return dialog;
|
|
|
}
|
|
|
|
|
|
-@@ -503,10 +511,11 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog(
|
|
|
+@@ -503,10 +515,11 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog(
|
|
|
std::string title_string =
|
|
|
!title.empty() ? title
|
|
|
: l10n_util::GetStringUTF8(IDS_SAVE_AS_DIALOG_TITLE);
|
|
@@ -83,7 +98,7 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
|
|
|
GTK_RESPONSE_ACCEPT);
|
|
|
SetGtkTransientForAura(dialog, parent);
|
|
|
|
|
|
-@@ -532,9 +541,10 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog(
|
|
|
+@@ -532,9 +545,10 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog(
|
|
|
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
|
|
|
// Overwrite confirmation is always enabled in GTK4.
|
|
|
if (!GtkCheckVersion(4)) {
|
|
@@ -96,6 +111,65 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
|
|
|
return dialog;
|
|
|
}
|
|
|
|
|
|
+@@ -589,15 +603,29 @@ void SelectFileDialogLinuxGtk::OnSelectSingleFolderDialogResponse(
|
|
|
+ void SelectFileDialogLinuxGtk::OnSelectMultiFileDialogResponse(
|
|
|
+ GtkWidget* dialog,
|
|
|
+ int response_id) {
|
|
|
++ SelectMultiFileHelper(dialog, response_id, false);
|
|
|
++}
|
|
|
++
|
|
|
++void SelectFileDialogLinuxGtk::OnSelectMultiFolderDialogResponse(
|
|
|
++ GtkWidget* dialog,
|
|
|
++ int response_id) {
|
|
|
++ SelectMultiFileHelper(dialog, response_id, true);
|
|
|
++}
|
|
|
++
|
|
|
++void SelectFileDialogLinuxGtk::SelectMultiFileHelper(GtkWidget* dialog,
|
|
|
++ int response_id,
|
|
|
++ bool allow_folder) {
|
|
|
+ if (IsCancelResponse(response_id)) {
|
|
|
+ FileNotSelected(dialog);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ auto filenames = GtkFileChooserGetFilenames(dialog);
|
|
|
+- std::erase_if(filenames, [this](const base::FilePath& path) {
|
|
|
+- return CallDirectoryExistsOnUIThread(path);
|
|
|
++ std::erase_if(filenames, [this, &allow_folder](const base::FilePath& path) {
|
|
|
++ bool directory_exists = CallDirectoryExistsOnUIThread(path);
|
|
|
++ return !allow_folder && directory_exists;
|
|
|
+ });
|
|
|
++
|
|
|
+ if (filenames.empty()) {
|
|
|
+ FileNotSelected(dialog);
|
|
|
+ return;
|
|
|
+diff --git a/ui/gtk/select_file_dialog_linux_gtk.h b/ui/gtk/select_file_dialog_linux_gtk.h
|
|
|
+index 213eaa5ec6d657a659726cb38103e8bd671fe907..f497447c598198bf690758b1d1c5c6fe4112627f 100644
|
|
|
+--- a/ui/gtk/select_file_dialog_linux_gtk.h
|
|
|
++++ b/ui/gtk/select_file_dialog_linux_gtk.h
|
|
|
+@@ -108,6 +108,12 @@ class SelectFileDialogLinuxGtk : public ui::SelectFileDialogLinux,
|
|
|
+ gint response_id,
|
|
|
+ bool allow_folder);
|
|
|
+
|
|
|
++ // Common function for OnSelectMultiFileDialogResponse and
|
|
|
++ // OnSelectMultiFolderDialogResponse.
|
|
|
++ void SelectMultiFileHelper(GtkWidget* dialog,
|
|
|
++ gint response_id,
|
|
|
++ bool allow_folder);
|
|
|
++
|
|
|
+ // Common function for CreateFileOpenDialog and CreateMultiFileOpenDialog.
|
|
|
+ GtkWidget* CreateFileOpenHelper(const std::string& title,
|
|
|
+ const base::FilePath& default_path,
|
|
|
+@@ -122,6 +128,9 @@ class SelectFileDialogLinuxGtk : public ui::SelectFileDialogLinux,
|
|
|
+ // Callback for when the user responds to a Open Multiple Files dialog.
|
|
|
+ void OnSelectMultiFileDialogResponse(GtkWidget* dialog, int response_id);
|
|
|
+
|
|
|
++ // Callback for when the user responds to a Select Multiple Folders dialog.
|
|
|
++ void OnSelectMultiFolderDialogResponse(GtkWidget* dialog, int response_id);
|
|
|
++
|
|
|
+ // Callback for when the file chooser gets destroyed.
|
|
|
+ void OnFileChooserDestroy(GtkWidget* dialog);
|
|
|
+
|
|
|
diff --git a/ui/shell_dialogs/select_file_dialog.h b/ui/shell_dialogs/select_file_dialog.h
|
|
|
index eb3d997598631b220c3566748f23a5cdac3e4692..b4b2f7294ce6e9349a4a8a05f614e93359eca25a 100644
|
|
|
--- a/ui/shell_dialogs/select_file_dialog.h
|
|
@@ -186,18 +260,90 @@ index 61683d0eddb04c494ca5e650e7d556b44968ec49..5492456a9138b250e97a5479838bb443
|
|
|
|
|
|
} // namespace ui
|
|
|
diff --git a/ui/shell_dialogs/select_file_dialog_linux_kde.cc b/ui/shell_dialogs/select_file_dialog_linux_kde.cc
|
|
|
-index 64a79ebe2e2d21d5a6b4a98042d1cdb7b6edad52..16f2ae01a8d33e6341ed52638e963c340455ebf8 100644
|
|
|
+index 64a79ebe2e2d21d5a6b4a98042d1cdb7b6edad52..748c2506781a237641b25b426876be14c8b7ba82 100644
|
|
|
--- a/ui/shell_dialogs/select_file_dialog_linux_kde.cc
|
|
|
+++ b/ui/shell_dialogs/select_file_dialog_linux_kde.cc
|
|
|
-@@ -468,7 +468,7 @@ void SelectFileDialogLinuxKde::CreateSelectFolderDialog(
|
|
|
+@@ -154,9 +154,20 @@ class SelectFileDialogLinuxKde : public SelectFileDialogLinux {
|
|
|
+ void OnSelectMultiFileDialogResponse(
|
|
|
+ gfx::AcceleratedWidget parent,
|
|
|
+ std::unique_ptr<KDialogOutputParams> results);
|
|
|
++
|
|
|
++ // Common function for OnSelectSingleFolderDialogResponse and
|
|
|
++ // OnSelectMultiFileDialogResponse.
|
|
|
++ void SelectMultiFileDialogHelper(
|
|
|
++ bool allow_folder,
|
|
|
++ gfx::AcceleratedWidget parent,
|
|
|
++ std::unique_ptr<KDialogOutputParams> results);
|
|
|
++
|
|
|
+ void OnSelectSingleFolderDialogResponse(
|
|
|
+ gfx::AcceleratedWidget parent,
|
|
|
+ std::unique_ptr<KDialogOutputParams> results);
|
|
|
++ void OnSelectMultiFolderDialogResponse(
|
|
|
++ gfx::AcceleratedWidget parent,
|
|
|
++ std::unique_ptr<KDialogOutputParams> results);
|
|
|
+
|
|
|
+ // Should be either DESKTOP_ENVIRONMENT_KDE3, KDE4, KDE5, or KDE6.
|
|
|
+ base::nix::DesktopEnvironment desktop_;
|
|
|
+@@ -461,6 +472,7 @@ void SelectFileDialogLinuxKde::CreateSelectFolderDialog(
|
|
|
+ int title_message_id = (type == SELECT_UPLOAD_FOLDER)
|
|
|
+ ? IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE
|
|
|
+ : IDS_SELECT_FOLDER_DIALOG_TITLE;
|
|
|
++ bool multiple_selection = allow_multiple_selection();
|
|
|
+ pipe_task_runner_->PostTaskAndReplyWithResult(
|
|
|
+ FROM_HERE,
|
|
|
+ base::BindOnce(
|
|
|
+@@ -468,10 +480,12 @@ void SelectFileDialogLinuxKde::CreateSelectFolderDialog(
|
|
|
KDialogParams(
|
|
|
"--getexistingdirectory", GetTitle(title, title_message_id),
|
|
|
default_path.empty() ? *last_opened_path() : default_path, parent,
|
|
|
- false, false)),
|
|
|
-+ false, allow_multiple_selection())),
|
|
|
++ false, multiple_selection)),
|
|
|
base::BindOnce(
|
|
|
- &SelectFileDialogLinuxKde::OnSelectSingleFolderDialogResponse, this,
|
|
|
- parent));
|
|
|
+- &SelectFileDialogLinuxKde::OnSelectSingleFolderDialogResponse, this,
|
|
|
+- parent));
|
|
|
++ multiple_selection
|
|
|
++ ? &SelectFileDialogLinuxKde::OnSelectMultiFolderDialogResponse
|
|
|
++ : &SelectFileDialogLinuxKde::OnSelectSingleFolderDialogResponse,
|
|
|
++ this, parent));
|
|
|
+ }
|
|
|
+
|
|
|
+ void SelectFileDialogLinuxKde::CreateFileOpenDialog(
|
|
|
+@@ -561,7 +575,8 @@ void SelectFileDialogLinuxKde::OnSelectSingleFolderDialogResponse(
|
|
|
+ SelectSingleFileHelper(true, std::move(results));
|
|
|
+ }
|
|
|
+
|
|
|
+-void SelectFileDialogLinuxKde::OnSelectMultiFileDialogResponse(
|
|
|
++void SelectFileDialogLinuxKde::SelectMultiFileDialogHelper(
|
|
|
++ bool allow_folder,
|
|
|
+ gfx::AcceleratedWidget parent,
|
|
|
+ std::unique_ptr<KDialogOutputParams> results) {
|
|
|
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
|
+@@ -579,7 +594,7 @@ void SelectFileDialogLinuxKde::OnSelectMultiFileDialogResponse(
|
|
|
+ base::SplitStringPiece(results->output, "\n", base::KEEP_WHITESPACE,
|
|
|
+ base::SPLIT_WANT_NONEMPTY)) {
|
|
|
+ base::FilePath path(line);
|
|
|
+- if (CallDirectoryExistsOnUIThread(path))
|
|
|
++ if (!allow_folder && CallDirectoryExistsOnUIThread(path))
|
|
|
+ continue;
|
|
|
+ filenames_fp.push_back(path);
|
|
|
+ }
|
|
|
+@@ -591,4 +606,16 @@ void SelectFileDialogLinuxKde::OnSelectMultiFileDialogResponse(
|
|
|
+ MultiFilesSelected(filenames_fp);
|
|
|
+ }
|
|
|
+
|
|
|
++void SelectFileDialogLinuxKde::OnSelectMultiFolderDialogResponse(
|
|
|
++ gfx::AcceleratedWidget parent,
|
|
|
++ std::unique_ptr<KDialogOutputParams> results) {
|
|
|
++ SelectMultiFileDialogHelper(true, parent, std::move(results));
|
|
|
++}
|
|
|
++
|
|
|
++void SelectFileDialogLinuxKde::OnSelectMultiFileDialogResponse(
|
|
|
++ gfx::AcceleratedWidget parent,
|
|
|
++ std::unique_ptr<KDialogOutputParams> results) {
|
|
|
++ SelectMultiFileDialogHelper(false, parent, std::move(results));
|
|
|
++}
|
|
|
++
|
|
|
+ } // namespace ui
|
|
|
diff --git a/ui/shell_dialogs/select_file_dialog_linux_portal.cc b/ui/shell_dialogs/select_file_dialog_linux_portal.cc
|
|
|
index 143f5fe1028e154192767599a1e68b45301a894d..132e670dc3ccd9a0f904a8869e516f4556fbf0af 100644
|
|
|
--- a/ui/shell_dialogs/select_file_dialog_linux_portal.cc
|