• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
operator ()(const DownloadItem * lhs,const DownloadItem * rhs)43   bool operator()(const DownloadItem* lhs, const DownloadItem* rhs) {
44     return lhs->start_time() > rhs->start_time();
45   }
46 };
47 
48 }  // namespace
49 
DownloadsDOMHandler(DownloadManager * dlm)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 
~DownloadsDOMHandler()59 DownloadsDOMHandler::~DownloadsDOMHandler() {
60   ClearDownloadItems();
61   download_manager_->RemoveObserver(this);
62 }
63 
64 // DownloadsDOMHandler, public: -----------------------------------------------
65 
Init()66 void DownloadsDOMHandler::Init() {
67   download_manager_->AddObserver(this);
68 }
69 
RegisterMessages()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 
OnDownloadUpdated(DownloadItem * download)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.
ModelChanged()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 
HandleGetDownloads(const ListValue * args)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 
HandleOpenFile(const ListValue * args)151 void DownloadsDOMHandler::HandleOpenFile(const ListValue* args) {
152   DownloadItem* file = GetDownloadByValue(args);
153   if (file)
154     file->OpenDownload();
155 }
156 
HandleDrag(const ListValue * args)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 
HandleSaveDangerous(const ListValue * args)168 void DownloadsDOMHandler::HandleSaveDangerous(const ListValue* args) {
169   DownloadItem* file = GetDownloadByValue(args);
170   if (file)
171     download_manager_->DangerousDownloadValidated(file);
172 }
173 
HandleDiscardDangerous(const ListValue * args)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 
HandleShow(const ListValue * args)180 void DownloadsDOMHandler::HandleShow(const ListValue* args) {
181   DownloadItem* file = GetDownloadByValue(args);
182   if (file)
183     file->ShowDownloadInShell();
184 }
185 
HandlePause(const ListValue * args)186 void DownloadsDOMHandler::HandlePause(const ListValue* args) {
187   DownloadItem* file = GetDownloadByValue(args);
188   if (file)
189     file->TogglePause();
190 }
191 
HandleRemove(const ListValue * args)192 void DownloadsDOMHandler::HandleRemove(const ListValue* args) {
193   DownloadItem* file = GetDownloadByValue(args);
194   if (file)
195     file->Remove();
196 }
197 
HandleCancel(const ListValue * args)198 void DownloadsDOMHandler::HandleCancel(const ListValue* args) {
199   DownloadItem* file = GetDownloadByValue(args);
200   if (file)
201     file->Cancel(true);
202 }
203 
HandleClearAll(const ListValue * args)204 void DownloadsDOMHandler::HandleClearAll(const ListValue* args) {
205   download_manager_->RemoveAllDownloads();
206 }
207 
208 // DownloadsDOMHandler, private: ----------------------------------------------
209 
SendCurrentDownloads()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 
ClearDownloadItems()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 
GetDownloadById(int id)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 
GetDownloadByValue(const ListValue * args)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