172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/views/download/download_item_view.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/callback.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_path.h"
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/i18n/break_iterator.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/i18n/rtl.h"
13731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/histogram.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/sys_string_conversions.h"
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/download_item_model.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/download_util.h"
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/themes/theme_service.h"
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/views/download/download_shelf_view.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h"
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "ui/base/accessibility/accessible_view_state.h"
253f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "ui/base/animation/slide_animation.h"
2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h"
2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h"
2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/text/text_elider.h"
2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/canvas_skia.h"
3072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/color_utils.h"
31dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "ui/gfx/image.h"
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "unicode/uchar.h"
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/button/native_button.h"
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/menu/menu_2.h"
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/root_view.h"
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/widget.h"
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeDelta;
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(paulg): These may need to be adjusted when download progress
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//              animation is added, and also possibly to take into account
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//              different screen resolutions.
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kTextWidth = 140;            // Pixels
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kDangerousTextWidth = 200;   // Pixels
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kHorizontalTextPadding = 2;  // Pixels
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kVerticalPadding = 3;        // Pixels
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kVerticalTextSpacer = 2;     // Pixels
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kVerticalTextPadding = 2;    // Pixels
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The maximum number of characters we show in a file name when displaying the
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// dangerous download message.
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kFileNameMaxLength = 20;
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// We add some padding before the left image so that the progress animation icon
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// hides the corners of the left image.
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kLeftPadding = 0;  // Pixels.
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The space between the Save and Discard buttons when prompting for a dangerous
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// download.
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kButtonPadding = 5;  // Pixels.
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The space on the left and right side of the dangerous download label.
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kLabelPadding = 4;  // Pixels.
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const SkColor kFileNameDisabledColor = SkColorSetRGB(171, 192, 212);
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// How long the 'download complete' animation should last for.
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kCompleteAnimationDurationMs = 2500;
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// How long the 'download interrupted' animation should last for.
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic const int kInterruptedAnimationDurationMs = 2500;
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// How long we keep the item disabled after the user clicked it to open the
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// downloaded item.
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kDisabledOnOpenDuration = 3000;
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Darken light-on-dark download status text by 20% before drawing, thus
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// creating a "muted" version of title text for both dark-on-light and
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// light-on-dark themes.
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const double kDownloadItemLuminanceMod = 0.8;
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DownloadShelfContextMenuWin -------------------------------------------------
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass DownloadShelfContextMenuWin : public DownloadShelfContextMenu {
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit DownloadShelfContextMenuWin(BaseDownloadItemModel* model)
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : DownloadShelfContextMenu(model) {
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(model);
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Run(const gfx::Point& point) {
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (download_->IsComplete())
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      menu_.reset(new views::Menu2(GetFinishedMenuModel()));
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      menu_.reset(new views::Menu2(GetInProgressMenuModel()));
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The menu's alignment is determined based on the UI layout.
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    views::Menu2::Alignment alignment;
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (base::i18n::IsRTL())
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      alignment = views::Menu2::ALIGN_TOPRIGHT;
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      alignment = views::Menu2::ALIGN_TOPLEFT;
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    menu_->RunMenuAt(point, alignment);
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This method runs when the caller has been deleted and we should not attempt
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to access |download_|.
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Stop() {
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    download_ = NULL;
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<views::Menu2> menu_;
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DownloadItemView ------------------------------------------------------------
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDownloadItemView::DownloadItemView(DownloadItem* download,
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DownloadShelfView* parent,
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BaseDownloadItemModel* model)
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  : warning_icon_(NULL),
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    download_(download),
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    parent_(parent),
1243f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    status_text_(UTF16ToWide(
1253f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen        l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_STARTING))),
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    show_status_text_(true),
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    body_state_(NORMAL),
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    drop_down_state_(NORMAL),
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    progress_angle_(download_util::kStartAngleDegrees),
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    drop_down_pressed_(false),
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dragging_(false),
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    starting_drag_(false),
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    model_(model),
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    save_button_(NULL),
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    discard_button_(NULL),
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dangerous_download_label_(NULL),
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dangerous_download_label_sized_(false),
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    disabled_while_opening_(false),
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    creation_time_(base::Time::Now()),
1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    ALLOW_THIS_IN_INITIALIZER_LIST(reenable_method_factory_(this)),
1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    deleted_(NULL) {
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(download_);
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  download_->AddObserver(this);
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ResourceBundle &rb = ResourceBundle::GetSharedInstance();
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BodyImageSet normal_body_image_set = {
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_LEFT_TOP),
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE),
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM),
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_CENTER_TOP),
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE),
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM),
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_RIGHT_TOP),
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE),
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM)
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  normal_body_image_set_ = normal_body_image_set;
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DropDownImageSet normal_drop_down_image_set = {
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_MENU_TOP),
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_MENU_MIDDLE),
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_MENU_BOTTOM)
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  normal_drop_down_image_set_ = normal_drop_down_image_set;
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BodyImageSet hot_body_image_set = {
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_LEFT_TOP_H),
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE_H),
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM_H),
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_CENTER_TOP_H),
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE_H),
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM_H),
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_RIGHT_TOP_H),
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_H),
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_H)
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  hot_body_image_set_ = hot_body_image_set;
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DropDownImageSet hot_drop_down_image_set = {
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_MENU_TOP_H),
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_MENU_MIDDLE_H),
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_MENU_BOTTOM_H)
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  hot_drop_down_image_set_ = hot_drop_down_image_set;
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BodyImageSet pushed_body_image_set = {
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_LEFT_TOP_P),
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE_P),
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM_P),
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_CENTER_TOP_P),
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE_P),
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM_P),
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_RIGHT_TOP_P),
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_P),
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_P)
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pushed_body_image_set_ = pushed_body_image_set;
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DropDownImageSet pushed_drop_down_image_set = {
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_MENU_TOP_P),
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_MENU_MIDDLE_P),
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_MENU_BOTTOM_P)
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pushed_drop_down_image_set_ = pushed_drop_down_image_set;
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BodyImageSet dangerous_mode_body_image_set = {
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_LEFT_TOP),
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE),
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM),
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_CENTER_TOP),
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE),
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM),
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_RIGHT_TOP_NO_DD),
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_NO_DD),
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_NO_DD)
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  dangerous_mode_body_image_set_ = dangerous_mode_body_image_set;
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  LoadIcon();
221dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  tooltip_text_ =
222dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      UTF16ToWide(download_->GetFileNameToReportUser().LossyDisplayName());
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  font_ = ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont);
2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  box_height_ = std::max<int>(2 * kVerticalPadding + font_.GetHeight() +
2263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                  kVerticalTextPadding + font_.GetHeight(),
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                              2 * kVerticalPadding +
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  normal_body_image_set_.top_left->height() +
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  normal_body_image_set_.bottom_left->height());
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (download_util::kSmallProgressIconSize > box_height_)
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    box_y_ = (download_util::kSmallProgressIconSize - box_height_) / 2;
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    box_y_ = kVerticalPadding;
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Size size = GetPreferredSize();
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (base::i18n::IsRTL()) {
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Drop down button is glued to the left of the download shelf.
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    drop_down_x_left_ = 0;
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    drop_down_x_right_ = normal_drop_down_image_set_.top->width();
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Drop down button is glued to the right of the download shelf.
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    drop_down_x_left_ =
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        size.width() - normal_drop_down_image_set_.top->width();
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    drop_down_x_right_ = size.width();
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2483f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  body_hover_animation_.reset(new ui::SlideAnimation(this));
2493f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  drop_hover_animation_.reset(new ui::SlideAnimation(this));
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (download->safety_state() == DownloadItem::DANGEROUS) {
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tooltip_text_.clear();
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    body_state_ = DANGEROUS;
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    drop_down_state_ = DANGEROUS;
2553f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    save_button_ = new views::NativeButton(this,
2563f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen        UTF16ToWide(l10n_util::GetStringUTF16(
2573f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen            download->is_extension_install() ?
2583f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen                IDS_CONTINUE_EXTENSION_DOWNLOAD : IDS_SAVE_DOWNLOAD)));
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    save_button_->set_ignore_minimum_size(true);
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    discard_button_ = new views::NativeButton(
2613f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen        this, UTF16ToWide(l10n_util::GetStringUTF16(IDS_DISCARD_DOWNLOAD)));
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    discard_button_->set_ignore_minimum_size(true);
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AddChildView(save_button_);
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AddChildView(discard_button_);
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Ensure the file name is not too long.
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Extract the file extension (if any).
269513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    FilePath filename(download->target_name());
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_LINUX)
271dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    string16 extension = WideToUTF16(base::SysNativeMBToWide(
272dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        filename.Extension()));
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
274dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    string16 extension = filename.Extension();
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Remove leading '.'
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (extension.length() > 0)
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      extension = extension.substr(1);
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_LINUX)
281dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    string16 rootname = WideToUTF16(base::SysNativeMBToWide(
282dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        filename.RemoveExtension().value()));
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
284dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    string16 rootname = filename.RemoveExtension().value();
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Elide giant extensions (this shouldn't currently be hit, but might
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // in future, should we ever notice unsafe giant extensions).
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (extension.length() > kFileNameMaxLength / 2)
29072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      ui::ElideString(extension, kFileNameMaxLength / 2, &extension);
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
292dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // The dangerous download label text and icon are different
293dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // under different cases.
294dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    string16 dangerous_label;
295dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (download->danger_type() == DownloadItem::DANGEROUS_URL) {
296dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // Safebrowsing shows the download URL leads to malicious file.
297dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      warning_icon_ = rb.GetBitmapNamed(IDR_SAFEBROWSING_WARNING);
298dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      dangerous_label =
299dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          l10n_util::GetStringUTF16(IDS_PROMPT_UNSAFE_DOWNLOAD_URL);
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
301dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // The download file has dangerous file type (e.g.: an executable).
302dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      DCHECK(download->danger_type() == DownloadItem::DANGEROUS_FILE);
303dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      warning_icon_ = rb.GetBitmapNamed(IDR_WARNING);
304dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (download->is_extension_install()) {
305dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        dangerous_label =
306dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            l10n_util::GetStringUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION);
307dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      } else {
308dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        ui::ElideString(rootname,
309dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                        kFileNameMaxLength - extension.length(),
310dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                        &rootname);
311dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        string16 filename = rootname + ASCIIToUTF16(".") + extension;
312dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        filename = base::i18n::GetDisplayStringInLTRDirectionality(filename);
313dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        dangerous_label =
314dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD, filename);
315dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
317dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
318dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    dangerous_download_label_ = new views::Label(UTF16ToWide(dangerous_label));
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dangerous_download_label_->SetMultiLine(true);
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dangerous_download_label_->SetHorizontalAlignment(
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        views::Label::ALIGN_LEFT);
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AddChildView(dangerous_download_label_);
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SizeLabelToMinWidth();
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
326731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  UpdateAccessibleName();
327731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  set_accessibility_focusable(true);
328731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Set up our animation.
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StartDownloadProgress();
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDownloadItemView::~DownloadItemView() {
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (context_menu_.get()) {
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    context_menu_->Stop();
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  icon_consumer_.CancelAllRequests();
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StopDownloadProgress();
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  download_->RemoveObserver(this);
3403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (deleted_)
3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    *deleted_ = true;
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Progress animation handlers.
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadItemView::UpdateDownloadProgress() {
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  progress_angle_ = (progress_angle_ +
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     download_util::kUnknownIncrementDegrees) %
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    download_util::kMaxDegrees;
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SchedulePaint();
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadItemView::StartDownloadProgress() {
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (progress_timer_.IsRunning())
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  progress_timer_.Start(
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      TimeDelta::FromMilliseconds(download_util::kProgressRateMs), this,
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      &DownloadItemView::UpdateDownloadProgress);
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadItemView::StopDownloadProgress() {
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  progress_timer_.Stop();
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DownloadItemView::OnExtractIconComplete(IconManager::Handle handle,
366ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                             gfx::Image* icon_bitmap) {
367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (icon_bitmap)
368ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    parent()->SchedulePaint();
369ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
370ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DownloadObserver interface.
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Update the progress graphic on the icon and our text status label
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// to reflect our current bytes downloaded, time remaining.
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadItemView::OnDownloadUpdated(DownloadItem* download) {
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(download == download_);
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (body_state_ == DANGEROUS &&
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      download->safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED) {
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We have been approved.
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ClearDangerousMode();
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3843f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  string16 status_text = model_->GetStatusText();
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (download_->state()) {
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case DownloadItem::IN_PROGRESS:
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      download_->is_paused() ? StopDownloadProgress() : StartDownloadProgress();
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
389ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case DownloadItem::INTERRUPTED:
390ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      StopDownloadProgress();
391ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      complete_animation_.reset(new ui::SlideAnimation(this));
392ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      complete_animation_->SetSlideDuration(kInterruptedAnimationDurationMs);
393ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      complete_animation_->SetTweenType(ui::Tween::LINEAR);
394ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      complete_animation_->Show();
395ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (status_text.empty())
396ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        show_status_text_ = false;
397ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SchedulePaint();
398ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      LoadIcon();
399ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case DownloadItem::COMPLETE:
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (download_->auto_opened()) {
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        parent_->RemoveDownloadView(this);  // This will delete us!
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return;
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      StopDownloadProgress();
4063f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      complete_animation_.reset(new ui::SlideAnimation(this));
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      complete_animation_->SetSlideDuration(kCompleteAnimationDurationMs);
4083f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      complete_animation_->SetTweenType(ui::Tween::LINEAR);
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      complete_animation_->Show();
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (status_text.empty())
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        show_status_text_ = false;
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SchedulePaint();
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LoadIcon();
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case DownloadItem::CANCELLED:
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      StopDownloadProgress();
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LoadIcon();
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case DownloadItem::REMOVING:
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      parent_->RemoveDownloadView(this);  // This will delete us!
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4263f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  status_text_ = UTF16ToWideHack(status_text);
427731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  UpdateAccessibleName();
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We use the parent's (DownloadShelfView's) SchedulePaint, since there
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // are spaces between each DownloadItemView that the parent is responsible
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // for painting.
43272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  parent()->SchedulePaint();
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadItemView::OnDownloadOpened(DownloadItem* download) {
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  disabled_while_opening_ = true;
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SetEnabled(false);
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoop::current()->PostDelayedTask(
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      FROM_HERE,
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      reenable_method_factory_.NewRunnableMethod(&DownloadItemView::Reenable),
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kDisabledOnOpenDuration);
4423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Notify our parent.
4443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  parent_->OpenedDownload(this);
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// View overrides
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// In dangerous mode we have to layout our buttons.
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadItemView::Layout() {
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (IsDangerousMode()) {
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dangerous_download_label_->SetColor(
453ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetThemeProvider()->GetColor(ThemeService::COLOR_BOOKMARK_TEXT));
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int x = kLeftPadding + dangerous_mode_body_image_set_.top_left->width() +
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      warning_icon_->width() + kLabelPadding;
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int y = (height() - dangerous_download_label_->height()) / 2;
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    dangerous_download_label_->SetBounds(x, y,
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         dangerous_download_label_->width(),
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         dangerous_download_label_->height());
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gfx::Size button_size = GetButtonSize();
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    x += dangerous_download_label_->width() + kLabelPadding;
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    y = (height() - button_size.height()) / 2;
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    save_button_->SetBounds(x, y, button_size.width(), button_size.height());
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    x += button_size.width() + kButtonPadding;
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    discard_button_->SetBounds(x, y, button_size.width(), button_size.height());
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
470ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsengfx::Size DownloadItemView::GetPreferredSize() {
471ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int width, height;
472ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
473ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // First, we set the height to the height of two rows or text plus margins.
474ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  height = 2 * kVerticalPadding + 2 * font_.GetHeight() + kVerticalTextPadding;
475ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Then we increase the size if the progress icon doesn't fit.
476ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  height = std::max<int>(height, download_util::kSmallProgressIconSize);
477ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
478ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsDangerousMode()) {
479ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    width = kLeftPadding + dangerous_mode_body_image_set_.top_left->width();
480ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    width += warning_icon_->width() + kLabelPadding;
481ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    width += dangerous_download_label_->width() + kLabelPadding;
482ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    gfx::Size button_size = GetButtonSize();
483ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Make sure the button fits.
484ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    height = std::max<int>(height, 2 * kVerticalPadding + button_size.height());
485ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Then we make sure the warning icon fits.
486ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    height = std::max<int>(height, 2 * kVerticalPadding +
487ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                   warning_icon_->height());
488ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    width += button_size.width() * 2 + kButtonPadding;
489ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    width += dangerous_mode_body_image_set_.top_right->width();
490ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
491ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    width = kLeftPadding + normal_body_image_set_.top_left->width();
492ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    width += download_util::kSmallProgressIconSize;
493ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    width += kTextWidth;
494ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    width += normal_body_image_set_.top_right->width();
495ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    width += normal_drop_down_image_set_.top->width();
496ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
497ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return gfx::Size(width, height);
498ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
499ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
500ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Handle a mouse click and open the context menu if the mouse is
501ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// over the drop-down region.
502ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool DownloadItemView::OnMousePressed(const views::MouseEvent& event) {
503ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Mouse should not activate us in dangerous mode.
504ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsDangerousMode())
505ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return true;
506ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
507ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Stop any completion animation.
508ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (complete_animation_.get() && complete_animation_->is_animating())
509ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    complete_animation_->End();
510ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
511ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  gfx::Point menu_location(event.location());
512ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (event.IsOnlyLeftMouseButton()) {
513ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!InDropDownButtonXCoordinateRange(event.x())) {
514ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SetState(PUSHED, NORMAL);
515ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return true;
516ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
517ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
518ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Anchor the menu below the dropmarker.
519ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    menu_location.SetPoint(base::i18n::IsRTL() ?
520ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                               drop_down_x_right_ : drop_down_x_left_,
521ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                           height());
522ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    drop_down_pressed_ = true;
523ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SetState(NORMAL, PUSHED);
524ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
525ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ShowContextMenu(menu_location, true);
526ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return true;
527ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
528ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
529ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Handle drag (file copy) operations.
530ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool DownloadItemView::OnMouseDragged(const views::MouseEvent& event) {
531ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Mouse should not activate us in dangerous mode.
532ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsDangerousMode())
533ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return true;
534ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
535ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!starting_drag_) {
536ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    starting_drag_ = true;
537ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    drag_start_point_ = event.location();
538ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
539ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (dragging_) {
540ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (download_->IsComplete()) {
541ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      IconManager* im = g_browser_process->icon_manager();
542ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      gfx::Image* icon = im->LookupIcon(download_->GetUserVerifiedFilePath(),
543ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                        IconLoader::SMALL);
544ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (icon) {
545ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        views::Widget* widget = GetWidget();
546ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        download_util::DragDownload(download_, icon,
547ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                    widget ? widget->GetNativeView() : NULL);
548ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
549ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
550ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else if (ExceededDragThreshold(
551ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                 event.location().x() - drag_start_point_.x(),
552ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                 event.location().y() - drag_start_point_.y())) {
553ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    dragging_ = true;
554ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
555ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return true;
556ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
557ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
558ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DownloadItemView::OnMouseReleased(const views::MouseEvent& event) {
559ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Mouse should not activate us in dangerous mode.
560ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsDangerousMode())
561ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
562ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
563ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (event.IsOnlyLeftMouseButton() &&
564ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      !InDropDownButtonXCoordinateRange(event.x())) {
565ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    OpenDownload();
566ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
567ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
568ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SetState(NORMAL, NORMAL);
569ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
570ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
571ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DownloadItemView::OnMouseCaptureLost() {
572ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Mouse should not activate us in dangerous mode.
573ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsDangerousMode())
574ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
575ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
576ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (dragging_) {
577ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Starting a drag results in a MouseCaptureLost.
578ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    dragging_ = false;
579ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    starting_drag_ = false;
580ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
581ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SetState(NORMAL, NORMAL);
582ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
583ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
584ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
585ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DownloadItemView::OnMouseMoved(const views::MouseEvent& event) {
586ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Mouse should not activate us in dangerous mode.
587ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsDangerousMode())
588ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
589ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
590ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool on_body = !InDropDownButtonXCoordinateRange(event.x());
591ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SetState(on_body ? HOT : NORMAL, on_body ? NORMAL : HOT);
592ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (on_body) {
593ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    body_hover_animation_->Show();
594ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    drop_hover_animation_->Hide();
595ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
596ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    body_hover_animation_->Hide();
597ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    drop_hover_animation_->Show();
598ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
599ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
600ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
601ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DownloadItemView::OnMouseExited(const views::MouseEvent& event) {
602ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Mouse should not activate us in dangerous mode.
603ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsDangerousMode())
604ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
605ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
606ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SetState(NORMAL, drop_down_pressed_ ? PUSHED : NORMAL);
607ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  body_hover_animation_->Hide();
608ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  drop_hover_animation_->Hide();
609ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
610ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
611ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool DownloadItemView::OnKeyPressed(const views::KeyEvent& event) {
612ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Key press should not activate us in dangerous mode.
613ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsDangerousMode())
614ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return true;
615ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
616ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (event.key_code() == ui::VKEY_SPACE ||
617ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      event.key_code() == ui::VKEY_RETURN) {
618ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    OpenDownload();
619ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return true;
620ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
621ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return false;
622ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
623ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
624ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool DownloadItemView::GetTooltipText(const gfx::Point& p,
625ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                      std::wstring* tooltip) {
626ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (tooltip_text_.empty())
627ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
628ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
629ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  tooltip->assign(tooltip_text_);
630ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return true;
631ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
632ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
633ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DownloadItemView::ShowContextMenu(const gfx::Point& p,
634ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                       bool is_mouse_gesture) {
635ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  gfx::Point point = p;
636ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
637ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Similar hack as in MenuButton.
638ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We're about to show the menu from a mouse press. By showing from the
639ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // mouse press event we block RootView in mouse dispatching. This also
640ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // appears to cause RootView to get a mouse pressed BEFORE the mouse
641ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // release is seen, which means RootView sends us another mouse press no
642ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // matter where the user pressed. To force RootView to recalculate the
643ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // mouse target during the mouse press we explicitly set the mouse handler
644ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // to NULL.
645ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GetRootView()->SetMouseHandler(NULL);
646ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
647ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If |is_mouse_gesture| is false, |p| is ignored. The menu is shown aligned
648ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // to drop down arrow button.
649ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!is_mouse_gesture) {
650ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    drop_down_pressed_ = true;
651ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SetState(NORMAL, PUSHED);
652ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
653ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    point.set_y(height());
654ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (base::i18n::IsRTL())
655ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      point.set_x(drop_down_x_right_);
656ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    else
657ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      point.set_x(drop_down_x_left_);
658ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
659ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
660ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  views::View::ConvertPointToScreen(this, &point);
661ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
662ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!context_menu_.get())
663ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    context_menu_.reset(new DownloadShelfContextMenuWin(model_.get()));
664ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // When we call the Run method on the menu, it runs an inner message loop
665ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // that might causes us to be deleted.
666ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool deleted = false;
667ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  deleted_ = &deleted;
668ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  context_menu_->Run(point);
669ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (deleted)
670ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;  // We have been deleted! Don't access 'this'.
671ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  deleted_ = NULL;
672ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
673ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If the menu action was to remove the download, this view will also be
674ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // invalid so we must not access 'this' in this case.
675ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (context_menu_->download()) {
676ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    drop_down_pressed_ = false;
677ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Showing the menu blocks. Here we revert the state.
678ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SetState(NORMAL, NORMAL);
679ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
680ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
681ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
682ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DownloadItemView::GetAccessibleState(ui::AccessibleViewState* state) {
683ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  state->name = accessible_name_;
684ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  state->role = ui::AccessibilityTypes::ROLE_PUSHBUTTON;
685ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (download_->safety_state() == DownloadItem::DANGEROUS) {
686ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    state->state = ui::AccessibilityTypes::STATE_UNAVAILABLE;
687ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
688ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    state->state = ui::AccessibilityTypes::STATE_HASPOPUP;
689ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
690ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
691ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadItemView::ButtonPressed(
693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    views::Button* sender, const views::Event& event) {
694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (sender == discard_button_) {
695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UMA_HISTOGRAM_LONG_TIMES("clickjacking.discard_download",
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             base::Time::Now() - creation_time_);
697ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (download_->IsPartialDownload())
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      download_->Cancel(true);
699ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    download_->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD);
700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // WARNING: we are deleted at this point.  Don't access 'this'.
701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (sender == save_button_) {
702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The user has confirmed a dangerous download.  We'd record how quickly the
703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // user did this to detect whether we're being clickjacked.
704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UMA_HISTOGRAM_LONG_TIMES("clickjacking.save_download",
705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             base::Time::Now() - creation_time_);
706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This will change the state and notify us.
7073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    download_->DangerousDownloadValidated();
708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
711ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DownloadItemView::AnimationProgressed(const ui::Animation* animation) {
712ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We don't care if what animation (body button/drop button/complete),
713ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // is calling back, as they all have to go through the same paint call.
714ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SchedulePaint();
715ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
716ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
717dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid DownloadItemView::OnPaint(gfx::Canvas* canvas) {
718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BodyImageSet* body_image_set = NULL;
719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (body_state_) {
720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case NORMAL:
721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case HOT:
722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      body_image_set = &normal_body_image_set_;
723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case PUSHED:
725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      body_image_set = &pushed_body_image_set_;
726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case DANGEROUS:
728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      body_image_set = &dangerous_mode_body_image_set_;
729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DropDownImageSet* drop_down_image_set = NULL;
734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (drop_down_state_) {
735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case NORMAL:
736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case HOT:
737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      drop_down_image_set = &normal_drop_down_image_set_;
738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case PUSHED:
740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      drop_down_image_set = &pushed_drop_down_image_set_;
741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case DANGEROUS:
743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      drop_down_image_set = NULL;  // No drop-down in dangerous mode.
744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int center_width = width() - kLeftPadding -
750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     body_image_set->left->width() -
751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     body_image_set->right->width() -
752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     (drop_down_image_set ?
753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        normal_drop_down_image_set_.center->width() :
754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        0);
755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // May be caused by animation.
757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (center_width <= 0)
758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Draw status before button image to effectively lighten text.
761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!IsDangerousMode()) {
762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (show_status_text_) {
76372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      int mirrored_x = GetMirroredXWithWidthInView(
764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          download_util::kSmallProgressIconSize, kTextWidth);
765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Add font_.height() to compensate for title, which is drawn later.
7663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      int y = box_y_ + kVerticalPadding + font_.GetHeight() +
767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              kVerticalTextPadding;
768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SkColor file_name_color = GetThemeProvider()->GetColor(
769ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          ThemeService::COLOR_BOOKMARK_TEXT);
770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // If text is light-on-dark, lightening it alone will do nothing.
771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Therefore we mute luminance a wee bit before drawing in this case.
772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (color_utils::RelativeLuminance(file_name_color) > 0.5)
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          file_name_color = SkColorSetRGB(
774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              static_cast<int>(kDownloadItemLuminanceMod *
775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               SkColorGetR(file_name_color)),
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              static_cast<int>(kDownloadItemLuminanceMod *
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               SkColorGetG(file_name_color)),
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              static_cast<int>(kDownloadItemLuminanceMod *
779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               SkColorGetB(file_name_color)));
78072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      canvas->DrawStringInt(WideToUTF16Hack(status_text_), font_,
78172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                            file_name_color, mirrored_x, y, kTextWidth,
78272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                            font_.GetHeight());
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Paint the background images.
787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int x = kLeftPadding;
7883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  canvas->Save();
7893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (base::i18n::IsRTL()) {
790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Since we do not have the mirrored images for
791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // (hot_)body_image_set->top_left, (hot_)body_image_set->left,
792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // (hot_)body_image_set->bottom_left, and drop_down_image_set,
793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // for RTL UI, we flip the canvas to draw those images mirrored.
794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Consequently, we do not need to mirror the x-axis of those images.
795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    canvas->TranslateInt(width(), 0);
796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    canvas->ScaleInt(-1, 1);
797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PaintBitmaps(canvas,
799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               body_image_set->top_left, body_image_set->left,
800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               body_image_set->bottom_left,
801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               x, box_y_, box_height_, body_image_set->top_left->width());
802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  x += body_image_set->top_left->width();
803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PaintBitmaps(canvas,
804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               body_image_set->top, body_image_set->center,
805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               body_image_set->bottom,
806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               x, box_y_, box_height_, center_width);
807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  x += center_width;
808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PaintBitmaps(canvas,
809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               body_image_set->top_right, body_image_set->right,
810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               body_image_set->bottom_right,
811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               x, box_y_, box_height_, body_image_set->top_right->width());
812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Overlay our body hot state.
814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (body_hover_animation_->GetCurrentValue() > 0) {
815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    canvas->SaveLayerAlpha(
816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        static_cast<int>(body_hover_animation_->GetCurrentValue() * 255));
817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    canvas->AsCanvasSkia()->drawARGB(0, 255, 255, 255, SkXfermode::kClear_Mode);
818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int x = kLeftPadding;
820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PaintBitmaps(canvas,
821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 hot_body_image_set_.top_left, hot_body_image_set_.left,
822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 hot_body_image_set_.bottom_left,
823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 x, box_y_, box_height_, hot_body_image_set_.top_left->width());
824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    x += body_image_set->top_left->width();
825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PaintBitmaps(canvas,
826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 hot_body_image_set_.top, hot_body_image_set_.center,
827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 hot_body_image_set_.bottom,
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 x, box_y_, box_height_, center_width);
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    x += center_width;
830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PaintBitmaps(canvas,
831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 hot_body_image_set_.top_right, hot_body_image_set_.right,
832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 hot_body_image_set_.bottom_right,
833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 x, box_y_, box_height_,
834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 hot_body_image_set_.top_right->width());
835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    canvas->Restore();
836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  x += body_image_set->top_right->width();
839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Paint the drop-down.
841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (drop_down_image_set) {
842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PaintBitmaps(canvas,
843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 drop_down_image_set->top, drop_down_image_set->center,
844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 drop_down_image_set->bottom,
845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 x, box_y_, box_height_, drop_down_image_set->top->width());
846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Overlay our drop-down hot state.
848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (drop_hover_animation_->GetCurrentValue() > 0) {
849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      canvas->SaveLayerAlpha(
850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          static_cast<int>(drop_hover_animation_->GetCurrentValue() * 255));
851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      canvas->AsCanvasSkia()->drawARGB(0, 255, 255, 255,
852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       SkXfermode::kClear_Mode);
853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      PaintBitmaps(canvas,
855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   drop_down_image_set->top, drop_down_image_set->center,
856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   drop_down_image_set->bottom,
857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   x, box_y_, box_height_, drop_down_image_set->top->width());
858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      canvas->Restore();
860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
8633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Restore the canvas to avoid file name etc. text are drawn flipped.
8643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Consequently, the x-axis of following canvas->DrawXXX() method should be
8653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // mirrored so the text and images are down in the right positions.
8663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  canvas->Restore();
867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Print the text, left aligned and always print the file extension.
869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Last value of x was the end of the right image, just before the button.
870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Note that in dangerous mode we use a label (as the text is multi-line).
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!IsDangerousMode()) {
8723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    string16 filename;
873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!disabled_while_opening_) {
87472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      filename = ui::ElideFilename(download_->GetFileNameToReportUser(),
87572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                   font_, kTextWidth);
876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // First, Calculate the download status opening string width.
8783f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      string16 status_string =
8793f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen          l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_OPENING, string16());
880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int status_string_width = font_.GetStringWidth(status_string);
881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Then, elide the file name.
8823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      string16 filename_string =
88372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          ui::ElideFilename(download_->GetFileNameToReportUser(), font_,
88472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                            kTextWidth - status_string_width);
885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Last, concat the whole string.
8863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      filename = l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_OPENING,
8873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                            filename_string);
888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
89072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int mirrored_x = GetMirroredXWithWidthInView(
891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        download_util::kSmallProgressIconSize, kTextWidth);
892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SkColor file_name_color = GetThemeProvider()->GetColor(
893ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        ThemeService::COLOR_BOOKMARK_TEXT);
8943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    int y =
8953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        box_y_ + (show_status_text_ ? kVerticalPadding :
8963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                      (box_height_ - font_.GetHeight()) / 2);
897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Draw the file's name.
89972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    canvas->DrawStringInt(filename, font_,
900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          IsEnabled() ? file_name_color :
901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        kFileNameDisabledColor,
9023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          mirrored_x, y, kTextWidth, font_.GetHeight());
903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
905dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Load the icon.
906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  IconManager* im = g_browser_process->icon_manager();
907dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  gfx::Image* image = im->LookupIcon(download_->GetUserVerifiedFilePath(),
908dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                     IconLoader::SMALL);
909dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const SkBitmap* icon = NULL;
910dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (IsDangerousMode())
911dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    icon = warning_icon_;
912dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  else if (image)
913dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    icon = *image;
914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We count on the fact that the icon manager will cache the icons and if one
916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // is available, it will be cached here. We *don't* want to request the icon
917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to be loaded here, since this will also get called if the icon can't be
918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // loaded, in which case LookupIcon will always be NULL. The loading will be
919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // triggered only when we think the status might change.
920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (icon) {
921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!IsDangerousMode()) {
922ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (download_->IsInProgress()) {
923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        download_util::PaintDownloadProgress(canvas, this, 0, 0,
924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             progress_angle_,
925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             download_->PercentComplete(),
926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             download_util::SMALL);
927ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      } else if (download_->IsComplete() &&
928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 complete_animation_.get() &&
929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 complete_animation_->is_animating()) {
930ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (download_->IsInterrupted()) {
931ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          download_util::PaintDownloadInterrupted(canvas, this, 0, 0,
932ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              complete_animation_->GetCurrentValue(),
933ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              download_util::SMALL);
934ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        } else {
935ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          download_util::PaintDownloadComplete(canvas, this, 0, 0,
936ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              complete_animation_->GetCurrentValue(),
937ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              download_util::SMALL);
938ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        }
939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Draw the icon image.
94372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int mirrored_x = GetMirroredXWithWidthInView(
944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        download_util::kSmallProgressIconOffset, icon->width());
945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (IsEnabled()) {
946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      canvas->DrawBitmapInt(*icon, mirrored_x,
947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            download_util::kSmallProgressIconOffset);
948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Use an alpha to make the image look disabled.
950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SkPaint paint;
951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      paint.setAlpha(120);
952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      canvas->DrawBitmapInt(*icon, mirrored_x,
953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            download_util::kSmallProgressIconOffset, paint);
954c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
958ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DownloadItemView::OpenDownload() {
959ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We're interested in how long it takes users to open downloads.  If they
960ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // open downloads super quickly, we should be concerned about clickjacking.
961ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  UMA_HISTOGRAM_LONG_TIMES("clickjacking.open_download",
962ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                           base::Time::Now() - creation_time_);
963ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  download_->OpenDownload();
964ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  UpdateAccessibleName();
965ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
966ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
967ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid DownloadItemView::LoadIcon() {
968ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  IconManager* im = g_browser_process->icon_manager();
969ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  im->LoadIcon(download_->GetUserVerifiedFilePath(),
970ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen               IconLoader::SMALL, &icon_consumer_,
971ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen               NewCallback(this, &DownloadItemView::OnExtractIconComplete));
972ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
973ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
974ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Load an icon for the file type we're downloading, and animate any in progress
975ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// download state.
976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadItemView::PaintBitmaps(gfx::Canvas* canvas,
977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    const SkBitmap* top_bitmap,
978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    const SkBitmap* center_bitmap,
979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    const SkBitmap* bottom_bitmap,
980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    int x, int y, int height, int width) {
981c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int middle_height = height - top_bitmap->height() - bottom_bitmap->height();
982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Draw the top.
983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->DrawBitmapInt(*top_bitmap,
984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        0, 0, top_bitmap->width(), top_bitmap->height(),
985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        x, y, width, top_bitmap->height(), false);
986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  y += top_bitmap->height();
987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Draw the center.
988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->DrawBitmapInt(*center_bitmap,
989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        0, 0, center_bitmap->width(), center_bitmap->height(),
990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        x, y, width, middle_height, false);
991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  y += middle_height;
992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Draw the bottom.
993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->DrawBitmapInt(*bottom_bitmap,
994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        0, 0, bottom_bitmap->width(), bottom_bitmap->height(),
995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        x, y, width, bottom_bitmap->height(), false);
996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadItemView::SetState(State body_state, State drop_down_state) {
999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (body_state_ == body_state && drop_down_state_ == drop_down_state)
1000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  body_state_ = body_state;
1003c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  drop_down_state_ = drop_down_state;
1004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SchedulePaint();
1005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadItemView::ClearDangerousMode() {
1008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(download_->safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED &&
1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         body_state_ == DANGEROUS && drop_down_state_ == DANGEROUS);
1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1011c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  body_state_ = NORMAL;
1012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  drop_down_state_ = NORMAL;
1013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Remove the views used by the dangerous mode.
1015c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RemoveChildView(save_button_);
1016c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete save_button_;
1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  save_button_ = NULL;
1018c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RemoveChildView(discard_button_);
1019c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete discard_button_;
1020c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  discard_button_ = NULL;
1021c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RemoveChildView(dangerous_download_label_);
1022c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete dangerous_download_label_;
1023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  dangerous_download_label_ = NULL;
1024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1025731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Set the accessible name back to the status and filename instead of the
1026731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // download warning.
1027731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  UpdateAccessibleName();
1028731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We need to load the icon now that the download_ has the real path.
1030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  LoadIcon();
1031dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  tooltip_text_ =
1032dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      UTF16ToWide(download_->GetFileNameToReportUser().LossyDisplayName());
1033c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1034c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Force the shelf to layout again as our size has changed.
1035c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  parent_->Layout();
1036c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  parent_->SchedulePaint();
1037c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Size DownloadItemView::GetButtonSize() {
1040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(save_button_ && discard_button_);
1041c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Size size;
1042c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1043c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We cache the size when successfully retrieved, not for performance reasons
1044c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // but because if this DownloadItemView is being animated while the tab is
1045c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // not showing, the native buttons are not parented and their preferred size
1046c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // is 0, messing-up the layout.
1047c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (cached_button_size_.width() != 0)
1048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return cached_button_size_;
1049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1050c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size = save_button_->GetMinimumSize();
1051c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Size discard_size = discard_button_->GetMinimumSize();
1052c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1053c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size.SetSize(std::max(size.width(), discard_size.width()),
1054c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               std::max(size.height(), discard_size.height()));
1055c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1056c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (size.width() != 0)
1057c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cached_button_size_ = size;
1058c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1059c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return size;
1060c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1061c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1062c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This method computes the minimum width of the label for displaying its text
1063c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// on 2 lines.  It just breaks the string in 2 lines on the spaces and keeps the
1064c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// configuration with minimum width.
1065c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadItemView::SizeLabelToMinWidth() {
1066c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (dangerous_download_label_sized_)
1067c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1068c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1069c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::wstring text = dangerous_download_label_->GetText();
1070c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TrimWhitespace(text, TRIM_ALL, &text);
1071c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(std::wstring::npos, text.find(L"\n"));
1072c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1073c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make the label big so that GetPreferredSize() is not constrained by the
1074c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // current width.
1075c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  dangerous_download_label_->SetBounds(0, 0, 1000, 1000);
1076c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1077c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Size size;
1078c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int min_width = -1;
1079ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  string16 text16 = WideToUTF16(text);
1080ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Using BREAK_WORD can work in most cases, but it can also break
1081ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // lines where it should not. Using BREAK_LINE is safer although
1082ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // slower for Chinese/Japanese. This is not perf-critical at all, though.
1083ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::BreakIterator iter(&text16, base::BreakIterator::BREAK_LINE);
1084ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool status = iter.Init();
1085ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(status);
1086ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1087ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  string16 current_text = text16;
1088ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  string16 prev_text = text16;
1089ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  while (iter.Advance()) {
1090ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    size_t pos = iter.pos();
1091ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (pos >= text16.length())
1092ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
1093ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // This can be a low surrogate codepoint, but u_isUWhiteSpace will
1094ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // return false and inserting a new line after a surrogate pair
1095ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // is perfectly ok.
1096ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    char16 line_end_char = text16[pos - 1];
1097ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (u_isUWhiteSpace(line_end_char))
1098ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      current_text.replace(pos - 1, 1, 1, char16('\n'));
1099ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    else
1100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      current_text.insert(pos, 1, char16('\n'));
1101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    dangerous_download_label_->SetText(UTF16ToWide(current_text));
1102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    size = dangerous_download_label_->GetPreferredSize();
1103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (min_width == -1)
1105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      min_width = size.width();
1106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If the width is growing again, it means we passed the optimal width spot.
1108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (size.width() > min_width) {
1109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      dangerous_download_label_->SetText(UTF16ToWide(prev_text));
1110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
1111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else {
1112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      min_width = size.width();
1113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
1114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Restore the string.
1116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    prev_text = current_text;
1117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    current_text = text16;
1118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If we have a line with no line breaking opportunity (which is very
1121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // unlikely), we won't cut it.
1122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (min_width == -1)
1123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    size = dangerous_download_label_->GetPreferredSize();
1124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  dangerous_download_label_->SetBounds(0, 0, size.width(), size.height());
1126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  dangerous_download_label_sized_ = true;
1127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadItemView::Reenable() {
1130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  disabled_while_opening_ = false;
1131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SetEnabled(true);  // Triggers a repaint.
1132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool DownloadItemView::InDropDownButtonXCoordinateRange(int x) {
1135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (x > drop_down_x_left_ && x < drop_down_x_right_)
1136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
1137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
1138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1139731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1140731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid DownloadItemView::UpdateAccessibleName() {
114172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  string16 new_name;
1142731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (download_->safety_state() == DownloadItem::DANGEROUS) {
114372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    new_name = WideToUTF16Hack(dangerous_download_label_->GetText());
1144731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else {
114572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    new_name = WideToUTF16Hack(status_text_) + char16(' ') +
1146dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        download_->GetFileNameToReportUser().LossyDisplayName();
1147731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
1148731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If the name has changed, notify assistive technology that the name
1150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // has changed so they can announce it immediately.
1151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (new_name != accessible_name_) {
1152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    accessible_name_ = new_name;
1153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (GetWidget()) {
1154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetWidget()->NotifyAccessibilityEvent(
1155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          this, ui::AccessibilityTypes::EVENT_NAME_CHANGED, true);
1156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
1157731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
1158731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
1159