Home | History | Annotate | Download | only in webui
      1 // Copyright (c) 2011 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/ui/webui/downloads_dom_handler.h"
      6 
      7 #include <algorithm>
      8 #include <functional>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/callback.h"
     12 #include "base/memory/singleton.h"
     13 #include "base/string_piece.h"
     14 #include "base/threading/thread.h"
     15 #include "base/utf_string_conversions.h"
     16 #include "base/values.h"
     17 #include "chrome/browser/browser_process.h"
     18 #include "chrome/browser/download/download_history.h"
     19 #include "chrome/browser/download/download_item.h"
     20 #include "chrome/browser/download/download_util.h"
     21 #include "chrome/browser/metrics/user_metrics.h"
     22 #include "chrome/browser/profiles/profile.h"
     23 #include "chrome/browser/ui/webui/chrome_url_data_manager.h"
     24 #include "chrome/browser/ui/webui/fileicon_source.h"
     25 #include "chrome/common/jstemplate_builder.h"
     26 #include "chrome/common/url_constants.h"
     27 #include "content/browser/browser_thread.h"
     28 #include "content/browser/tab_contents/tab_contents.h"
     29 #include "grit/generated_resources.h"
     30 #include "ui/gfx/image.h"
     31 
     32 namespace {
     33 
     34 // Maximum number of downloads to show. TODO(glen): Remove this and instead
     35 // stuff the downloads down the pipe slowly.
     36 static const int kMaxDownloads = 150;
     37 
     38 // Sort DownloadItems into descending order by their start time.
     39 class DownloadItemSorter : public std::binary_function<DownloadItem*,
     40                                                        DownloadItem*,
     41                                                        bool> {
     42  public:
     43   bool operator()(const DownloadItem* lhs, const DownloadItem* rhs) {
     44     return lhs->start_time() > rhs->start_time();
     45   }
     46 };
     47 
     48 }  // namespace
     49 
     50 DownloadsDOMHandler::DownloadsDOMHandler(DownloadManager* dlm)
     51     : search_text_(),
     52       download_manager_(dlm),
     53       callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
     54   // Create our fileicon data source.
     55   dlm->profile()->GetChromeURLDataManager()->AddDataSource(
     56       new FileIconSource());
     57 }
     58 
     59 DownloadsDOMHandler::~DownloadsDOMHandler() {
     60   ClearDownloadItems();
     61   download_manager_->RemoveObserver(this);
     62 }
     63 
     64 // DownloadsDOMHandler, public: -----------------------------------------------
     65 
     66 void DownloadsDOMHandler::Init() {
     67   download_manager_->AddObserver(this);
     68 }
     69 
     70 void DownloadsDOMHandler::RegisterMessages() {
     71   web_ui_->RegisterMessageCallback("getDownloads",
     72       NewCallback(this, &DownloadsDOMHandler::HandleGetDownloads));
     73   web_ui_->RegisterMessageCallback("openFile",
     74       NewCallback(this, &DownloadsDOMHandler::HandleOpenFile));
     75 
     76   web_ui_->RegisterMessageCallback("drag",
     77       NewCallback(this, &DownloadsDOMHandler::HandleDrag));
     78 
     79   web_ui_->RegisterMessageCallback("saveDangerous",
     80       NewCallback(this, &DownloadsDOMHandler::HandleSaveDangerous));
     81   web_ui_->RegisterMessageCallback("discardDangerous",
     82       NewCallback(this, &DownloadsDOMHandler::HandleDiscardDangerous));
     83   web_ui_->RegisterMessageCallback("show",
     84       NewCallback(this, &DownloadsDOMHandler::HandleShow));
     85   web_ui_->RegisterMessageCallback("togglepause",
     86       NewCallback(this, &DownloadsDOMHandler::HandlePause));
     87   web_ui_->RegisterMessageCallback("resume",
     88       NewCallback(this, &DownloadsDOMHandler::HandlePause));
     89   web_ui_->RegisterMessageCallback("remove",
     90       NewCallback(this, &DownloadsDOMHandler::HandleRemove));
     91   web_ui_->RegisterMessageCallback("cancel",
     92       NewCallback(this, &DownloadsDOMHandler::HandleCancel));
     93   web_ui_->RegisterMessageCallback("clearAll",
     94       NewCallback(this, &DownloadsDOMHandler::HandleClearAll));
     95 }
     96 
     97 void DownloadsDOMHandler::OnDownloadUpdated(DownloadItem* download) {
     98   // Get the id for the download. Our downloads are sorted latest to first,
     99   // and the id is the index into that list. We should be careful of sync
    100   // errors between the UI and the download_items_ list (we may wish to use
    101   // something other than 'id').
    102   OrderedDownloads::iterator it = find(download_items_.begin(),
    103                                        download_items_.end(),
    104                                        download);
    105   if (it == download_items_.end())
    106     return;
    107   const int id = static_cast<int>(it - download_items_.begin());
    108 
    109   ListValue results_value;
    110   results_value.Append(download_util::CreateDownloadItemValue(download, id));
    111   web_ui_->CallJavascriptFunction("downloadUpdated", results_value);
    112 }
    113 
    114 // A download has started or been deleted. Query our DownloadManager for the
    115 // current set of downloads.
    116 void DownloadsDOMHandler::ModelChanged() {
    117   ClearDownloadItems();
    118   download_manager_->SearchDownloads(WideToUTF16(search_text_),
    119                                      &download_items_);
    120   sort(download_items_.begin(), download_items_.end(), DownloadItemSorter());
    121 
    122   // Scan for any in progress downloads and add ourself to them as an observer.
    123   for (OrderedDownloads::iterator it = download_items_.begin();
    124        it != download_items_.end(); ++it) {
    125     if (static_cast<int>(it - download_items_.begin()) > kMaxDownloads)
    126       break;
    127 
    128     DownloadItem* download = *it;
    129     if (download->IsInProgress()) {
    130       // We want to know what happens as the download progresses.
    131       download->AddObserver(this);
    132     } else if (download->safety_state() == DownloadItem::DANGEROUS) {
    133       // We need to be notified when the user validates the dangerous download.
    134       download->AddObserver(this);
    135     }
    136   }
    137 
    138   SendCurrentDownloads();
    139 }
    140 
    141 void DownloadsDOMHandler::HandleGetDownloads(const ListValue* args) {
    142   std::wstring new_search = UTF16ToWideHack(ExtractStringValue(args));
    143   if (search_text_.compare(new_search) != 0) {
    144     search_text_ = new_search;
    145     ModelChanged();
    146   } else {
    147     SendCurrentDownloads();
    148   }
    149 }
    150 
    151 void DownloadsDOMHandler::HandleOpenFile(const ListValue* args) {
    152   DownloadItem* file = GetDownloadByValue(args);
    153   if (file)
    154     file->OpenDownload();
    155 }
    156 
    157 void DownloadsDOMHandler::HandleDrag(const ListValue* args) {
    158   DownloadItem* file = GetDownloadByValue(args);
    159   if (file) {
    160     IconManager* im = g_browser_process->icon_manager();
    161     gfx::Image* icon = im->LookupIcon(file->GetUserVerifiedFilePath(),
    162                                       IconLoader::NORMAL);
    163     gfx::NativeView view = web_ui_->tab_contents()->GetNativeView();
    164     download_util::DragDownload(file, icon, view);
    165   }
    166 }
    167 
    168 void DownloadsDOMHandler::HandleSaveDangerous(const ListValue* args) {
    169   DownloadItem* file = GetDownloadByValue(args);
    170   if (file)
    171     download_manager_->DangerousDownloadValidated(file);
    172 }
    173 
    174 void DownloadsDOMHandler::HandleDiscardDangerous(const ListValue* args) {
    175   DownloadItem* file = GetDownloadByValue(args);
    176   if (file)
    177     file->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD);
    178 }
    179 
    180 void DownloadsDOMHandler::HandleShow(const ListValue* args) {
    181   DownloadItem* file = GetDownloadByValue(args);
    182   if (file)
    183     file->ShowDownloadInShell();
    184 }
    185 
    186 void DownloadsDOMHandler::HandlePause(const ListValue* args) {
    187   DownloadItem* file = GetDownloadByValue(args);
    188   if (file)
    189     file->TogglePause();
    190 }
    191 
    192 void DownloadsDOMHandler::HandleRemove(const ListValue* args) {
    193   DownloadItem* file = GetDownloadByValue(args);
    194   if (file)
    195     file->Remove();
    196 }
    197 
    198 void DownloadsDOMHandler::HandleCancel(const ListValue* args) {
    199   DownloadItem* file = GetDownloadByValue(args);
    200   if (file)
    201     file->Cancel(true);
    202 }
    203 
    204 void DownloadsDOMHandler::HandleClearAll(const ListValue* args) {
    205   download_manager_->RemoveAllDownloads();
    206 }
    207 
    208 // DownloadsDOMHandler, private: ----------------------------------------------
    209 
    210 void DownloadsDOMHandler::SendCurrentDownloads() {
    211   ListValue results_value;
    212   for (OrderedDownloads::iterator it = download_items_.begin();
    213       it != download_items_.end(); ++it) {
    214     int index = static_cast<int>(it - download_items_.begin());
    215     if (index > kMaxDownloads)
    216       break;
    217     results_value.Append(download_util::CreateDownloadItemValue(*it, index));
    218   }
    219 
    220   web_ui_->CallJavascriptFunction("downloadsList", results_value);
    221 }
    222 
    223 void DownloadsDOMHandler::ClearDownloadItems() {
    224   // Clear out old state and remove self as observer for each download.
    225   for (OrderedDownloads::iterator it = download_items_.begin();
    226       it != download_items_.end(); ++it) {
    227     (*it)->RemoveObserver(this);
    228   }
    229   download_items_.clear();
    230 }
    231 
    232 DownloadItem* DownloadsDOMHandler::GetDownloadById(int id) {
    233   for (OrderedDownloads::iterator it = download_items_.begin();
    234       it != download_items_.end(); ++it) {
    235     if (static_cast<int>(it - download_items_.begin() == id)) {
    236       return (*it);
    237     }
    238   }
    239 
    240   return NULL;
    241 }
    242 
    243 DownloadItem* DownloadsDOMHandler::GetDownloadByValue(const ListValue* args) {
    244   int id;
    245   if (ExtractIntegerValue(args, &id)) {
    246     return GetDownloadById(id);
    247   }
    248   return NULL;
    249 }
    250