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.
5 #include "chrome/browser/download/download_item_model.h"
7 #include "base/i18n/number_formatting.h"
8 #include "base/i18n/rtl.h"
9 #include "base/metrics/field_trial.h"
10 #include "base/strings/string16.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/supports_user_data.h"
14 #include "base/time/time.h"
15 #include "chrome/browser/download/chrome_download_manager_delegate.h"
16 #include "chrome/browser/download/download_crx_util.h"
17 #include "chrome/browser/download/download_service.h"
18 #include "chrome/browser/download/download_service_factory.h"
19 #include "chrome/browser/download/download_stats.h"
20 #include "chrome/browser/safe_browsing/download_feedback_service.h"
21 #include "content/public/browser/download_danger_type.h"
22 #include "content/public/browser/download_interrupt_reasons.h"
23 #include "content/public/browser/download_item.h"
24 #include "grit/chromium_strings.h"
25 #include "grit/generated_resources.h"
26 #include "ui/base/l10n/l10n_util.h"
27 #include "ui/base/l10n/time_format.h"
28 #include "ui/base/text/bytes_formatting.h"
29 #include "ui/gfx/text_elider.h"
31 using base::TimeDelta
;
32 using content::DownloadItem
;
36 // Per DownloadItem data used by DownloadItemModel. The model doesn't keep any
37 // state since there could be multiple models associated with a single
38 // DownloadItem, and the lifetime of the model is shorter than the DownloadItem.
39 class DownloadItemModelData
: public base::SupportsUserData::Data
{
41 // Get the DownloadItemModelData object for |download|. Returns NULL if
42 // there's no model data.
43 static const DownloadItemModelData
* Get(const DownloadItem
* download
);
45 // Get the DownloadItemModelData object for |download|. Creates a model data
46 // object if not found. Always returns a non-NULL pointer, unless OOM.
47 static DownloadItemModelData
* GetOrCreate(DownloadItem
* download
);
49 bool should_show_in_shelf() const { return should_show_in_shelf_
; }
50 void set_should_show_in_shelf(bool should_show_in_shelf
) {
51 should_show_in_shelf_
= should_show_in_shelf
;
54 bool should_notify_ui() const { return should_notify_ui_
; }
55 void set_should_notify_ui(bool should_notify_ui
) {
56 should_notify_ui_
= should_notify_ui
;
59 bool should_prefer_opening_in_browser() const {
60 return should_prefer_opening_in_browser_
;
62 void set_should_prefer_opening_in_browser(bool preference
) {
63 should_prefer_opening_in_browser_
= preference
;
67 DownloadItemModelData();
68 virtual ~DownloadItemModelData() {}
70 static const char kKey
[];
72 // Whether the download should be displayed in the download shelf. True by
74 bool should_show_in_shelf_
;
76 // Whether the UI should be notified when the download is ready to be
78 bool should_notify_ui_
;
80 // Whether the download should be opened in the browser vs. the system handler
82 bool should_prefer_opening_in_browser_
;
86 const char DownloadItemModelData::kKey
[] = "DownloadItemModelData key";
89 const DownloadItemModelData
* DownloadItemModelData::Get(
90 const DownloadItem
* download
) {
91 return static_cast<const DownloadItemModelData
*>(download
->GetUserData(kKey
));
95 DownloadItemModelData
* DownloadItemModelData::GetOrCreate(
96 DownloadItem
* download
) {
97 DownloadItemModelData
* data
=
98 static_cast<DownloadItemModelData
*>(download
->GetUserData(kKey
));
100 data
= new DownloadItemModelData();
101 download
->SetUserData(kKey
, data
);
106 DownloadItemModelData::DownloadItemModelData()
107 : should_show_in_shelf_(true),
108 should_notify_ui_(false),
109 should_prefer_opening_in_browser_(false) {
112 base::string16
InterruptReasonStatusMessage(int reason
) {
113 int string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS
;
115 switch (static_cast<content::DownloadInterruptReason
>(reason
)) {
116 case content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED
:
117 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_ACCESS_DENIED
;
119 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
:
120 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_DISK_FULL
;
122 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG
:
123 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_PATH_TOO_LONG
;
125 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE
:
126 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_LARGE
;
128 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED
:
129 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_VIRUS
;
131 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR
:
132 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_TEMPORARY_PROBLEM
;
134 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED
:
135 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_BLOCKED
;
137 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED
:
138 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_SECURITY_CHECK_FAILED
;
140 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT
:
141 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_SHORT
;
143 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST
:
144 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED
:
145 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_ERROR
;
147 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT
:
148 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_TIMEOUT
;
150 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED
:
151 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_DISCONNECTED
;
153 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN
:
154 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_DOWN
;
156 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED
:
157 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_PROBLEM
;
159 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT
:
160 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_NO_FILE
;
162 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
:
163 string_id
= IDS_DOWNLOAD_STATUS_CANCELLED
;
165 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN
:
166 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_SHUTDOWN
;
168 case content::DOWNLOAD_INTERRUPT_REASON_CRASH
:
169 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS_CRASH
;
171 case content::DOWNLOAD_INTERRUPT_REASON_NONE
:
174 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE
:
175 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION
:
176 case content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED
:
177 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS
;
180 return l10n_util::GetStringUTF16(string_id
);
183 base::string16
InterruptReasonMessage(int reason
) {
184 int string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS
;
185 base::string16 status_text
;
187 switch (static_cast<content::DownloadInterruptReason
>(reason
)) {
188 case content::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED
:
189 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_ACCESS_DENIED
;
191 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
:
192 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_DISK_FULL
;
194 case content::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG
:
195 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_PATH_TOO_LONG
;
197 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE
:
198 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_LARGE
;
200 case content::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED
:
201 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_VIRUS
;
203 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR
:
204 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_TEMPORARY_PROBLEM
;
206 case content::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED
:
207 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_BLOCKED
;
209 case content::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED
:
210 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SECURITY_CHECK_FAILED
;
212 case content::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT
:
213 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_SHORT
;
215 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST
:
216 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED
:
217 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_ERROR
;
219 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT
:
220 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_TIMEOUT
;
222 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED
:
223 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_DISCONNECTED
;
225 case content::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN
:
226 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_DOWN
;
228 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED
:
229 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_PROBLEM
;
231 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT
:
232 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NO_FILE
;
234 case content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
:
235 string_id
= IDS_DOWNLOAD_STATUS_CANCELLED
;
237 case content::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN
:
238 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SHUTDOWN
;
240 case content::DOWNLOAD_INTERRUPT_REASON_CRASH
:
241 string_id
= IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_CRASH
;
243 case content::DOWNLOAD_INTERRUPT_REASON_NONE
:
246 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE
:
247 case content::DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION
:
248 case content::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED
:
249 string_id
= IDS_DOWNLOAD_INTERRUPTED_STATUS
;
252 status_text
= l10n_util::GetStringUTF16(string_id
);
259 // -----------------------------------------------------------------------------
262 DownloadItemModel::DownloadItemModel(DownloadItem
* download
)
263 : download_(download
) {}
265 DownloadItemModel::~DownloadItemModel() {}
267 base::string16
DownloadItemModel::GetInterruptReasonText() const {
268 if (download_
->GetState() != DownloadItem::INTERRUPTED
||
269 download_
->GetLastReason() ==
270 content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
) {
271 return base::string16();
273 return InterruptReasonMessage(download_
->GetLastReason());
276 base::string16
DownloadItemModel::GetStatusText() const {
277 base::string16 status_text
;
278 switch (download_
->GetState()) {
279 case DownloadItem::IN_PROGRESS
:
280 status_text
= GetInProgressStatusString();
282 case DownloadItem::COMPLETE
:
283 if (download_
->GetFileExternallyRemoved()) {
284 status_text
= l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_REMOVED
);
289 case DownloadItem::CANCELLED
:
290 status_text
= l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED
);
292 case DownloadItem::INTERRUPTED
: {
293 content::DownloadInterruptReason reason
= download_
->GetLastReason();
294 if (reason
!= content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
) {
295 base::string16 interrupt_reason
= InterruptReasonStatusMessage(reason
);
296 status_text
= l10n_util::GetStringFUTF16(
297 IDS_DOWNLOAD_STATUS_INTERRUPTED
, interrupt_reason
);
299 // Same as DownloadItem::CANCELLED.
300 status_text
= l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED
);
311 base::string16
DownloadItemModel::GetTabProgressStatusText() const {
312 int64 total
= GetTotalBytes();
313 int64 size
= download_
->GetReceivedBytes();
314 base::string16 received_size
= ui::FormatBytes(size
);
315 base::string16 amount
= received_size
;
317 // Adjust both strings for the locale direction since we don't yet know which
318 // string we'll end up using for constructing the final progress string.
319 base::i18n::AdjustStringForLocaleDirection(&amount
);
322 base::string16 total_text
= ui::FormatBytes(total
);
323 base::i18n::AdjustStringForLocaleDirection(&total_text
);
325 base::i18n::AdjustStringForLocaleDirection(&received_size
);
326 amount
= l10n_util::GetStringFUTF16(
327 IDS_DOWNLOAD_TAB_PROGRESS_SIZE
, received_size
, total_text
);
329 amount
.assign(received_size
);
331 int64 current_speed
= download_
->CurrentSpeed();
332 base::string16 speed_text
= ui::FormatSpeed(current_speed
);
333 base::i18n::AdjustStringForLocaleDirection(&speed_text
);
335 base::TimeDelta remaining
;
336 base::string16 time_remaining
;
337 if (download_
->IsPaused()) {
338 time_remaining
= l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED
);
339 } else if (download_
->TimeRemaining(&remaining
)) {
340 time_remaining
= ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING
,
341 ui::TimeFormat::LENGTH_SHORT
,
345 if (time_remaining
.empty()) {
346 base::i18n::AdjustStringForLocaleDirection(&amount
);
347 return l10n_util::GetStringFUTF16(
348 IDS_DOWNLOAD_TAB_PROGRESS_STATUS_TIME_UNKNOWN
, speed_text
, amount
);
350 return l10n_util::GetStringFUTF16(
351 IDS_DOWNLOAD_TAB_PROGRESS_STATUS
, speed_text
, amount
, time_remaining
);
354 base::string16
DownloadItemModel::GetTooltipText(const gfx::FontList
& font_list
,
355 int max_width
) const {
356 base::string16 tooltip
= gfx::ElideFilename(
357 download_
->GetFileNameToReportUser(), font_list
, max_width
);
358 content::DownloadInterruptReason reason
= download_
->GetLastReason();
359 if (download_
->GetState() == DownloadItem::INTERRUPTED
&&
360 reason
!= content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
) {
361 tooltip
+= base::ASCIIToUTF16("\n");
362 tooltip
+= gfx::ElideText(InterruptReasonStatusMessage(reason
),
363 font_list
, max_width
, gfx::ELIDE_AT_END
);
368 base::string16
DownloadItemModel::GetWarningText(const gfx::FontList
& font_list
,
369 int base_width
) const {
370 // Should only be called if IsDangerous().
371 DCHECK(IsDangerous());
372 base::string16 elided_filename
=
373 gfx::ElideFilename(download_
->GetFileNameToReportUser(), font_list
,
375 switch (download_
->GetDangerType()) {
376 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
: {
377 return l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL
);
379 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
: {
380 if (download_crx_util::IsExtensionDownload(*download_
)) {
381 return l10n_util::GetStringUTF16(
382 IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION
);
384 return l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD
,
388 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT
:
389 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST
: {
390 return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT
,
393 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT
: {
394 return l10n_util::GetStringFUTF16(IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT
,
397 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED
: {
398 return l10n_util::GetStringFUTF16(
399 IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS
, elided_filename
);
401 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
:
402 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT
:
403 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED
:
404 case content::DOWNLOAD_DANGER_TYPE_MAX
: {
409 return base::string16();
412 base::string16
DownloadItemModel::GetWarningConfirmButtonText() const {
413 // Should only be called if IsDangerous()
414 DCHECK(IsDangerous());
415 if (download_
->GetDangerType() ==
416 content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
&&
417 download_crx_util::IsExtensionDownload(*download_
)) {
418 return l10n_util::GetStringUTF16(IDS_CONTINUE_EXTENSION_DOWNLOAD
);
420 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD
);
424 int64
DownloadItemModel::GetCompletedBytes() const {
425 return download_
->GetReceivedBytes();
428 int64
DownloadItemModel::GetTotalBytes() const {
429 return download_
->AllDataSaved() ? download_
->GetReceivedBytes() :
430 download_
->GetTotalBytes();
433 // TODO(asanka,rdsmith): Once 'open' moves exclusively to the
434 // ChromeDownloadManagerDelegate, we should calculate the percentage here
435 // instead of calling into the DownloadItem.
436 int DownloadItemModel::PercentComplete() const {
437 return download_
->PercentComplete();
440 bool DownloadItemModel::IsDangerous() const {
441 return download_
->IsDangerous();
444 bool DownloadItemModel::MightBeMalicious() const {
447 switch (download_
->GetDangerType()) {
448 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
:
449 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT
:
450 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT
:
451 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST
:
452 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED
:
455 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
:
456 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT
:
457 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED
:
458 case content::DOWNLOAD_DANGER_TYPE_MAX
:
459 // We shouldn't get any of these due to the IsDangerous() test above.
462 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
:
469 // If you change this definition of malicious, also update
470 // DownloadManagerImpl::NonMaliciousInProgressCount.
471 bool DownloadItemModel::IsMalicious() const {
472 if (!MightBeMalicious())
474 switch (download_
->GetDangerType()) {
475 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL
:
476 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT
:
477 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST
:
478 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED
:
481 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
:
482 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT
:
483 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED
:
484 case content::DOWNLOAD_DANGER_TYPE_MAX
:
485 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE
:
486 // We shouldn't get any of these due to the MightBeMalicious() test above.
489 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT
:
496 bool DownloadItemModel::ShouldAllowDownloadFeedback() const {
497 #if defined(FULL_SAFE_BROWSING)
500 return safe_browsing::DownloadFeedbackService::IsEnabledForDownload(
507 bool DownloadItemModel::ShouldRemoveFromShelfWhenComplete() const {
508 switch (download_
->GetState()) {
509 case DownloadItem::IN_PROGRESS
:
510 // If the download is dangerous or malicious, we should display a warning
511 // on the shelf until the user accepts the download.
515 // If the download is an extension, temporary, or will be opened
516 // automatically, then it should be removed from the shelf on completion.
517 // TODO(asanka): The logic for deciding opening behavior should be in a
518 // central location. http://crbug.com/167702
519 return (download_crx_util::IsExtensionDownload(*download_
) ||
520 download_
->IsTemporary() ||
521 download_
->GetOpenWhenComplete() ||
522 download_
->ShouldOpenFileBasedOnExtension());
524 case DownloadItem::COMPLETE
:
525 // If the download completed, then rely on GetAutoOpened() to check for
526 // opening behavior. This should accurately reflect whether the download
527 // was successfully opened. Extensions, for example, may fail to open.
528 return download_
->GetAutoOpened() || download_
->IsTemporary();
530 case DownloadItem::CANCELLED
:
531 case DownloadItem::INTERRUPTED
:
532 // Interrupted or cancelled downloads should remain on the shelf.
535 case DownloadItem::MAX_DOWNLOAD_STATE
:
543 bool DownloadItemModel::ShouldShowDownloadStartedAnimation() const {
544 return !download_
->IsSavePackageDownload() &&
545 !download_crx_util::IsExtensionDownload(*download_
);
548 bool DownloadItemModel::ShouldShowInShelf() const {
549 const DownloadItemModelData
* data
= DownloadItemModelData::Get(download_
);
550 return !data
|| data
->should_show_in_shelf();
553 void DownloadItemModel::SetShouldShowInShelf(bool should_show
) {
554 DownloadItemModelData
* data
= DownloadItemModelData::GetOrCreate(download_
);
555 data
->set_should_show_in_shelf(should_show
);
558 bool DownloadItemModel::ShouldNotifyUI() const {
559 const DownloadItemModelData
* data
= DownloadItemModelData::Get(download_
);
560 return data
&& data
->should_notify_ui();
563 void DownloadItemModel::SetShouldNotifyUI(bool should_notify
) {
564 DownloadItemModelData
* data
= DownloadItemModelData::GetOrCreate(download_
);
565 data
->set_should_notify_ui(should_notify
);
568 bool DownloadItemModel::ShouldPreferOpeningInBrowser() const {
569 const DownloadItemModelData
* data
= DownloadItemModelData::Get(download_
);
570 return data
&& data
->should_prefer_opening_in_browser();
573 void DownloadItemModel::SetShouldPreferOpeningInBrowser(bool preference
) {
574 DownloadItemModelData
* data
= DownloadItemModelData::GetOrCreate(download_
);
575 data
->set_should_prefer_opening_in_browser(preference
);
578 base::string16
DownloadItemModel::GetProgressSizesString() const {
579 base::string16 size_ratio
;
580 int64 size
= GetCompletedBytes();
581 int64 total
= GetTotalBytes();
583 ui::DataUnits amount_units
= ui::GetByteDisplayUnits(total
);
584 base::string16 simple_size
= ui::FormatBytesWithUnits(size
, amount_units
, false);
586 // In RTL locales, we render the text "size/total" in an RTL context. This
587 // is problematic since a string such as "123/456 MB" is displayed
588 // as "MB 123/456" because it ends with an LTR run. In order to solve this,
589 // we mark the total string as an LTR string if the UI layout is
590 // right-to-left so that the string "456 MB" is treated as an LTR run.
591 base::string16 simple_total
= base::i18n::GetDisplayStringInLTRDirectionality(
592 ui::FormatBytesWithUnits(total
, amount_units
, true));
593 size_ratio
= l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_SIZES
,
594 simple_size
, simple_total
);
596 size_ratio
= ui::FormatBytes(size
);
601 base::string16
DownloadItemModel::GetInProgressStatusString() const {
602 DCHECK_EQ(DownloadItem::IN_PROGRESS
, download_
->GetState());
604 TimeDelta time_remaining
;
605 // time_remaining is only known if the download isn't paused.
606 bool time_remaining_known
= (!download_
->IsPaused() &&
607 download_
->TimeRemaining(&time_remaining
));
609 // Indication of progress. (E.g.:"100/200 MB" or "100MB")
610 base::string16 size_ratio
= GetProgressSizesString();
612 // The download is a CRX (app, extension, theme, ...) and it is being unpacked
614 if (download_
->AllDataSaved() &&
615 download_crx_util::IsExtensionDownload(*download_
)) {
616 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CRX_INSTALL_RUNNING
);
619 // A paused download: "100/120 MB, Paused"
620 if (download_
->IsPaused()) {
621 return l10n_util::GetStringFUTF16(
622 IDS_DOWNLOAD_STATUS_IN_PROGRESS
, size_ratio
,
623 l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED
));
626 // A download scheduled to be opened when complete: "Opening in 10 secs"
627 if (download_
->GetOpenWhenComplete()) {
628 if (!time_remaining_known
)
629 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_OPEN_WHEN_COMPLETE
);
631 return l10n_util::GetStringFUTF16(
632 IDS_DOWNLOAD_STATUS_OPEN_IN
,
633 ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION
,
634 ui::TimeFormat::LENGTH_SHORT
, time_remaining
));
637 // In progress download with known time left: "100/120 MB, 10 secs left"
638 if (time_remaining_known
) {
639 return l10n_util::GetStringFUTF16(
640 IDS_DOWNLOAD_STATUS_IN_PROGRESS
, size_ratio
,
641 ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING
,
642 ui::TimeFormat::LENGTH_SHORT
, time_remaining
));
645 // In progress download with no known time left and non-zero completed bytes:
646 // "100/120 MB" or "100 MB"
647 if (GetCompletedBytes() > 0)
650 // Instead of displaying "0 B" we say "Starting..."
651 return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_STARTING
);
654 void DownloadItemModel::OpenUsingPlatformHandler() {
655 DownloadService
* download_service
=
656 DownloadServiceFactory::GetForBrowserContext(
657 download_
->GetBrowserContext());
658 if (!download_service
)
661 ChromeDownloadManagerDelegate
* delegate
=
662 download_service
->GetDownloadManagerDelegate();
665 delegate
->OpenDownloadUsingPlatformHandler(download_
);
666 RecordDownloadOpenMethod(DOWNLOAD_OPEN_METHOD_USER_PLATFORM
);