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