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