web_dialog_helper.cc 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. // Copyright (c) 2014 GitHub, Inc. All rights reserved.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "atom/browser/web_dialog_helper.h"
  5. #include <string>
  6. #include <vector>
  7. #include "atom/browser/atom_browser_context.h"
  8. #include "atom/browser/native_window.h"
  9. #include "atom/browser/ui/file_dialog.h"
  10. #include "base/bind.h"
  11. #include "base/files/file_enumerator.h"
  12. #include "base/files/file_path.h"
  13. #include "base/strings/utf_string_conversions.h"
  14. #include "chrome/common/pref_names.h"
  15. #include "components/prefs/pref_service.h"
  16. #include "content/public/browser/render_frame_host.h"
  17. #include "content/public/browser/render_process_host.h"
  18. #include "content/public/browser/render_view_host.h"
  19. #include "content/public/browser/web_contents.h"
  20. #include "content/public/common/file_chooser_file_info.h"
  21. #include "content/public/common/file_chooser_params.h"
  22. #include "net/base/mime_util.h"
  23. #include "ui/shell_dialogs/selected_file_info.h"
  24. namespace {
  25. class FileSelectHelper : public base::RefCounted<FileSelectHelper>,
  26. public content::WebContentsObserver {
  27. public:
  28. FileSelectHelper(content::RenderFrameHost* render_frame_host,
  29. const content::FileChooserParams::Mode& mode)
  30. : render_frame_host_(render_frame_host), mode_(mode) {
  31. auto web_contents = content::WebContents::FromRenderFrameHost(
  32. render_frame_host);
  33. content::WebContentsObserver::Observe(web_contents);
  34. }
  35. void ShowOpenDialog(const file_dialog::DialogSettings& settings) {
  36. auto callback = base::Bind(&FileSelectHelper::OnOpenDialogDone, this);
  37. file_dialog::ShowOpenDialog(settings, callback);
  38. }
  39. void ShowSaveDialog(const file_dialog::DialogSettings& settings) {
  40. auto callback = base::Bind(&FileSelectHelper::OnSaveDialogDone, this);
  41. file_dialog::ShowSaveDialog(settings, callback);
  42. }
  43. private:
  44. friend class base::RefCounted<FileSelectHelper>;
  45. ~FileSelectHelper() override {}
  46. void OnOpenDialogDone(bool result, const std::vector<base::FilePath>& paths) {
  47. std::vector<content::FileChooserFileInfo> file_info;
  48. if (result) {
  49. for (auto& path : paths) {
  50. content::FileChooserFileInfo info;
  51. info.file_path = path;
  52. info.display_name = path.BaseName().value();
  53. file_info.push_back(info);
  54. }
  55. if (render_frame_host_ && !paths.empty()) {
  56. auto browser_context = static_cast<atom::AtomBrowserContext*>(
  57. render_frame_host_->GetProcess()->GetBrowserContext());
  58. browser_context->prefs()->SetFilePath(prefs::kSelectFileLastDirectory,
  59. paths[0].DirName());
  60. }
  61. }
  62. OnFilesSelected(file_info);
  63. }
  64. void OnSaveDialogDone(bool result, const base::FilePath& path) {
  65. std::vector<content::FileChooserFileInfo> file_info;
  66. if (result) {
  67. content::FileChooserFileInfo info;
  68. info.file_path = path;
  69. info.display_name = path.BaseName().value();
  70. file_info.push_back(info);
  71. }
  72. OnFilesSelected(file_info);
  73. }
  74. void OnFilesSelected(
  75. const std::vector<content::FileChooserFileInfo>& file_info) {
  76. if (render_frame_host_)
  77. render_frame_host_->FilesSelectedInChooser(file_info, mode_);
  78. }
  79. // content::WebContentsObserver:
  80. void RenderFrameHostChanged(content::RenderFrameHost* old_host,
  81. content::RenderFrameHost* new_host) override {
  82. if (old_host == render_frame_host_)
  83. render_frame_host_ = nullptr;
  84. }
  85. // content::WebContentsObserver:
  86. void RenderFrameDeleted(content::RenderFrameHost* deleted_host) override {
  87. if (deleted_host == render_frame_host_)
  88. render_frame_host_ = nullptr;
  89. }
  90. // content::WebContentsObserver:
  91. void WebContentsDestroyed() override {
  92. render_frame_host_ = nullptr;
  93. }
  94. content::RenderFrameHost* render_frame_host_;
  95. content::FileChooserParams::Mode mode_;
  96. };
  97. file_dialog::Filters GetFileTypesFromAcceptType(
  98. const std::vector<base::string16>& accept_types) {
  99. file_dialog::Filters filters;
  100. if (accept_types.empty())
  101. return filters;
  102. std::vector<base::FilePath::StringType> extensions;
  103. for (const auto& accept_type : accept_types) {
  104. std::string ascii_type = base::UTF16ToASCII(accept_type);
  105. if (ascii_type[0] == '.') {
  106. // If the type starts with a period it is assumed to be a file extension,
  107. // like `.txt`, // so we just have to add it to the list.
  108. base::FilePath::StringType extension(
  109. ascii_type.begin(), ascii_type.end());
  110. // Skip the first character.
  111. extensions.push_back(extension.substr(1));
  112. } else {
  113. // For MIME Type, `audio/*, vidio/*, image/*
  114. net::GetExtensionsForMimeType(ascii_type, &extensions);
  115. }
  116. }
  117. // If no valid exntesion is added, return empty filters.
  118. if (extensions.empty())
  119. return filters;
  120. filters.push_back(file_dialog::Filter());
  121. for (const auto& extension : extensions) {
  122. #if defined(OS_WIN)
  123. filters[0].second.push_back(base::UTF16ToASCII(extension));
  124. #else
  125. filters[0].second.push_back(extension);
  126. #endif
  127. }
  128. return filters;
  129. }
  130. } // namespace
  131. namespace atom {
  132. WebDialogHelper::WebDialogHelper(NativeWindow* window)
  133. : window_(window),
  134. weak_factory_(this) {
  135. }
  136. WebDialogHelper::~WebDialogHelper() {
  137. }
  138. void WebDialogHelper::RunFileChooser(
  139. content::RenderFrameHost* render_frame_host,
  140. const content::FileChooserParams& params) {
  141. std::vector<content::FileChooserFileInfo> result;
  142. file_dialog::DialogSettings settings;
  143. settings.filters = GetFileTypesFromAcceptType(params.accept_types);
  144. settings.parent_window = window_;
  145. settings.title = base::UTF16ToUTF8(params.title);
  146. scoped_refptr<FileSelectHelper> file_select_helper(
  147. new FileSelectHelper(render_frame_host, params.mode));
  148. if (params.mode == content::FileChooserParams::Save) {
  149. settings.default_path = params.default_file_name;
  150. file_select_helper->ShowSaveDialog(settings);
  151. } else {
  152. int flags = file_dialog::FILE_DIALOG_CREATE_DIRECTORY;
  153. switch (params.mode) {
  154. case content::FileChooserParams::OpenMultiple:
  155. flags |= file_dialog::FILE_DIALOG_MULTI_SELECTIONS;
  156. case content::FileChooserParams::Open:
  157. flags |= file_dialog::FILE_DIALOG_OPEN_FILE;
  158. break;
  159. case content::FileChooserParams::UploadFolder:
  160. flags |= file_dialog::FILE_DIALOG_OPEN_DIRECTORY;
  161. break;
  162. default:
  163. NOTREACHED();
  164. }
  165. AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
  166. window_->web_contents()->GetBrowserContext());
  167. settings.default_path = browser_context->prefs()->GetFilePath(
  168. prefs::kSelectFileLastDirectory).Append(params.default_file_name);
  169. settings.properties = flags;
  170. file_select_helper->ShowOpenDialog(settings);
  171. }
  172. }
  173. void WebDialogHelper::EnumerateDirectory(content::WebContents* web_contents,
  174. int request_id,
  175. const base::FilePath& dir) {
  176. int types = base::FileEnumerator::FILES |
  177. base::FileEnumerator::DIRECTORIES |
  178. base::FileEnumerator::INCLUDE_DOT_DOT;
  179. base::FileEnumerator file_enum(dir, false, types);
  180. base::FilePath path;
  181. std::vector<base::FilePath> paths;
  182. while (!(path = file_enum.Next()).empty())
  183. paths.push_back(path);
  184. web_contents->GetRenderViewHost()->DirectoryEnumerationFinished(
  185. request_id, paths);
  186. }
  187. } // namespace atom