|  | // Copyright (c) 2012 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/download/download_file_picker.h" | 
|  |  | 
|  | #include "base/metrics/histogram.h" | 
|  | #include "chrome/browser/download/download_prefs.h" | 
|  | #include "chrome/browser/platform_util.h" | 
|  | #include "chrome/browser/ui/chrome_select_file_policy.h" | 
|  | #include "content/public/browser/browser_context.h" | 
|  | #include "content/public/browser/download_item.h" | 
|  | #include "content/public/browser/download_manager.h" | 
|  | #include "content/public/browser/web_contents.h" | 
|  |  | 
|  | using content::DownloadItem; | 
|  | using content::DownloadManager; | 
|  | using content::WebContents; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | enum FilePickerResult { | 
|  | FILE_PICKER_SAME, | 
|  | FILE_PICKER_DIFFERENT_DIR, | 
|  | FILE_PICKER_DIFFERENT_NAME, | 
|  | FILE_PICKER_CANCEL, | 
|  | FILE_PICKER_MAX, | 
|  | }; | 
|  |  | 
|  | // Record how the File Picker was used during a download. This UMA is only | 
|  | // recorded for profiles that do not always prompt for save locations on | 
|  | // downloads. | 
|  | void RecordFilePickerResult(const base::FilePath& suggested_path, | 
|  | const base::FilePath& actual_path) { | 
|  | FilePickerResult result; | 
|  | if (suggested_path == actual_path) | 
|  | result = FILE_PICKER_SAME; | 
|  | else if (actual_path.empty()) | 
|  | result = FILE_PICKER_CANCEL; | 
|  | else if (suggested_path.DirName() != actual_path.DirName()) | 
|  | result = FILE_PICKER_DIFFERENT_DIR; | 
|  | else | 
|  | result = FILE_PICKER_DIFFERENT_NAME; | 
|  |  | 
|  | UMA_HISTOGRAM_ENUMERATION("Download.FilePickerResult", | 
|  | result, | 
|  | FILE_PICKER_MAX); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | DownloadFilePicker::DownloadFilePicker( | 
|  | DownloadItem* item, | 
|  | const base::FilePath& suggested_path, | 
|  | const FileSelectedCallback& callback) | 
|  | : suggested_path_(suggested_path), | 
|  | file_selected_callback_(callback), | 
|  | should_record_file_picker_result_(false) { | 
|  | const DownloadPrefs* prefs = | 
|  | DownloadPrefs::FromBrowserContext(item->GetBrowserContext()); | 
|  | DCHECK(prefs); | 
|  | // Only record UMA if we aren't prompting the user for all downloads. | 
|  | should_record_file_picker_result_ = !prefs->PromptForDownload(); | 
|  |  | 
|  | WebContents* web_contents = item->GetWebContents(); | 
|  | select_file_dialog_ = ui::SelectFileDialog::Create( | 
|  | this, new ChromeSelectFilePolicy(web_contents)); | 
|  | ui::SelectFileDialog::FileTypeInfo file_type_info; | 
|  | // Platform file pickers, notably on Mac and Windows, tend to break | 
|  | // with double extensions like .tar.gz, so only pass in normal ones. | 
|  | base::FilePath::StringType extension = suggested_path_.FinalExtension(); | 
|  | if (!extension.empty()) { | 
|  | extension.erase(extension.begin());  // drop the . | 
|  | file_type_info.extensions.resize(1); | 
|  | file_type_info.extensions[0].push_back(extension); | 
|  | } | 
|  | file_type_info.include_all_files = true; | 
|  | file_type_info.support_drive = true; | 
|  | gfx::NativeWindow owning_window = web_contents ? | 
|  | platform_util::GetTopLevel(web_contents->GetNativeView()) : NULL; | 
|  |  | 
|  | select_file_dialog_->SelectFile(ui::SelectFileDialog::SELECT_SAVEAS_FILE, | 
|  | base::string16(), | 
|  | suggested_path_, | 
|  | &file_type_info, | 
|  | 0, | 
|  | base::FilePath::StringType(), | 
|  | owning_window, | 
|  | NULL); | 
|  | } | 
|  |  | 
|  | DownloadFilePicker::~DownloadFilePicker() { | 
|  | } | 
|  |  | 
|  | void DownloadFilePicker::OnFileSelected(const base::FilePath& path) { | 
|  | if (should_record_file_picker_result_) | 
|  | RecordFilePickerResult(suggested_path_, path); | 
|  | file_selected_callback_.Run(path); | 
|  | delete this; | 
|  | } | 
|  |  | 
|  | void DownloadFilePicker::FileSelected(const base::FilePath& path, | 
|  | int index, | 
|  | void* params) { | 
|  | OnFileSelected(path); | 
|  | // Deletes |this| | 
|  | } | 
|  |  | 
|  | void DownloadFilePicker::FileSelectionCanceled(void* params) { | 
|  | OnFileSelected(base::FilePath()); | 
|  | // Deletes |this| | 
|  | } | 
|  |  | 
|  | // static | 
|  | void DownloadFilePicker::ShowFilePicker(DownloadItem* item, | 
|  | const base::FilePath& suggested_path, | 
|  | const FileSelectedCallback& callback) { | 
|  | new DownloadFilePicker(item, suggested_path, callback); | 
|  | // DownloadFilePicker deletes itself. | 
|  | } |