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/download_file_picker.h" 6 7 #include "base/metrics/histogram.h" 8 #include "chrome/browser/download/download_prefs.h" 9 #include "chrome/browser/platform_util.h" 10 #include "chrome/browser/ui/chrome_select_file_policy.h" 11 #include "content/public/browser/browser_context.h" 12 #include "content/public/browser/download_item.h" 13 #include "content/public/browser/download_manager.h" 14 #include "content/public/browser/web_contents.h" 15 16 using content::DownloadItem; 17 using content::DownloadManager; 18 using content::WebContents; 19 20 namespace { 21 22 enum FilePickerResult { 23 FILE_PICKER_SAME, 24 FILE_PICKER_DIFFERENT_DIR, 25 FILE_PICKER_DIFFERENT_NAME, 26 FILE_PICKER_CANCEL, 27 FILE_PICKER_MAX, 28 }; 29 30 // Record how the File Picker was used during a download. This UMA is only 31 // recorded for profiles that do not always prompt for save locations on 32 // downloads. 33 void RecordFilePickerResult(const base::FilePath& suggested_path, 34 const base::FilePath& actual_path) { 35 FilePickerResult result; 36 if (suggested_path == actual_path) 37 result = FILE_PICKER_SAME; 38 else if (actual_path.empty()) 39 result = FILE_PICKER_CANCEL; 40 else if (suggested_path.DirName() != actual_path.DirName()) 41 result = FILE_PICKER_DIFFERENT_DIR; 42 else 43 result = FILE_PICKER_DIFFERENT_NAME; 44 45 UMA_HISTOGRAM_ENUMERATION("Download.FilePickerResult", 46 result, 47 FILE_PICKER_MAX); 48 } 49 50 } // namespace 51 52 DownloadFilePicker::DownloadFilePicker( 53 DownloadItem* item, 54 const base::FilePath& suggested_path, 55 const FileSelectedCallback& callback) 56 : suggested_path_(suggested_path), 57 file_selected_callback_(callback), 58 should_record_file_picker_result_(false) { 59 const DownloadPrefs* prefs = 60 DownloadPrefs::FromBrowserContext(item->GetBrowserContext()); 61 DCHECK(prefs); 62 // Only record UMA if we aren't prompting the user for all downloads. 63 should_record_file_picker_result_ = !prefs->PromptForDownload(); 64 65 WebContents* web_contents = item->GetWebContents(); 66 select_file_dialog_ = ui::SelectFileDialog::Create( 67 this, new ChromeSelectFilePolicy(web_contents)); 68 ui::SelectFileDialog::FileTypeInfo file_type_info; 69 // Platform file pickers, notably on Mac and Windows, tend to break 70 // with double extensions like .tar.gz, so only pass in normal ones. 71 base::FilePath::StringType extension = suggested_path_.FinalExtension(); 72 if (!extension.empty()) { 73 extension.erase(extension.begin()); // drop the . 74 file_type_info.extensions.resize(1); 75 file_type_info.extensions[0].push_back(extension); 76 } 77 file_type_info.include_all_files = true; 78 file_type_info.support_drive = true; 79 gfx::NativeWindow owning_window = web_contents ? 80 platform_util::GetTopLevel(web_contents->GetNativeView()) : NULL; 81 82 select_file_dialog_->SelectFile(ui::SelectFileDialog::SELECT_SAVEAS_FILE, 83 base::string16(), 84 suggested_path_, 85 &file_type_info, 86 0, 87 base::FilePath::StringType(), 88 owning_window, 89 NULL); 90 } 91 92 DownloadFilePicker::~DownloadFilePicker() { 93 } 94 95 void DownloadFilePicker::OnFileSelected(const base::FilePath& path) { 96 if (should_record_file_picker_result_) 97 RecordFilePickerResult(suggested_path_, path); 98 file_selected_callback_.Run(path); 99 delete this; 100 } 101 102 void DownloadFilePicker::FileSelected(const base::FilePath& path, 103 int index, 104 void* params) { 105 OnFileSelected(path); 106 // Deletes |this| 107 } 108 109 void DownloadFilePicker::FileSelectionCanceled(void* params) { 110 OnFileSelected(base::FilePath()); 111 // Deletes |this| 112 } 113 114 // static 115 void DownloadFilePicker::ShowFilePicker(DownloadItem* item, 116 const base::FilePath& suggested_path, 117 const FileSelectedCallback& callback) { 118 new DownloadFilePicker(item, suggested_path, callback); 119 // DownloadFilePicker deletes itself. 120 } 121