Home | History | Annotate | Download | only in browser
      1 // Copyright 2013 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 "content/shell/browser/shell_download_manager_delegate.h"
      6 
      7 #if defined(TOOLKIT_GTK)
      8 #include <gtk/gtk.h>
      9 #endif
     10 
     11 #if defined(OS_WIN)
     12 #include <windows.h>
     13 #include <commdlg.h>
     14 #endif
     15 
     16 #include "base/bind.h"
     17 #include "base/command_line.h"
     18 #include "base/file_util.h"
     19 #include "base/logging.h"
     20 #include "base/strings/string_util.h"
     21 #include "base/strings/utf_string_conversions.h"
     22 #include "content/public/browser/browser_context.h"
     23 #include "content/public/browser/browser_thread.h"
     24 #include "content/public/browser/download_manager.h"
     25 #include "content/public/browser/web_contents.h"
     26 #include "content/public/browser/web_contents_view.h"
     27 #include "content/shell/browser/webkit_test_controller.h"
     28 #include "content/shell/common/shell_switches.h"
     29 #include "net/base/net_util.h"
     30 
     31 namespace content {
     32 
     33 ShellDownloadManagerDelegate::ShellDownloadManagerDelegate()
     34     : download_manager_(NULL),
     35       suppress_prompting_(false) {
     36   // Balanced in Shutdown();
     37   AddRef();
     38 }
     39 
     40 ShellDownloadManagerDelegate::~ShellDownloadManagerDelegate(){
     41 }
     42 
     43 
     44 void ShellDownloadManagerDelegate::SetDownloadManager(
     45     DownloadManager* download_manager) {
     46   download_manager_ = download_manager;
     47 }
     48 
     49 void ShellDownloadManagerDelegate::Shutdown() {
     50   Release();
     51 }
     52 
     53 bool ShellDownloadManagerDelegate::DetermineDownloadTarget(
     54     DownloadItem* download,
     55     const DownloadTargetCallback& callback) {
     56   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     57   // This assignment needs to be here because even at the call to
     58   // SetDownloadManager, the system is not fully initialized.
     59   if (default_download_path_.empty()) {
     60     default_download_path_ = download_manager_->GetBrowserContext()->GetPath().
     61         Append(FILE_PATH_LITERAL("Downloads"));
     62   }
     63 
     64   if (!download->GetForcedFilePath().empty()) {
     65     callback.Run(download->GetForcedFilePath(),
     66                  DownloadItem::TARGET_DISPOSITION_OVERWRITE,
     67                  DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
     68                  download->GetForcedFilePath());
     69     return true;
     70   }
     71 
     72   base::FilePath generated_name = net::GenerateFileName(
     73       download->GetURL(),
     74       download->GetContentDisposition(),
     75       std::string(),
     76       download->GetSuggestedFilename(),
     77       download->GetMimeType(),
     78       "download");
     79 
     80   BrowserThread::PostTask(
     81       BrowserThread::FILE,
     82       FROM_HERE,
     83       base::Bind(
     84           &ShellDownloadManagerDelegate::GenerateFilename,
     85           this, download->GetId(), callback, generated_name,
     86           default_download_path_));
     87   return true;
     88 }
     89 
     90 bool ShellDownloadManagerDelegate::ShouldOpenDownload(
     91       DownloadItem* item,
     92       const DownloadOpenDelayedCallback& callback) {
     93   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree) &&
     94       WebKitTestController::Get()->IsMainWindow(item->GetWebContents()) &&
     95       item->GetMimeType() == "text/html") {
     96     WebKitTestController::Get()->OpenURL(
     97         net::FilePathToFileURL(item->GetFullPath()));
     98   }
     99   return true;
    100 }
    101 
    102 void ShellDownloadManagerDelegate::GetNextId(
    103     const DownloadIdCallback& callback) {
    104   static uint32 next_id = DownloadItem::kInvalidId + 1;
    105   callback.Run(next_id++);
    106 }
    107 
    108 void ShellDownloadManagerDelegate::GenerateFilename(
    109     uint32 download_id,
    110     const DownloadTargetCallback& callback,
    111     const base::FilePath& generated_name,
    112     const base::FilePath& suggested_directory) {
    113   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    114   if (!base::PathExists(suggested_directory))
    115     base::CreateDirectory(suggested_directory);
    116 
    117   base::FilePath suggested_path(suggested_directory.Append(generated_name));
    118   BrowserThread::PostTask(
    119       BrowserThread::UI,
    120       FROM_HERE,
    121       base::Bind(
    122           &ShellDownloadManagerDelegate::OnDownloadPathGenerated,
    123           this, download_id, callback, suggested_path));
    124 }
    125 
    126 void ShellDownloadManagerDelegate::OnDownloadPathGenerated(
    127     uint32 download_id,
    128     const DownloadTargetCallback& callback,
    129     const base::FilePath& suggested_path) {
    130   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    131   if (suppress_prompting_) {
    132     // Testing exit.
    133     callback.Run(suggested_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
    134                  DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
    135                  suggested_path.AddExtension(FILE_PATH_LITERAL(".crdownload")));
    136     return;
    137   }
    138 
    139   ChooseDownloadPath(download_id, callback, suggested_path);
    140 }
    141 
    142 void ShellDownloadManagerDelegate::ChooseDownloadPath(
    143     uint32 download_id,
    144     const DownloadTargetCallback& callback,
    145     const base::FilePath& suggested_path) {
    146   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    147   DownloadItem* item = download_manager_->GetDownload(download_id);
    148   if (!item || (item->GetState() != DownloadItem::IN_PROGRESS))
    149     return;
    150 
    151   base::FilePath result;
    152 #if defined(OS_WIN) && !defined(USE_AURA)
    153   std::wstring file_part = base::FilePath(suggested_path).BaseName().value();
    154   wchar_t file_name[MAX_PATH];
    155   base::wcslcpy(file_name, file_part.c_str(), arraysize(file_name));
    156   OPENFILENAME save_as;
    157   ZeroMemory(&save_as, sizeof(save_as));
    158   save_as.lStructSize = sizeof(OPENFILENAME);
    159   save_as.hwndOwner = item->GetWebContents()->GetView()->GetNativeView();
    160   save_as.lpstrFile = file_name;
    161   save_as.nMaxFile = arraysize(file_name);
    162 
    163   std::wstring directory;
    164   if (!suggested_path.empty())
    165     directory = suggested_path.DirName().value();
    166 
    167   save_as.lpstrInitialDir = directory.c_str();
    168   save_as.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING |
    169                   OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
    170 
    171   if (GetSaveFileName(&save_as))
    172     result = base::FilePath(std::wstring(save_as.lpstrFile));
    173 #elif defined(TOOLKIT_GTK)
    174   GtkWidget *dialog;
    175   gfx::NativeWindow parent_window;
    176   std::string base_name = base::FilePath(suggested_path).BaseName().value();
    177 
    178   parent_window = item->GetWebContents()->GetView()->GetTopLevelNativeWindow();
    179   dialog = gtk_file_chooser_dialog_new("Save File",
    180                                        parent_window,
    181                                        GTK_FILE_CHOOSER_ACTION_SAVE,
    182                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
    183                                        GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
    184                                        NULL);
    185   gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog),
    186                                                  TRUE);
    187   gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog),
    188                                     base_name.c_str());
    189 
    190   if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
    191     char *filename;
    192     filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
    193     result = base::FilePath(filename);
    194     g_free(filename);
    195   }
    196   gtk_widget_destroy(dialog);
    197 #else
    198   NOTIMPLEMENTED();
    199 #endif
    200 
    201   callback.Run(result, DownloadItem::TARGET_DISPOSITION_PROMPT,
    202                DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, result);
    203 }
    204 
    205 void ShellDownloadManagerDelegate::SetDownloadBehaviorForTesting(
    206     const base::FilePath& default_download_path) {
    207   default_download_path_ = default_download_path;
    208   suppress_prompting_ = true;
    209 }
    210 
    211 }  // namespace content
    212