Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / download / save_package_file_picker.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/download/save_package_file_picker.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/i18n/file_util_icu.h"
10 #include "base/metrics/histogram.h"
11 #include "base/prefs/pref_member.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/download/chrome_download_manager_delegate.h"
15 #include "chrome/browser/download/download_prefs.h"
16 #include "chrome/browser/platform_util.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/chrome_select_file_policy.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/common/pref_names.h"
21 #include "content/public/browser/download_manager.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/save_page_type.h"
24 #include "content/public/browser/web_contents.h"
25 #include "grit/generated_resources.h"
26 #include "ui/base/l10n/l10n_util.h"
27
28 #if defined(OS_CHROMEOS)
29 #include "chrome/browser/chromeos/drive/download_handler.h"
30 #include "chrome/browser/chromeos/drive/file_system_util.h"
31 #endif
32
33 using content::RenderProcessHost;
34 using content::SavePageType;
35 using content::WebContents;
36
37 namespace {
38
39 // If false, we don't prompt the user as to where to save the file.  This
40 // exists only for testing.
41 bool g_should_prompt_for_filename = true;
42
43 void OnSavePackageDownloadCreated(content::DownloadItem* download) {
44   ChromeDownloadManagerDelegate::DisableSafeBrowsing(download);
45 }
46
47 #if defined(OS_CHROMEOS)
48 void OnSavePackageDownloadCreatedChromeOS(
49     Profile* profile,
50     const base::FilePath& drive_path,
51     content::DownloadItem* download) {
52   drive::DownloadHandler::GetForProfile(profile)->SetDownloadParams(
53       drive_path, download);
54   OnSavePackageDownloadCreated(download);
55 }
56
57 // Trampoline callback between SubstituteDriveDownloadPath() and |callback|.
58 void ContinueSettingUpDriveDownload(
59     const content::SavePackagePathPickedCallback& callback,
60     content::SavePageType save_type,
61     Profile* profile,
62     const base::FilePath& drive_path,
63     const base::FilePath& drive_tmp_download_path) {
64   if (drive_tmp_download_path.empty())  // Substitution failed.
65     return;
66   callback.Run(drive_tmp_download_path, save_type, base::Bind(
67       &OnSavePackageDownloadCreatedChromeOS, profile, drive_path));
68 }
69 #endif
70
71 // Adds "Webpage, HTML Only" type to FileTypeInfo.
72 void AddHtmlOnlyFileTypeInfo(
73     ui::SelectFileDialog::FileTypeInfo* file_type_info,
74     const base::FilePath::StringType& extra_extension) {
75   file_type_info->extension_description_overrides.push_back(
76       l10n_util::GetStringUTF16(IDS_SAVE_PAGE_DESC_HTML_ONLY));
77
78   std::vector<base::FilePath::StringType> extensions;
79   extensions.push_back(FILE_PATH_LITERAL("html"));
80   extensions.push_back(FILE_PATH_LITERAL("htm"));
81   if (!extra_extension.empty())
82     extensions.push_back(extra_extension);
83   file_type_info->extensions.push_back(extensions);
84 }
85
86 // Adds "Web Archive, Single File" type to FileTypeInfo.
87 void AddSingleFileFileTypeInfo(
88     ui::SelectFileDialog::FileTypeInfo* file_type_info) {
89   file_type_info->extension_description_overrides.push_back(
90       l10n_util::GetStringUTF16(IDS_SAVE_PAGE_DESC_SINGLE_FILE));
91
92   std::vector<base::FilePath::StringType> extensions;
93   extensions.push_back(FILE_PATH_LITERAL("mhtml"));
94   file_type_info->extensions.push_back(extensions);
95 }
96
97 // Chrome OS doesn't support HTML-Complete. crbug.com/154823
98 #if !defined(OS_CHROMEOS)
99 // Adds "Webpage, Complete" type to FileTypeInfo.
100 void AddCompleteFileTypeInfo(
101     ui::SelectFileDialog::FileTypeInfo* file_type_info,
102     const base::FilePath::StringType& extra_extension) {
103   file_type_info->extension_description_overrides.push_back(
104       l10n_util::GetStringUTF16(IDS_SAVE_PAGE_DESC_COMPLETE));
105
106   std::vector<base::FilePath::StringType> extensions;
107   extensions.push_back(FILE_PATH_LITERAL("htm"));
108   extensions.push_back(FILE_PATH_LITERAL("html"));
109   if (!extra_extension.empty())
110     extensions.push_back(extra_extension);
111   file_type_info->extensions.push_back(extensions);
112 }
113 #endif
114
115 }  // anonymous namespace
116
117 bool SavePackageFilePicker::ShouldSaveAsMHTML() const {
118 #if !defined(OS_CHROMEOS)
119   if (!CommandLine::ForCurrentProcess()->HasSwitch(
120              switches::kSavePageAsMHTML))
121     return false;
122 #endif
123   return can_save_as_complete_;
124 }
125
126 SavePackageFilePicker::SavePackageFilePicker(
127     content::WebContents* web_contents,
128     const base::FilePath& suggested_path,
129     const base::FilePath::StringType& default_extension,
130     bool can_save_as_complete,
131     DownloadPrefs* download_prefs,
132     const content::SavePackagePathPickedCallback& callback)
133     : render_process_id_(web_contents->GetRenderProcessHost()->GetID()),
134       can_save_as_complete_(can_save_as_complete),
135       download_prefs_(download_prefs),
136       callback_(callback) {
137   base::FilePath suggested_path_copy = suggested_path;
138   base::FilePath::StringType default_extension_copy = default_extension;
139   int file_type_index = 0;
140   ui::SelectFileDialog::FileTypeInfo file_type_info;
141
142   file_type_info.support_drive = true;
143
144   if (can_save_as_complete_) {
145     // The option index is not zero-based. Put a dummy entry.
146     save_types_.push_back(content::SAVE_PAGE_TYPE_UNKNOWN);
147
148     base::FilePath::StringType extra_extension;
149     if (ShouldSaveAsMHTML()) {
150       default_extension_copy = FILE_PATH_LITERAL("mhtml");
151       suggested_path_copy = suggested_path_copy.ReplaceExtension(
152           default_extension_copy);
153     } else {
154       if (!suggested_path_copy.FinalExtension().empty() &&
155           !suggested_path_copy.MatchesExtension(FILE_PATH_LITERAL(".htm")) &&
156           !suggested_path_copy.MatchesExtension(FILE_PATH_LITERAL(".html"))) {
157         extra_extension = suggested_path_copy.FinalExtension().substr(1);
158       }
159     }
160
161     AddHtmlOnlyFileTypeInfo(&file_type_info, extra_extension);
162     save_types_.push_back(content::SAVE_PAGE_TYPE_AS_ONLY_HTML);
163
164     if (ShouldSaveAsMHTML()) {
165       AddSingleFileFileTypeInfo(&file_type_info);
166       save_types_.push_back(content::SAVE_PAGE_TYPE_AS_MHTML);
167     }
168
169 #if !defined(OS_CHROMEOS)
170     AddCompleteFileTypeInfo(&file_type_info, extra_extension);
171     save_types_.push_back(content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML);
172 #endif
173
174     file_type_info.include_all_files = false;
175
176     content::SavePageType preferred_save_type =
177         static_cast<content::SavePageType>(download_prefs_->save_file_type());
178     if (ShouldSaveAsMHTML())
179       preferred_save_type = content::SAVE_PAGE_TYPE_AS_MHTML;
180
181     // Select the item saved in the pref.
182     for (size_t i = 0; i < save_types_.size(); ++i) {
183       if (save_types_[i] == preferred_save_type) {
184         file_type_index = i;
185         break;
186       }
187     }
188
189     // If the item saved in the pref was not found, use the last item.
190     if (!file_type_index)
191       file_type_index = save_types_.size() - 1;
192   } else {
193     // The contents can not be saved as complete-HTML, so do not show the file
194     // filters.
195     file_type_info.extensions.resize(1);
196     file_type_info.extensions[0].push_back(
197         suggested_path_copy.FinalExtension());
198
199     if (!file_type_info.extensions[0][0].empty()) {
200       // Drop the .
201       file_type_info.extensions[0][0].erase(0, 1);
202     }
203
204     file_type_info.include_all_files = true;
205     file_type_index = 1;
206   }
207
208   if (g_should_prompt_for_filename) {
209     select_file_dialog_ = ui::SelectFileDialog::Create(
210         this, new ChromeSelectFilePolicy(web_contents));
211     select_file_dialog_->SelectFile(
212         ui::SelectFileDialog::SELECT_SAVEAS_FILE,
213         base::string16(),
214         suggested_path_copy,
215         &file_type_info,
216         file_type_index,
217         default_extension_copy,
218         platform_util::GetTopLevel(web_contents->GetNativeView()),
219         NULL);
220   } else {
221     // Just use 'suggested_path_copy' instead of opening the dialog prompt.
222     // Go through FileSelected() for consistency.
223     FileSelected(suggested_path_copy, file_type_index, NULL);
224   }
225 }
226
227 SavePackageFilePicker::~SavePackageFilePicker() {
228 }
229
230 void SavePackageFilePicker::SetShouldPromptUser(bool should_prompt) {
231   g_should_prompt_for_filename = should_prompt;
232 }
233
234 void SavePackageFilePicker::FileSelected(
235     const base::FilePath& path, int index, void* unused_params) {
236   scoped_ptr<SavePackageFilePicker> delete_this(this);
237   RenderProcessHost* process = RenderProcessHost::FromID(render_process_id_);
238   if (!process)
239     return;
240   SavePageType save_type = content::SAVE_PAGE_TYPE_UNKNOWN;
241
242   if (can_save_as_complete_) {
243     DCHECK_LT(index, static_cast<int>(save_types_.size()));
244     save_type = save_types_[index];
245     if (select_file_dialog_.get() &&
246         select_file_dialog_->HasMultipleFileTypeChoices())
247       download_prefs_->SetSaveFileType(save_type);
248
249     UMA_HISTOGRAM_ENUMERATION("Download.SavePageType",
250                               save_type,
251                               content::SAVE_PAGE_TYPE_MAX);
252   } else {
253     // Use "HTML Only" type as a dummy.
254     save_type = content::SAVE_PAGE_TYPE_AS_ONLY_HTML;
255   }
256
257   base::FilePath path_copy(path);
258   base::i18n::NormalizeFileNameEncoding(&path_copy);
259
260   download_prefs_->SetSaveFilePath(path_copy.DirName());
261
262 #if defined(OS_CHROMEOS)
263   if (drive::util::IsUnderDriveMountPoint(path_copy)) {
264     // Here's a map to the callback chain:
265     // SubstituteDriveDownloadPath ->
266     //   ContinueSettingUpDriveDownload ->
267     //     callback_ = SavePackage::OnPathPicked ->
268     //       download_created_callback = OnSavePackageDownloadCreatedChromeOS
269     Profile* profile = Profile::FromBrowserContext(
270         process->GetBrowserContext());
271     drive::DownloadHandler* drive_download_handler =
272         drive::DownloadHandler::GetForProfile(profile);
273     drive_download_handler->SubstituteDriveDownloadPath(
274         path_copy, NULL, base::Bind(&ContinueSettingUpDriveDownload,
275                                     callback_,
276                                     save_type,
277                                     profile,
278                                     path_copy));
279     return;
280   }
281 #endif
282
283   callback_.Run(path_copy, save_type,
284                 base::Bind(&OnSavePackageDownloadCreated));
285 }
286
287 void SavePackageFilePicker::FileSelectionCanceled(void* unused_params) {
288   delete this;
289 }