blob: b1c89fca2b294f477212fae55762f12646996472 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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_item_model.h"
6
7#include "base/i18n/number_formatting.h"
8#include "base/i18n/rtl.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01009#include "base/strings/string16.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010010#include "base/strings/sys_string_conversions.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010011#include "base/strings/utf_string_conversions.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000012#include "base/supports_user_data.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010013#include "base/time/time.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000014#include "chrome/browser/download/download_crx_util.h"
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010015#include "chrome/browser/safe_browsing/download_feedback_service.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000016#include "content/public/browser/download_danger_type.h"
17#include "content/public/browser/download_interrupt_reasons.h"
18#include "content/public/browser/download_item.h"
19#include "grit/chromium_strings.h"
20#include "grit/generated_resources.h"
21#include "ui/base/l10n/l10n_util.h"
Ben Murdochbb1529c2013-08-08 10:24:53 +010022#include "ui/base/l10n/time_format.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000023#include "ui/base/text/bytes_formatting.h"
24#include "ui/base/text/text_elider.h"
25
Torne (Richard Coles)58218062012-11-14 11:43:16 +000026using base::TimeDelta;
27using content::DownloadItem;
28
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000029namespace {
30
31// Per DownloadItem data used by DownloadItemModel. The model doesn't keep any
32// state since there could be multiple models associated with a single
33// DownloadItem, and the lifetime of the model is shorter than the DownloadItem.
34class DownloadItemModelData : public base::SupportsUserData::Data {
35 public:
36 // Get the DownloadItemModelData object for |download|. Returns NULL if
37 // there's no model data.
38 static const DownloadItemModelData* Get(const DownloadItem* download);
39
40 // Get the DownloadItemModelData object for |download|. Creates a model data
41 // object if not found. Always returns a non-NULL pointer, unless OOM.
42 static DownloadItemModelData* GetOrCreate(DownloadItem* download);
43
44 bool should_show_in_shelf() const { return should_show_in_shelf_; }
45 void set_should_show_in_shelf(bool should_show_in_shelf) {
46 should_show_in_shelf_ = should_show_in_shelf;
47 }
48
49 bool should_notify_ui() const { return should_notify_ui_; }
50 void set_should_notify_ui(bool should_notify_ui) {
51 should_notify_ui_ = should_notify_ui;
52 }
53
54 private:
55 DownloadItemModelData();
56 virtual ~DownloadItemModelData() {}
57
58 static const char kKey[];
59
60 // Whether the download should be displayed in the download shelf. True by
61 // default.
62 bool should_show_in_shelf_;
63
64 // Whether the UI should be notified when the download is ready to be
65 // presented.
66 bool should_notify_ui_;
67};
68
69// static
70const char DownloadItemModelData::kKey[] = "DownloadItemModelData key";
71
72// static
73const DownloadItemModelData* DownloadItemModelData::Get(
74 const DownloadItem* download) {
75 return static_cast<const DownloadItemModelData*>(download->GetUserData(kKey));
76}
77
78// static
79DownloadItemModelData* DownloadItemModelData::GetOrCreate(
80 DownloadItem* download) {
81 DownloadItemModelData* data =
82 static_cast<DownloadItemModelData*>(download->GetUserData(kKey));
83 if (data == NULL) {
84 data = new DownloadItemModelData();
85 download->SetUserData(kKey, data);
86 }
87 return data;
88}
89
90DownloadItemModelData::DownloadItemModelData()
91 : should_show_in_shelf_(true),
92 should_notify_ui_(false) {
93}
94
95string16 InterruptReasonStatusMessage(int reason) {
96 int string_id = 0;
97
98 switch (reason) {
99 case content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED:
100 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_ACCESS_DENIED;
101 break;
102 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
103 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_DISK_FULL;
104 break;
105 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
106 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_PATH_TOO_LONG;
107 break;
108 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
109 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_LARGE;
110 break;
111 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
112 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_VIRUS;
113 break;
114 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
115 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_TEMPORARY_PROBLEM;
116 break;
117 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
118 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_BLOCKED;
119 break;
120 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
121 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SECURITY_CHECK_FAILED;
122 break;
123 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
124 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_SHORT;
125 break;
126 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED:
127 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_ERROR;
128 break;
129 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
130 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_TIMEOUT;
131 break;
132 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
133 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_DISCONNECTED;
134 break;
135 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
136 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_DOWN;
137 break;
138 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
139 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_PROBLEM;
140 break;
141 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
142 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NO_FILE;
143 break;
144 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
145 string_id = IDS_DOWNLOAD_STATUS_CANCELLED;
146 break;
147 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
148 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SHUTDOWN;
149 break;
150 case content::DOWNLOAD_INTERRUPT_REASON_CRASH:
151 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_CRASH;
152 break;
153 default:
154 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
155 break;
156 }
157
158 return l10n_util::GetStringUTF16(string_id);
159}
160
161string16 InterruptReasonMessage(int reason) {
162 int string_id = 0;
163 string16 status_text;
164
165 switch (reason) {
166 case content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED:
167 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_ACCESS_DENIED;
168 break;
169 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
170 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_DISK_FULL;
171 break;
172 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
173 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_PATH_TOO_LONG;
174 break;
175 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
176 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_LARGE;
177 break;
178 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
179 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_VIRUS;
180 break;
181 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
182 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_TEMPORARY_PROBLEM;
183 break;
184 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
185 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_BLOCKED;
186 break;
187 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
188 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SECURITY_CHECK_FAILED;
189 break;
190 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
191 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_SHORT;
192 break;
193 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED:
194 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_ERROR;
195 break;
196 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
197 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_TIMEOUT;
198 break;
199 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
200 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_DISCONNECTED;
201 break;
202 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
203 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_DOWN;
204 break;
205 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
206 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_PROBLEM;
207 break;
208 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
209 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NO_FILE;
210 break;
211 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
212 string_id = IDS_DOWNLOAD_STATUS_CANCELLED;
213 break;
214 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
215 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SHUTDOWN;
216 break;
217 case content::DOWNLOAD_INTERRUPT_REASON_CRASH:
218 string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_CRASH;
219 break;
220 default:
221 string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
222 break;
223 }
224
225 status_text = l10n_util::GetStringUTF16(string_id);
226
227 return status_text;
228}
229
230} // namespace
231
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000232// -----------------------------------------------------------------------------
233// DownloadItemModel
234
235DownloadItemModel::DownloadItemModel(DownloadItem* download)
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000236 : download_(download) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000237}
238
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000239DownloadItemModel::~DownloadItemModel() {
240}
241
242string16 DownloadItemModel::GetInterruptReasonText() const {
243 if (download_->GetState() != DownloadItem::INTERRUPTED ||
244 download_->GetLastReason() ==
245 content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED) {
246 return string16();
247 }
248 return InterruptReasonMessage(download_->GetLastReason());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000249}
250
251string16 DownloadItemModel::GetStatusText() const {
252 string16 status_text;
253 switch (download_->GetState()) {
254 case DownloadItem::IN_PROGRESS:
255 status_text = GetInProgressStatusString();
256 break;
257 case DownloadItem::COMPLETE:
258 if (download_->GetFileExternallyRemoved()) {
259 status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_REMOVED);
260 } else {
261 status_text.clear();
262 }
263 break;
264 case DownloadItem::CANCELLED:
265 status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED);
266 break;
267 case DownloadItem::INTERRUPTED: {
268 content::DownloadInterruptReason reason = download_->GetLastReason();
269 if (reason != content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED) {
270 string16 interrupt_reason = InterruptReasonStatusMessage(reason);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000271 status_text = l10n_util::GetStringFUTF16(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000272 IDS_DOWNLOAD_STATUS_INTERRUPTED, interrupt_reason);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000273 } else {
274 // Same as DownloadItem::CANCELLED.
275 status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED);
276 }
277 break;
278 }
279 default:
280 NOTREACHED();
281 }
282
283 return status_text;
284}
285
286string16 DownloadItemModel::GetTooltipText(const gfx::Font& font,
287 int max_width) const {
288 string16 tooltip = ui::ElideFilename(
289 download_->GetFileNameToReportUser(), font, max_width);
290 content::DownloadInterruptReason reason = download_->GetLastReason();
291 if (download_->GetState() == DownloadItem::INTERRUPTED &&
292 reason != content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED) {
293 tooltip += ASCIIToUTF16("\n");
294 tooltip += ui::ElideText(InterruptReasonStatusMessage(reason),
295 font, max_width, ui::ELIDE_AT_END);
296 }
297 return tooltip;
298}
299
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000300string16 DownloadItemModel::GetWarningText(const gfx::Font& font,
301 int base_width) const {
302 // Should only be called if IsDangerous().
303 DCHECK(IsDangerous());
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100304 string16 elided_filename =
305 ui::ElideFilename(download_->GetFileNameToReportUser(), font, base_width);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000306 switch (download_->GetDangerType()) {
307 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
308 return l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL);
309
310 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
311 if (download_crx_util::IsExtensionDownload(*download_)) {
312 return l10n_util::GetStringUTF16(
313 IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION);
314 } else {
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100315 return l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD,
316 elided_filename);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000317 }
318
319 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000320 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100321 return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT,
322 elided_filename);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000323
324 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100325 return l10n_util::GetStringFUTF16(IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
326 elided_filename);
327
328 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000329 return l10n_util::GetStringFUTF16(
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100330 IDS_PROMPT_DOWNLOAD_CHANGES_SEARCH_SETTINGS, elided_filename);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000331
332 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
333 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000334 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000335 case content::DOWNLOAD_DANGER_TYPE_MAX:
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100336 break;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000337 }
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100338 NOTREACHED();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000339 return string16();
340}
341
342string16 DownloadItemModel::GetWarningConfirmButtonText() const {
343 // Should only be called if IsDangerous()
344 DCHECK(IsDangerous());
345 if (download_->GetDangerType() ==
346 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE &&
347 download_crx_util::IsExtensionDownload(*download_)) {
348 return l10n_util::GetStringUTF16(IDS_CONTINUE_EXTENSION_DOWNLOAD);
349 } else {
350 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD);
351 }
352}
353
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000354int64 DownloadItemModel::GetCompletedBytes() const {
355 return download_->GetReceivedBytes();
356}
357
358int64 DownloadItemModel::GetTotalBytes() const {
359 return download_->AllDataSaved() ? download_->GetReceivedBytes() :
360 download_->GetTotalBytes();
361}
362
363// TODO(asanka,rdsmith): Once 'open' moves exclusively to the
364// ChromeDownloadManagerDelegate, we should calculate the percentage here
365// instead of calling into the DownloadItem.
366int DownloadItemModel::PercentComplete() const {
367 return download_->PercentComplete();
368}
369
370bool DownloadItemModel::IsDangerous() const {
371 return download_->IsDangerous();
372}
373
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000374bool DownloadItemModel::IsMalicious() const {
375 if (!IsDangerous())
376 return false;
377 switch (download_->GetDangerType()) {
378 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
379 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
380 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000381 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100382 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000383 return true;
384
385 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
386 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000387 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000388 case content::DOWNLOAD_DANGER_TYPE_MAX:
389 // We shouldn't get any of these due to the IsDangerous() test above.
390 NOTREACHED();
391 // Fallthrough.
392 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
393 return false;
394 }
395 NOTREACHED();
396 return false;
397}
398
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100399bool DownloadItemModel::ShouldAllowDownloadFeedback() const {
400 if (!IsDangerous())
401 return false;
402 return safe_browsing::DownloadFeedbackService::IsEnabledForDownload(
403 *download_);
404}
405
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000406bool DownloadItemModel::ShouldRemoveFromShelfWhenComplete() const {
Ben Murdochca12bfa2013-07-23 11:17:05 +0100407 switch (download_->GetState()) {
408 case DownloadItem::IN_PROGRESS:
409 // If the download is dangerous or malicious, we should display a warning
410 // on the shelf until the user accepts the download.
411 if (IsDangerous())
412 return false;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000413
Ben Murdochca12bfa2013-07-23 11:17:05 +0100414 // If the download is an extension, temporary, or will be opened
415 // automatically, then it should be removed from the shelf on completion.
416 // TODO(asanka): The logic for deciding opening behavior should be in a
417 // central location. http://crbug.com/167702
418 return (download_crx_util::IsExtensionDownload(*download_) ||
419 download_->IsTemporary() ||
420 download_->GetOpenWhenComplete() ||
421 download_->ShouldOpenFileBasedOnExtension());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000422
Ben Murdochca12bfa2013-07-23 11:17:05 +0100423 case DownloadItem::COMPLETE:
424 // If the download completed, then rely on GetAutoOpened() to check for
425 // opening behavior. This should accurately reflect whether the download
426 // was successfully opened. Extensions, for example, may fail to open.
427 return download_->GetAutoOpened() || download_->IsTemporary();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000428
Ben Murdochca12bfa2013-07-23 11:17:05 +0100429 case DownloadItem::CANCELLED:
430 case DownloadItem::INTERRUPTED:
431 // Interrupted or cancelled downloads should remain on the shelf.
432 return false;
433
434 case DownloadItem::MAX_DOWNLOAD_STATE:
435 NOTREACHED();
436 }
437
438 NOTREACHED();
439 return false;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000440}
441
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000442bool DownloadItemModel::ShouldShowDownloadStartedAnimation() const {
443 return !download_->IsSavePackageDownload() &&
444 !download_crx_util::IsExtensionDownload(*download_);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000445}
446
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000447bool DownloadItemModel::ShouldShowInShelf() const {
448 const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
449 return !data || data->should_show_in_shelf();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000450}
451
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000452void DownloadItemModel::SetShouldShowInShelf(bool should_show) {
453 DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_);
454 data->set_should_show_in_shelf(should_show);
455}
456
457bool DownloadItemModel::ShouldNotifyUI() const {
458 const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
459 return data && data->should_notify_ui();
460}
461
462void DownloadItemModel::SetShouldNotifyUI(bool should_notify) {
463 DownloadItemModelData* data = DownloadItemModelData::GetOrCreate(download_);
464 data->set_should_notify_ui(should_notify);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000465}
466
467string16 DownloadItemModel::GetProgressSizesString() const {
468 string16 size_ratio;
469 int64 size = GetCompletedBytes();
470 int64 total = GetTotalBytes();
471 if (total > 0) {
472 ui::DataUnits amount_units = ui::GetByteDisplayUnits(total);
473 string16 simple_size = ui::FormatBytesWithUnits(size, amount_units, false);
474
475 // In RTL locales, we render the text "size/total" in an RTL context. This
476 // is problematic since a string such as "123/456 MB" is displayed
477 // as "MB 123/456" because it ends with an LTR run. In order to solve this,
478 // we mark the total string as an LTR string if the UI layout is
479 // right-to-left so that the string "456 MB" is treated as an LTR run.
480 string16 simple_total = base::i18n::GetDisplayStringInLTRDirectionality(
481 ui::FormatBytesWithUnits(total, amount_units, true));
482 size_ratio = l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_SIZES,
483 simple_size, simple_total);
484 } else {
485 size_ratio = ui::FormatBytes(size);
486 }
487 return size_ratio;
488}
489
490string16 DownloadItemModel::GetInProgressStatusString() const {
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100491 DCHECK_EQ(DownloadItem::IN_PROGRESS, download_->GetState());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000492
493 TimeDelta time_remaining;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000494 // time_remaining is only known if the download isn't paused.
495 bool time_remaining_known = (!download_->IsPaused() &&
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000496 download_->TimeRemaining(&time_remaining));
497
498 // Indication of progress. (E.g.:"100/200 MB" or "100MB")
499 string16 size_ratio = GetProgressSizesString();
500
501 // The download is a CRX (app, extension, theme, ...) and it is being unpacked
502 // and validated.
503 if (download_->AllDataSaved() &&
504 download_crx_util::IsExtensionDownload(*download_)) {
505 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CRX_INSTALL_RUNNING);
506 }
507
508 // A paused download: "100/120 MB, Paused"
509 if (download_->IsPaused()) {
510 return l10n_util::GetStringFUTF16(
511 IDS_DOWNLOAD_STATUS_IN_PROGRESS, size_ratio,
512 l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED));
513 }
514
515 // A download scheduled to be opened when complete: "Opening in 10 secs"
516 if (download_->GetOpenWhenComplete()) {
517 if (!time_remaining_known)
518 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_OPEN_WHEN_COMPLETE);
519
520 return l10n_util::GetStringFUTF16(
521 IDS_DOWNLOAD_STATUS_OPEN_IN,
Ben Murdochbb1529c2013-08-08 10:24:53 +0100522 ui::TimeFormat::TimeRemainingShort(time_remaining));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000523 }
524
525 // In progress download with known time left: "100/120 MB, 10 secs left"
526 if (time_remaining_known) {
527 return l10n_util::GetStringFUTF16(
528 IDS_DOWNLOAD_STATUS_IN_PROGRESS, size_ratio,
Ben Murdochbb1529c2013-08-08 10:24:53 +0100529 ui::TimeFormat::TimeRemaining(time_remaining));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000530 }
531
532 // In progress download with no known time left and non-zero completed bytes:
533 // "100/120 MB" or "100 MB"
534 if (GetCompletedBytes() > 0)
535 return size_ratio;
536
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000537 // Instead of displaying "0 B" we say "Starting..."
538 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_STARTING);
539}