| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/views/download/download_item_view.h" | 5 #include "chrome/browser/ui/views/download/download_item_view.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/callback.h" | 13 #include "base/callback.h" |
| 14 #include "base/files/file_path.h" | 14 #include "base/files/file_path.h" |
| 15 #include "base/i18n/break_iterator.h" | 15 #include "base/i18n/break_iterator.h" |
| 16 #include "base/i18n/rtl.h" | 16 #include "base/i18n/rtl.h" |
| 17 #include "base/location.h" | 17 #include "base/location.h" |
| 18 #include "base/macros.h" |
| 19 #include "base/memory/ptr_util.h" |
| 18 #include "base/metrics/histogram_macros.h" | 20 #include "base/metrics/histogram_macros.h" |
| 19 #include "base/single_thread_task_runner.h" | 21 #include "base/single_thread_task_runner.h" |
| 20 #include "base/strings/string_util.h" | 22 #include "base/strings/string_util.h" |
| 21 #include "base/strings/stringprintf.h" | 23 #include "base/strings/stringprintf.h" |
| 22 #include "base/strings/sys_string_conversions.h" | 24 #include "base/strings/sys_string_conversions.h" |
| 23 #include "base/strings/utf_string_conversions.h" | 25 #include "base/strings/utf_string_conversions.h" |
| 24 #include "base/threading/thread_task_runner_handle.h" | 26 #include "base/threading/thread_task_runner_handle.h" |
| 25 #include "chrome/browser/browser_process.h" | 27 #include "chrome/browser/browser_process.h" |
| 26 #include "chrome/browser/download/chrome_download_manager_delegate.h" | 28 #include "chrome/browser/download/chrome_download_manager_delegate.h" |
| 27 #include "chrome/browser/download/download_item_model.h" | 29 #include "chrome/browser/download/download_item_model.h" |
| 28 #include "chrome/browser/download/download_stats.h" | 30 #include "chrome/browser/download/download_stats.h" |
| 29 #include "chrome/browser/download/drag_download_item.h" | 31 #include "chrome/browser/download/drag_download_item.h" |
| 30 #include "chrome/browser/extensions/api/experience_sampling_private/experience_s
ampling.h" | 32 #include "chrome/browser/extensions/api/experience_sampling_private/experience_s
ampling.h" |
| 31 #include "chrome/browser/profiles/profile.h" | 33 #include "chrome/browser/profiles/profile.h" |
| 32 #include "chrome/browser/safe_browsing/download_feedback_service.h" | 34 #include "chrome/browser/safe_browsing/download_feedback_service.h" |
| 33 #include "chrome/browser/safe_browsing/download_protection_service.h" | 35 #include "chrome/browser/safe_browsing/download_protection_service.h" |
| 34 #include "chrome/browser/safe_browsing/safe_browsing_service.h" | 36 #include "chrome/browser/safe_browsing/safe_browsing_service.h" |
| 35 #include "chrome/browser/themes/theme_properties.h" | 37 #include "chrome/browser/themes/theme_properties.h" |
| 36 #include "chrome/browser/ui/views/download/download_feedback_dialog_view.h" | 38 #include "chrome/browser/ui/views/download/download_feedback_dialog_view.h" |
| 37 #include "chrome/browser/ui/views/download/download_shelf_context_menu_view.h" | 39 #include "chrome/browser/ui/views/download/download_shelf_context_menu_view.h" |
| 38 #include "chrome/browser/ui/views/download/download_shelf_view.h" | 40 #include "chrome/browser/ui/views/download/download_shelf_view.h" |
| 39 #include "chrome/browser/ui/views/frame/browser_view.h" | 41 #include "chrome/browser/ui/views/frame/browser_view.h" |
| 40 #include "chrome/common/pref_names.h" | 42 #include "chrome/common/pref_names.h" |
| 41 #include "chrome/grit/generated_resources.h" | 43 #include "chrome/grit/generated_resources.h" |
| 42 #include "chrome/grit/theme_resources.h" | |
| 43 #include "components/prefs/pref_service.h" | 44 #include "components/prefs/pref_service.h" |
| 44 #include "content/public/browser/download_danger_type.h" | 45 #include "content/public/browser/download_danger_type.h" |
| 45 #include "third_party/icu/source/common/unicode/uchar.h" | 46 #include "third_party/icu/source/common/unicode/uchar.h" |
| 46 #include "ui/accessibility/ax_view_state.h" | 47 #include "ui/accessibility/ax_view_state.h" |
| 47 #include "ui/base/l10n/l10n_util.h" | 48 #include "ui/base/l10n/l10n_util.h" |
| 49 #include "ui/base/material_design/material_design_controller.h" |
| 48 #include "ui/base/resource/resource_bundle.h" | 50 #include "ui/base/resource/resource_bundle.h" |
| 49 #include "ui/base/theme_provider.h" | 51 #include "ui/base/theme_provider.h" |
| 50 #include "ui/events/event.h" | 52 #include "ui/events/event.h" |
| 51 #include "ui/gfx/animation/slide_animation.h" | 53 #include "ui/gfx/animation/slide_animation.h" |
| 52 #include "ui/gfx/canvas.h" | 54 #include "ui/gfx/canvas.h" |
| 55 #include "ui/gfx/color_palette.h" |
| 53 #include "ui/gfx/color_utils.h" | 56 #include "ui/gfx/color_utils.h" |
| 54 #include "ui/gfx/image/image.h" | 57 #include "ui/gfx/image/image.h" |
| 55 #include "ui/gfx/scoped_canvas.h" | 58 #include "ui/gfx/paint_vector_icon.h" |
| 56 #include "ui/gfx/text_elider.h" | 59 #include "ui/gfx/text_elider.h" |
| 57 #include "ui/gfx/text_utils.h" | 60 #include "ui/gfx/text_utils.h" |
| 58 #include "ui/views/controls/button/label_button.h" | 61 #include "ui/gfx/vector_icons_public.h" |
| 62 #include "ui/views/animation/flood_fill_ink_drop_ripple.h" |
| 63 #include "ui/views/animation/ink_drop_highlight.h" |
| 64 #include "ui/views/border.h" |
| 65 #include "ui/views/controls/button/image_button.h" |
| 66 #include "ui/views/controls/button/md_text_button.h" |
| 67 #include "ui/views/controls/button/vector_icon_button.h" |
| 68 #include "ui/views/controls/focusable_border.h" |
| 59 #include "ui/views/controls/label.h" | 69 #include "ui/views/controls/label.h" |
| 60 #include "ui/views/mouse_constants.h" | 70 #include "ui/views/mouse_constants.h" |
| 61 #include "ui/views/widget/root_view.h" | 71 #include "ui/views/widget/root_view.h" |
| 62 #include "ui/views/widget/widget.h" | 72 #include "ui/views/widget/widget.h" |
| 63 | 73 |
| 64 using content::DownloadItem; | 74 using content::DownloadItem; |
| 65 using extensions::ExperienceSamplingEvent; | 75 using extensions::ExperienceSamplingEvent; |
| 66 | 76 |
| 67 namespace { | 77 namespace { |
| 68 | 78 |
| 69 // TODO(paulg): These may need to be adjusted when download progress | 79 // All values in dp. |
| 70 // animation is added, and also possibly to take into account | 80 const int kTextWidth = 140; |
| 71 // different screen resolutions. | 81 const int kDangerousTextWidth = 200; |
| 72 const int kTextWidth = 140; // Pixels | |
| 73 const int kDangerousTextWidth = 200; // Pixels | |
| 74 const int kVerticalPadding = 3; // Pixels | |
| 75 const int kVerticalTextPadding = 2; // Pixels | |
| 76 const int kTooltipMaxWidth = 800; // Pixels | |
| 77 | 82 |
| 78 // Padding around progress indicator, on all sides. | 83 // The normal height of the item which may be exceeded if text is large. |
| 79 const int kProgressPadding = 7; | 84 const int kDefaultHeight = 48; |
| 80 | 85 |
| 81 // We add some padding before the left image so that the progress animation icon | 86 // The vertical distance between the item's visual upper bound (as delineated by |
| 82 // hides the corners of the left image. | 87 // the separator on the right) and the edge of the shelf. |
| 83 const int kLeftPadding = 0; // Pixels. | 88 const int kTopBottomPadding = 6; |
| 89 |
| 90 // The minimum vertical padding above and below contents of the download item. |
| 91 // This is only used when the text size is large. |
| 92 const int kMinimumVerticalPadding = 2 + kTopBottomPadding; |
| 93 |
| 94 // Vertical padding between filename and status text. |
| 95 const int kVerticalTextPadding = 1; |
| 96 |
| 97 const int kTooltipMaxWidth = 800; |
| 98 |
| 99 // Padding before the icon and at end of the item. |
| 100 const int kStartPadding = 12; |
| 101 const int kEndPadding = 6; |
| 102 |
| 103 // Horizontal padding between progress indicator and filename/status text. |
| 104 const int kProgressTextPadding = 8; |
| 84 | 105 |
| 85 // The space between the Save and Discard buttons when prompting for a dangerous | 106 // The space between the Save and Discard buttons when prompting for a dangerous |
| 86 // download. | 107 // download. |
| 87 const int kButtonPadding = 5; // Pixels. | 108 const int kButtonPadding = 5; |
| 88 | 109 |
| 89 // The space on the left and right side of the dangerous download label. | 110 // The touchable space around the dropdown button's icon. |
| 90 const int kLabelPadding = 4; // Pixels. | 111 const int kDropdownBorderWidth = 10; |
| 91 | 112 |
| 92 const SkColor kFileNameDisabledColor = SkColorSetRGB(171, 192, 212); | 113 // The space on the right side of the dangerous download label. |
| 114 const int kLabelPadding = 8; |
| 115 |
| 116 // Height/width of the warning icon, also in dp. |
| 117 const int kWarningIconSize = 24; |
| 93 | 118 |
| 94 // How long the 'download complete' animation should last for. | 119 // How long the 'download complete' animation should last for. |
| 95 const int kCompleteAnimationDurationMs = 2500; | 120 const int kCompleteAnimationDurationMs = 2500; |
| 96 | 121 |
| 97 // How long the 'download interrupted' animation should last for. | 122 // How long the 'download interrupted' animation should last for. |
| 98 const int kInterruptedAnimationDurationMs = 2500; | 123 const int kInterruptedAnimationDurationMs = 2500; |
| 99 | 124 |
| 100 // How long we keep the item disabled after the user clicked it to open the | 125 // How long we keep the item disabled after the user clicked it to open the |
| 101 // downloaded item. | 126 // downloaded item. |
| 102 const int kDisabledOnOpenDuration = 3000; | 127 const int kDisabledOnOpenDuration = 3000; |
| 103 | 128 |
| 129 // The separator is drawn as a border. It's one dp wide. |
| 130 class SeparatorBorder : public views::FocusableBorder { |
| 131 public: |
| 132 explicit SeparatorBorder(SkColor color) : color_(color) {} |
| 133 ~SeparatorBorder() override {} |
| 134 |
| 135 void Paint(const views::View& view, gfx::Canvas* canvas) override { |
| 136 if (view.HasFocus()) |
| 137 return FocusableBorder::Paint(view, canvas); |
| 138 |
| 139 int end_x = base::i18n::IsRTL() ? 0 : view.width() - 1; |
| 140 canvas->DrawLine(gfx::Point(end_x, kTopBottomPadding), |
| 141 gfx::Point(end_x, view.height() - kTopBottomPadding), |
| 142 color_); |
| 143 } |
| 144 |
| 145 gfx::Insets GetInsets() const override { return gfx::Insets(0, 0, 0, 1); } |
| 146 |
| 147 gfx::Size GetMinimumSize() const override { |
| 148 return gfx::Size(1, 2 * kTopBottomPadding + 1); |
| 149 } |
| 150 |
| 151 private: |
| 152 SkColor color_; |
| 153 |
| 154 DISALLOW_COPY_AND_ASSIGN(SeparatorBorder); |
| 155 }; |
| 156 |
| 104 } // namespace | 157 } // namespace |
| 105 | 158 |
| 159 // Allows the DownloadItemView to control the InkDrop on the drop down button. |
| 160 class DownloadItemView::DropDownButton : public views::VectorIconButton { |
| 161 public: |
| 162 explicit DropDownButton(views::VectorIconButtonDelegate* delegate) |
| 163 : views::VectorIconButton(delegate) {} |
| 164 ~DropDownButton() override {} |
| 165 |
| 166 // Promoted visibility to public. |
| 167 void AnimateInkDrop(views::InkDropState state) { |
| 168 // TODO(bruthig): Plumb in the proper Event. |
| 169 views::VectorIconButton::AnimateInkDrop(state, nullptr /* event */); |
| 170 } |
| 171 |
| 172 private: |
| 173 DISALLOW_COPY_AND_ASSIGN(DropDownButton); |
| 174 }; |
| 175 |
| 106 DownloadItemView::DownloadItemView(DownloadItem* download_item, | 176 DownloadItemView::DownloadItemView(DownloadItem* download_item, |
| 107 DownloadShelfView* parent) | 177 DownloadShelfView* parent) |
| 108 : warning_icon_(NULL), | 178 : shelf_(parent), |
| 109 shelf_(parent), | 179 status_text_(l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_STARTING)), |
| 110 status_text_(l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_STARTING)), | 180 dropdown_state_(NORMAL), |
| 111 body_state_(NORMAL), | 181 mode_(NORMAL_MODE), |
| 112 drop_down_state_(NORMAL), | 182 dragging_(false), |
| 113 mode_(NORMAL_MODE), | 183 starting_drag_(false), |
| 114 drop_down_pressed_(false), | 184 model_(download_item), |
| 115 dragging_(false), | 185 save_button_(nullptr), |
| 116 starting_drag_(false), | 186 discard_button_(nullptr), |
| 117 model_(download_item), | 187 dropdown_button_(new DropDownButton(this)), |
| 118 save_button_(NULL), | 188 dangerous_download_label_(nullptr), |
| 119 discard_button_(NULL), | 189 dangerous_download_label_sized_(false), |
| 120 dangerous_download_label_(NULL), | 190 disabled_while_opening_(false), |
| 121 dangerous_download_label_sized_(false), | 191 creation_time_(base::Time::Now()), |
| 122 disabled_while_opening_(false), | 192 time_download_warning_shown_(base::Time()), |
| 123 creation_time_(base::Time::Now()), | 193 weak_ptr_factory_(this) { |
| 124 time_download_warning_shown_(base::Time()), | 194 SetInkDropMode(InkDropMode::ON); |
| 125 weak_ptr_factory_(this) { | |
| 126 DCHECK(download()); | 195 DCHECK(download()); |
| 196 DCHECK(ui::MaterialDesignController::IsModeMaterial()); |
| 127 download()->AddObserver(this); | 197 download()->AddObserver(this); |
| 128 set_context_menu_controller(this); | 198 set_context_menu_controller(this); |
| 129 | 199 |
| 130 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 200 dropdown_button_->SetBorder( |
| 131 | 201 views::Border::CreateEmptyBorder(gfx::Insets(kDropdownBorderWidth))); |
| 132 BodyImageSet normal_body_image_set = { | 202 dropdown_button_->set_ink_drop_size(gfx::Size(32, 32)); |
| 133 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_LEFT_TOP), | 203 AddChildView(dropdown_button_); |
| 134 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE), | |
| 135 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM), | |
| 136 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_CENTER_TOP), | |
| 137 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE), | |
| 138 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM), | |
| 139 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_RIGHT_TOP), | |
| 140 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE), | |
| 141 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM) | |
| 142 }; | |
| 143 normal_body_image_set_ = normal_body_image_set; | |
| 144 | |
| 145 DropDownImageSet normal_drop_down_image_set = { | |
| 146 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_MENU_TOP), | |
| 147 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_MENU_MIDDLE), | |
| 148 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_MENU_BOTTOM) | |
| 149 }; | |
| 150 normal_drop_down_image_set_ = normal_drop_down_image_set; | |
| 151 | |
| 152 BodyImageSet hot_body_image_set = { | |
| 153 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_LEFT_TOP_H), | |
| 154 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE_H), | |
| 155 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM_H), | |
| 156 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_CENTER_TOP_H), | |
| 157 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE_H), | |
| 158 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM_H), | |
| 159 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_RIGHT_TOP_H), | |
| 160 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_H), | |
| 161 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_H) | |
| 162 }; | |
| 163 hot_body_image_set_ = hot_body_image_set; | |
| 164 | |
| 165 DropDownImageSet hot_drop_down_image_set = { | |
| 166 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_MENU_TOP_H), | |
| 167 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_MENU_MIDDLE_H), | |
| 168 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_MENU_BOTTOM_H) | |
| 169 }; | |
| 170 hot_drop_down_image_set_ = hot_drop_down_image_set; | |
| 171 | |
| 172 BodyImageSet pushed_body_image_set = { | |
| 173 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_LEFT_TOP_P), | |
| 174 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE_P), | |
| 175 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM_P), | |
| 176 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_CENTER_TOP_P), | |
| 177 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE_P), | |
| 178 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM_P), | |
| 179 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_RIGHT_TOP_P), | |
| 180 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_P), | |
| 181 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_P) | |
| 182 }; | |
| 183 pushed_body_image_set_ = pushed_body_image_set; | |
| 184 | |
| 185 DropDownImageSet pushed_drop_down_image_set = { | |
| 186 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_MENU_TOP_P), | |
| 187 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_MENU_MIDDLE_P), | |
| 188 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_MENU_BOTTOM_P) | |
| 189 }; | |
| 190 pushed_drop_down_image_set_ = pushed_drop_down_image_set; | |
| 191 | |
| 192 BodyImageSet dangerous_mode_body_image_set = { | |
| 193 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_LEFT_TOP), | |
| 194 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE), | |
| 195 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM), | |
| 196 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_CENTER_TOP), | |
| 197 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE), | |
| 198 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM), | |
| 199 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_RIGHT_TOP_NO_DD), | |
| 200 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_NO_DD), | |
| 201 rb.GetImageSkiaNamed(IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_NO_DD) | |
| 202 }; | |
| 203 dangerous_mode_body_image_set_ = dangerous_mode_body_image_set; | |
| 204 | |
| 205 malicious_mode_body_image_set_ = normal_body_image_set; | |
| 206 | 204 |
| 207 LoadIcon(); | 205 LoadIcon(); |
| 208 | 206 |
| 209 font_list_ = rb.GetFontList(ui::ResourceBundle::BaseFont); | 207 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| 210 box_height_ = std::max<int>(2 * kVerticalPadding + font_list_.GetHeight() + | 208 font_list_ = |
| 211 kVerticalTextPadding + font_list_.GetHeight(), | 209 rb.GetFontList(ui::ResourceBundle::BaseFont).DeriveWithSizeDelta(1); |
| 212 2 * kVerticalPadding + | 210 status_font_list_ = |
| 213 normal_body_image_set_.top_left->height() + | 211 rb.GetFontList(ui::ResourceBundle::BaseFont).DeriveWithSizeDelta(-2); |
| 214 normal_body_image_set_.bottom_left->height()); | |
| 215 | |
| 216 box_y_ = std::max(0, (2 * kProgressPadding + | |
| 217 DownloadShelf::kProgressIndicatorSize - box_height_) / | |
| 218 2); | |
| 219 | |
| 220 body_hover_animation_.reset(new gfx::SlideAnimation(this)); | |
| 221 drop_hover_animation_.reset(new gfx::SlideAnimation(this)); | |
| 222 | 212 |
| 223 SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); | 213 SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); |
| 224 | 214 |
| 225 OnDownloadUpdated(download()); | 215 OnDownloadUpdated(download()); |
| 226 UpdateDropDownButtonPosition(); | 216 |
| 217 SetDropdownState(NORMAL); |
| 218 UpdateColorsFromTheme(); |
| 227 } | 219 } |
| 228 | 220 |
| 229 DownloadItemView::~DownloadItemView() { | 221 DownloadItemView::~DownloadItemView() { |
| 230 StopDownloadProgress(); | 222 StopDownloadProgress(); |
| 231 download()->RemoveObserver(this); | 223 download()->RemoveObserver(this); |
| 232 | 224 |
| 233 // ExperienceSampling: If the user took no action to remove the warning | 225 // ExperienceSampling: If the user took no action to remove the warning |
| 234 // before it disappeared, then the user effectively dismissed the download | 226 // before it disappeared, then the user effectively dismissed the download |
| 235 // without keeping it. | 227 // without keeping it. |
| 236 if (sampling_event_.get()) | 228 if (sampling_event_.get()) |
| (...skipping 13 matching lines...) Expand all Loading... |
| 250 } | 242 } |
| 251 | 243 |
| 252 void DownloadItemView::StopDownloadProgress() { | 244 void DownloadItemView::StopDownloadProgress() { |
| 253 if (!progress_timer_.IsRunning()) | 245 if (!progress_timer_.IsRunning()) |
| 254 return; | 246 return; |
| 255 previous_progress_elapsed_ += base::TimeTicks::Now() - progress_start_time_; | 247 previous_progress_elapsed_ += base::TimeTicks::Now() - progress_start_time_; |
| 256 progress_start_time_ = base::TimeTicks(); | 248 progress_start_time_ = base::TimeTicks(); |
| 257 progress_timer_.Stop(); | 249 progress_timer_.Stop(); |
| 258 } | 250 } |
| 259 | 251 |
| 252 // static |
| 253 SkColor DownloadItemView::GetTextColorForThemeProvider( |
| 254 const ui::ThemeProvider* theme) { |
| 255 return theme ? theme->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT) |
| 256 : gfx::kPlaceholderColor; |
| 257 } |
| 258 |
| 260 void DownloadItemView::OnExtractIconComplete(gfx::Image* icon_bitmap) { | 259 void DownloadItemView::OnExtractIconComplete(gfx::Image* icon_bitmap) { |
| 261 if (icon_bitmap) | 260 if (icon_bitmap) |
| 262 shelf_->SchedulePaint(); | 261 shelf_->SchedulePaint(); |
| 263 } | 262 } |
| 264 | 263 |
| 265 // DownloadObserver interface. | 264 // DownloadObserver interface. |
| 266 | 265 |
| 267 // Update the progress graphic on the icon and our text status label | 266 // Update the progress graphic on the icon and our text status label |
| 268 // to reflect our current bytes downloaded, time remaining. | 267 // to reflect our current bytes downloaded, time remaining. |
| 269 void DownloadItemView::OnDownloadUpdated(DownloadItem* download_item) { | 268 void DownloadItemView::OnDownloadUpdated(DownloadItem* download_item) { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 338 base::TimeDelta::FromMilliseconds(kDisabledOnOpenDuration)); | 337 base::TimeDelta::FromMilliseconds(kDisabledOnOpenDuration)); |
| 339 | 338 |
| 340 // Notify our parent. | 339 // Notify our parent. |
| 341 shelf_->OpenedDownload(); | 340 shelf_->OpenedDownload(); |
| 342 } | 341 } |
| 343 | 342 |
| 344 // View overrides | 343 // View overrides |
| 345 | 344 |
| 346 // In dangerous mode we have to layout our buttons. | 345 // In dangerous mode we have to layout our buttons. |
| 347 void DownloadItemView::Layout() { | 346 void DownloadItemView::Layout() { |
| 347 UpdateColorsFromTheme(); |
| 348 |
| 348 if (IsShowingWarningDialog()) { | 349 if (IsShowingWarningDialog()) { |
| 349 BodyImageSet* body_image_set = | 350 gfx::Point child_origin( |
| 350 (mode_ == DANGEROUS_MODE) ? &dangerous_mode_body_image_set_ : | 351 kStartPadding + kWarningIconSize + kStartPadding, |
| 351 &malicious_mode_body_image_set_; | 352 (height() - dangerous_download_label_->height()) / 2); |
| 352 int x = kLeftPadding + body_image_set->top_left->width() + | 353 dangerous_download_label_->SetPosition(child_origin); |
| 353 warning_icon_->width() + kLabelPadding; | 354 |
| 354 int y = (height() - dangerous_download_label_->height()) / 2; | 355 child_origin.Offset(dangerous_download_label_->width() + kLabelPadding, 0); |
| 355 dangerous_download_label_->SetBounds(x, y, | |
| 356 dangerous_download_label_->width(), | |
| 357 dangerous_download_label_->height()); | |
| 358 gfx::Size button_size = GetButtonSize(); | 356 gfx::Size button_size = GetButtonSize(); |
| 359 x += dangerous_download_label_->width() + kLabelPadding; | 357 child_origin.set_y((height() - button_size.height()) / 2); |
| 360 y = (height() - button_size.height()) / 2; | |
| 361 if (save_button_) { | 358 if (save_button_) { |
| 362 save_button_->SetBounds(x, y, button_size.width(), button_size.height()); | 359 save_button_->SetBoundsRect(gfx::Rect(child_origin, button_size)); |
| 363 x += button_size.width() + kButtonPadding; | 360 child_origin.Offset(button_size.width() + kButtonPadding, 0); |
| 364 } | 361 } |
| 365 discard_button_->SetBounds(x, y, button_size.width(), button_size.height()); | 362 discard_button_->SetBoundsRect(gfx::Rect(child_origin, button_size)); |
| 366 UpdateColorsFromTheme(); | 363 } |
| 364 |
| 365 if (mode_ != DANGEROUS_MODE) { |
| 366 dropdown_button_->SizeToPreferredSize(); |
| 367 dropdown_button_->SetPosition( |
| 368 gfx::Point(width() - dropdown_button_->width() - kEndPadding, |
| 369 (height() - dropdown_button_->height()) / 2)); |
| 367 } | 370 } |
| 368 } | 371 } |
| 369 | 372 |
| 370 gfx::Size DownloadItemView::GetPreferredSize() const { | 373 gfx::Size DownloadItemView::GetPreferredSize() const { |
| 371 int width, height; | 374 int width = 0; |
| 372 | 375 // We set the height to the height of two rows or text plus margins. |
| 373 // First, we set the height to the height of two rows or text plus margins. | 376 int child_height = font_list_.GetBaseline() + kVerticalTextPadding + |
| 374 height = 2 * kVerticalPadding + 2 * font_list_.GetHeight() + | 377 status_font_list_.GetHeight(); |
| 375 kVerticalTextPadding; | |
| 376 // Then we increase the size if the progress icon doesn't fit. | |
| 377 height = std::max<int>( | |
| 378 height, DownloadShelf::kProgressIndicatorSize + 2 * kProgressPadding); | |
| 379 | 378 |
| 380 if (IsShowingWarningDialog()) { | 379 if (IsShowingWarningDialog()) { |
| 381 const BodyImageSet* body_image_set = | 380 // Width. |
| 382 (mode_ == DANGEROUS_MODE) ? &dangerous_mode_body_image_set_ : | 381 width = kStartPadding + kWarningIconSize + kStartPadding + |
| 383 &malicious_mode_body_image_set_; | 382 dangerous_download_label_->width() + kLabelPadding; |
| 384 width = kLeftPadding + body_image_set->top_left->width(); | |
| 385 width += warning_icon_->width() + kLabelPadding; | |
| 386 width += dangerous_download_label_->width() + kLabelPadding; | |
| 387 gfx::Size button_size = GetButtonSize(); | 383 gfx::Size button_size = GetButtonSize(); |
| 388 // Make sure the button fits. | |
| 389 height = std::max<int>(height, 2 * kVerticalPadding + button_size.height()); | |
| 390 // Then we make sure the warning icon fits. | |
| 391 height = std::max<int>(height, 2 * kVerticalPadding + | |
| 392 warning_icon_->height()); | |
| 393 if (save_button_) | 384 if (save_button_) |
| 394 width += button_size.width() + kButtonPadding; | 385 width += button_size.width() + kButtonPadding; |
| 395 width += button_size.width(); | 386 width += button_size.width() + kEndPadding; |
| 396 width += body_image_set->top_right->width(); | 387 |
| 397 if (mode_ == MALICIOUS_MODE) | 388 // Height: make sure the button fits and the warning icon fits. |
| 398 width += normal_drop_down_image_set_.top->width(); | 389 child_height = |
| 390 std::max({child_height, button_size.height(), kWarningIconSize}); |
| 399 } else { | 391 } else { |
| 400 width = kLeftPadding + normal_body_image_set_.top_left->width(); | 392 width = kStartPadding + DownloadShelf::kProgressIndicatorSize + |
| 401 width += DownloadShelf::kProgressIndicatorSize + 2 * kProgressPadding; | 393 kProgressTextPadding + kTextWidth + kEndPadding; |
| 402 width += kTextWidth; | |
| 403 width += normal_body_image_set_.top_right->width(); | |
| 404 width += normal_drop_down_image_set_.top->width(); | |
| 405 } | 394 } |
| 406 return gfx::Size(width, height); | 395 |
| 396 if (mode_ != DANGEROUS_MODE) |
| 397 width += dropdown_button_->GetPreferredSize().width(); |
| 398 |
| 399 return gfx::Size(width, std::max(kDefaultHeight, |
| 400 2 * kMinimumVerticalPadding + child_height)); |
| 407 } | 401 } |
| 408 | 402 |
| 409 // Handle a mouse click and open the context menu if the mouse is | |
| 410 // over the drop-down region. | |
| 411 bool DownloadItemView::OnMousePressed(const ui::MouseEvent& event) { | 403 bool DownloadItemView::OnMousePressed(const ui::MouseEvent& event) { |
| 412 HandlePressEvent(event, event.IsOnlyLeftMouseButton()); | 404 HandlePressEvent(event, event.IsOnlyLeftMouseButton()); |
| 413 return true; | 405 return true; |
| 414 } | 406 } |
| 415 | 407 |
| 416 // Handle drag (file copy) operations. | 408 // Handle drag (file copy) operations. |
| 417 bool DownloadItemView::OnMouseDragged(const ui::MouseEvent& event) { | 409 bool DownloadItemView::OnMouseDragged(const ui::MouseEvent& event) { |
| 418 // Mouse should not activate us in dangerous mode. | 410 // Mouse should not activate us in dangerous mode. |
| 419 if (IsShowingWarningDialog()) | 411 if (IsShowingWarningDialog()) |
| 420 return true; | 412 return true; |
| 421 | 413 |
| 422 if (!starting_drag_) { | 414 if (!starting_drag_) { |
| 423 starting_drag_ = true; | 415 starting_drag_ = true; |
| 424 drag_start_point_ = event.location(); | 416 drag_start_point_ = event.location(); |
| 417 AnimateInkDrop(views::InkDropState::HIDDEN, &event); |
| 425 } | 418 } |
| 426 if (dragging_) { | 419 if (dragging_) { |
| 427 if (download()->GetState() == DownloadItem::COMPLETE) { | 420 if (download()->GetState() == DownloadItem::COMPLETE) { |
| 428 IconManager* im = g_browser_process->icon_manager(); | 421 IconManager* im = g_browser_process->icon_manager(); |
| 429 gfx::Image* icon = im->LookupIconFromFilepath( | 422 gfx::Image* icon = im->LookupIconFromFilepath( |
| 430 download()->GetTargetFilePath(), IconLoader::SMALL); | 423 download()->GetTargetFilePath(), IconLoader::SMALL); |
| 431 views::Widget* widget = GetWidget(); | 424 views::Widget* widget = GetWidget(); |
| 432 DragDownloadItem( | 425 DragDownloadItem(download(), icon, |
| 433 download(), icon, widget ? widget->GetNativeView() : NULL); | 426 widget ? widget->GetNativeView() : NULL); |
| 434 } | 427 } |
| 435 } else if (ExceededDragThreshold(event.location() - drag_start_point_)) { | 428 } else if (ExceededDragThreshold(event.location() - drag_start_point_)) { |
| 436 dragging_ = true; | 429 dragging_ = true; |
| 437 } | 430 } |
| 438 return true; | 431 return true; |
| 439 } | 432 } |
| 440 | 433 |
| 441 void DownloadItemView::OnMouseReleased(const ui::MouseEvent& event) { | 434 void DownloadItemView::OnMouseReleased(const ui::MouseEvent& event) { |
| 442 HandleClickEvent(event, event.IsOnlyLeftMouseButton()); | 435 HandleClickEvent(event, event.IsOnlyLeftMouseButton()); |
| 443 } | 436 } |
| 444 | 437 |
| 445 void DownloadItemView::OnMouseCaptureLost() { | 438 void DownloadItemView::OnMouseCaptureLost() { |
| 446 // Mouse should not activate us in dangerous mode. | 439 // Mouse should not activate us in dangerous mode. |
| 447 if (mode_ == DANGEROUS_MODE) | 440 if (mode_ != NORMAL_MODE) |
| 448 return; | 441 return; |
| 449 | 442 |
| 450 if (dragging_) { | 443 if (dragging_) { |
| 451 // Starting a drag results in a MouseCaptureLost. | 444 // Starting a drag results in a MouseCaptureLost. |
| 452 dragging_ = false; | 445 dragging_ = false; |
| 453 starting_drag_ = false; | 446 starting_drag_ = false; |
| 454 } | 447 } |
| 455 SetState(NORMAL, NORMAL); | |
| 456 } | |
| 457 | |
| 458 void DownloadItemView::OnMouseMoved(const ui::MouseEvent& event) { | |
| 459 // Mouse should not activate us in dangerous mode. | |
| 460 if (mode_ == DANGEROUS_MODE) | |
| 461 return; | |
| 462 | |
| 463 bool on_body = !InDropDownButtonXCoordinateRange(event.x()); | |
| 464 SetState(on_body ? HOT : NORMAL, on_body ? NORMAL : HOT); | |
| 465 } | |
| 466 | |
| 467 void DownloadItemView::OnMouseExited(const ui::MouseEvent& event) { | |
| 468 // Mouse should not activate us in dangerous mode. | |
| 469 if (mode_ == DANGEROUS_MODE) | |
| 470 return; | |
| 471 | |
| 472 SetState(NORMAL, drop_down_pressed_ ? PUSHED : NORMAL); | |
| 473 } | 448 } |
| 474 | 449 |
| 475 bool DownloadItemView::OnKeyPressed(const ui::KeyEvent& event) { | 450 bool DownloadItemView::OnKeyPressed(const ui::KeyEvent& event) { |
| 476 // Key press should not activate us in dangerous mode. | 451 // Key press should not activate us in dangerous mode. |
| 477 if (IsShowingWarningDialog()) | 452 if (IsShowingWarningDialog()) |
| 478 return true; | 453 return true; |
| 479 | 454 |
| 480 if (event.key_code() == ui::VKEY_SPACE || | 455 if (event.key_code() == ui::VKEY_SPACE || |
| 481 event.key_code() == ui::VKEY_RETURN) { | 456 event.key_code() == ui::VKEY_RETURN) { |
| 457 AnimateInkDrop(views::InkDropState::ACTION_TRIGGERED, nullptr /* &event */); |
| 482 // OpenDownload may delete this, so don't add any code after this line. | 458 // OpenDownload may delete this, so don't add any code after this line. |
| 483 OpenDownload(); | 459 OpenDownload(); |
| 484 return true; | 460 return true; |
| 485 } | 461 } |
| 486 return false; | 462 return false; |
| 487 } | 463 } |
| 488 | 464 |
| 489 bool DownloadItemView::GetTooltipText(const gfx::Point& p, | 465 bool DownloadItemView::GetTooltipText(const gfx::Point& p, |
| 490 base::string16* tooltip) const { | 466 base::string16* tooltip) const { |
| 491 if (IsShowingWarningDialog()) { | 467 if (IsShowingWarningDialog()) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 502 state->name = accessible_name_; | 478 state->name = accessible_name_; |
| 503 state->role = ui::AX_ROLE_BUTTON; | 479 state->role = ui::AX_ROLE_BUTTON; |
| 504 if (model_.IsDangerous()) | 480 if (model_.IsDangerous()) |
| 505 state->AddStateFlag(ui::AX_STATE_DISABLED); | 481 state->AddStateFlag(ui::AX_STATE_DISABLED); |
| 506 else | 482 else |
| 507 state->AddStateFlag(ui::AX_STATE_HASPOPUP); | 483 state->AddStateFlag(ui::AX_STATE_HASPOPUP); |
| 508 } | 484 } |
| 509 | 485 |
| 510 void DownloadItemView::OnThemeChanged() { | 486 void DownloadItemView::OnThemeChanged() { |
| 511 UpdateColorsFromTheme(); | 487 UpdateColorsFromTheme(); |
| 488 SchedulePaint(); |
| 489 } |
| 490 |
| 491 void DownloadItemView::AddInkDropLayer(ui::Layer* ink_drop_layer) { |
| 492 InkDropHostView::AddInkDropLayer(ink_drop_layer); |
| 493 // The layer that's added to host the ink drop layer must mask to bounds |
| 494 // so the hover effect is clipped while animating open. |
| 495 layer()->SetMasksToBounds(true); |
| 496 } |
| 497 |
| 498 std::unique_ptr<views::InkDropRipple> DownloadItemView::CreateInkDropRipple() |
| 499 const { |
| 500 return base::MakeUnique<views::FloodFillInkDropRipple>( |
| 501 GetLocalBounds(), GetInkDropCenterBasedOnLastEvent(), |
| 502 color_utils::DeriveDefaultIconColor(GetTextColor()), |
| 503 ink_drop_visible_opacity()); |
| 504 } |
| 505 |
| 506 std::unique_ptr<views::InkDropHighlight> |
| 507 DownloadItemView::CreateInkDropHighlight() const { |
| 508 if (IsShowingWarningDialog()) |
| 509 return nullptr; |
| 510 |
| 511 gfx::Size size = GetPreferredSize(); |
| 512 return base::MakeUnique<views::InkDropHighlight>( |
| 513 size, kInkDropSmallCornerRadius, |
| 514 gfx::RectF(gfx::SizeF(size)).CenterPoint(), |
| 515 color_utils::DeriveDefaultIconColor(GetTextColor())); |
| 512 } | 516 } |
| 513 | 517 |
| 514 void DownloadItemView::OnGestureEvent(ui::GestureEvent* event) { | 518 void DownloadItemView::OnGestureEvent(ui::GestureEvent* event) { |
| 515 if (event->type() == ui::ET_GESTURE_TAP_DOWN) { | 519 if (event->type() == ui::ET_GESTURE_TAP_DOWN) { |
| 516 HandlePressEvent(*event, true); | 520 HandlePressEvent(*event, true); |
| 517 event->SetHandled(); | 521 event->SetHandled(); |
| 518 return; | 522 return; |
| 519 } | 523 } |
| 520 | 524 |
| 521 if (event->type() == ui::ET_GESTURE_TAP) { | 525 if (event->type() == ui::ET_GESTURE_TAP) { |
| 522 HandleClickEvent(*event, true); | 526 HandleClickEvent(*event, true); |
| 523 event->SetHandled(); | 527 event->SetHandled(); |
| 524 return; | 528 return; |
| 525 } | 529 } |
| 526 | 530 |
| 527 SetState(NORMAL, NORMAL); | |
| 528 views::View::OnGestureEvent(event); | 531 views::View::OnGestureEvent(event); |
| 529 } | 532 } |
| 530 | 533 |
| 531 void DownloadItemView::ShowContextMenuForView(View* source, | 534 void DownloadItemView::ShowContextMenuForView(View* source, |
| 532 const gfx::Point& point, | 535 const gfx::Point& point, |
| 533 ui::MenuSourceType source_type) { | 536 ui::MenuSourceType source_type) { |
| 534 // |point| is in screen coordinates. So convert it to local coordinates first. | 537 ShowContextMenuImpl(gfx::Rect(point, gfx::Size()), source_type); |
| 535 gfx::Point local_point = point; | |
| 536 ConvertPointFromScreen(this, &local_point); | |
| 537 ShowContextMenuImpl(local_point, source_type); | |
| 538 } | 538 } |
| 539 | 539 |
| 540 void DownloadItemView::ButtonPressed(views::Button* sender, | 540 void DownloadItemView::ButtonPressed(views::Button* sender, |
| 541 const ui::Event& event) { | 541 const ui::Event& event) { |
| 542 if (sender == dropdown_button_) { |
| 543 // TODO(estade): this is copied from ToolbarActionView but should be shared |
| 544 // one way or another. |
| 545 ui::MenuSourceType type = ui::MENU_SOURCE_NONE; |
| 546 if (event.IsMouseEvent()) |
| 547 type = ui::MENU_SOURCE_MOUSE; |
| 548 else if (event.IsKeyEvent()) |
| 549 type = ui::MENU_SOURCE_KEYBOARD; |
| 550 else if (event.IsGestureEvent()) |
| 551 type = ui::MENU_SOURCE_TOUCH; |
| 552 SetDropdownState(PUSHED); |
| 553 ShowContextMenuImpl(dropdown_button_->GetBoundsInScreen(), type); |
| 554 return; |
| 555 } |
| 556 |
| 542 base::TimeDelta warning_duration; | 557 base::TimeDelta warning_duration; |
| 543 if (!time_download_warning_shown_.is_null()) | 558 if (!time_download_warning_shown_.is_null()) |
| 544 warning_duration = base::Time::Now() - time_download_warning_shown_; | 559 warning_duration = base::Time::Now() - time_download_warning_shown_; |
| 545 | 560 |
| 546 if (save_button_ && sender == save_button_) { | 561 if (save_button_ && sender == save_button_) { |
| 547 // The user has confirmed a dangerous download. We'd record how quickly the | 562 // The user has confirmed a dangerous download. We'd record how quickly the |
| 548 // user did this to detect whether we're being clickjacked. | 563 // user did this to detect whether we're being clickjacked. |
| 549 UMA_HISTOGRAM_LONG_TIMES("clickjacking.save_download", warning_duration); | 564 UMA_HISTOGRAM_LONG_TIMES("clickjacking.save_download", warning_duration); |
| 550 // ExperienceSampling: User chose to proceed with a dangerous download. | 565 // ExperienceSampling: User chose to proceed with a dangerous download. |
| 551 if (sampling_event_.get()) { | 566 if (sampling_event_.get()) { |
| 552 sampling_event_->CreateUserDecisionEvent( | 567 sampling_event_->CreateUserDecisionEvent( |
| 553 ExperienceSamplingEvent::kProceed); | 568 ExperienceSamplingEvent::kProceed); |
| 554 sampling_event_.reset(NULL); | 569 sampling_event_.reset(NULL); |
| 555 } | 570 } |
| 556 // This will change the state and notify us. | 571 // This will change the state and notify us. |
| 557 download()->ValidateDangerousDownload(); | 572 download()->ValidateDangerousDownload(); |
| 558 return; | 573 return; |
| 559 } | 574 } |
| 560 | 575 |
| 561 // WARNING: all end states after this point delete |this|. | 576 // WARNING: all end states after this point delete |this|. |
| 562 DCHECK_EQ(discard_button_, sender); | 577 DCHECK_EQ(discard_button_, sender); |
| 563 UMA_HISTOGRAM_LONG_TIMES("clickjacking.discard_download", warning_duration); | 578 UMA_HISTOGRAM_LONG_TIMES("clickjacking.discard_download", warning_duration); |
| 564 if (!model_.IsMalicious() && model_.ShouldAllowDownloadFeedback() && | 579 if (!model_.IsMalicious() && model_.ShouldAllowDownloadFeedback() && |
| 565 !shelf_->browser()->profile()->IsOffTheRecord()) { | 580 !shelf_->browser()->profile()->IsOffTheRecord()) { |
| 566 if (!shelf_->browser()->profile()->GetPrefs()->HasPrefPath( | 581 if (!shelf_->browser()->profile()->GetPrefs()->HasPrefPath( |
| 567 prefs::kSafeBrowsingExtendedReportingEnabled)) { | 582 prefs::kSafeBrowsingExtendedReportingEnabled)) { |
| 568 // Show dialog, because the dialog hasn't been shown before. | 583 // Show dialog, because the dialog hasn't been shown before. |
| 569 DownloadFeedbackDialogView::Show( | 584 DownloadFeedbackDialogView::Show( |
| 570 shelf_->get_parent()->GetNativeWindow(), | 585 shelf_->get_parent()->GetNativeWindow(), shelf_->browser()->profile(), |
| 571 shelf_->browser()->profile(), | |
| 572 shelf_->GetNavigator(), | 586 shelf_->GetNavigator(), |
| 573 base::Bind( | 587 base::Bind(&DownloadItemView::PossiblySubmitDownloadToFeedbackService, |
| 574 &DownloadItemView::PossiblySubmitDownloadToFeedbackService, | 588 weak_ptr_factory_.GetWeakPtr())); |
| 575 weak_ptr_factory_.GetWeakPtr())); | |
| 576 } else { | 589 } else { |
| 577 PossiblySubmitDownloadToFeedbackService( | 590 PossiblySubmitDownloadToFeedbackService( |
| 578 shelf_->browser()->profile()->GetPrefs()->GetBoolean( | 591 shelf_->browser()->profile()->GetPrefs()->GetBoolean( |
| 579 prefs::kSafeBrowsingExtendedReportingEnabled)); | 592 prefs::kSafeBrowsingExtendedReportingEnabled)); |
| 580 } | 593 } |
| 581 return; | 594 return; |
| 582 } | 595 } |
| 583 download()->Remove(); | 596 download()->Remove(); |
| 584 } | 597 } |
| 585 | 598 |
| 599 SkColor DownloadItemView::GetVectorIconBaseColor() const { |
| 600 return GetTextColor(); |
| 601 } |
| 602 |
| 586 void DownloadItemView::AnimationProgressed(const gfx::Animation* animation) { | 603 void DownloadItemView::AnimationProgressed(const gfx::Animation* animation) { |
| 587 // We don't care if what animation (body button/drop button/complete), | 604 // We don't care if what animation (body button/drop button/complete), |
| 588 // is calling back, as they all have to go through the same paint call. | 605 // is calling back, as they all have to go through the same paint call. |
| 589 SchedulePaint(); | 606 SchedulePaint(); |
| 590 } | 607 } |
| 591 | 608 |
| 592 void DownloadItemView::OnPaint(gfx::Canvas* canvas) { | 609 void DownloadItemView::OnPaint(gfx::Canvas* canvas) { |
| 593 OnPaintBackground(canvas); | 610 // Make sure to draw |this| opaquely. Since the toolbar color can be partially |
| 594 if (HasFocus()) | 611 // transparent, start with a black backdrop (which is the default initialized |
| 595 canvas->DrawFocusRect(GetLocalBounds()); | 612 // color for opaque canvases). |
| 613 canvas->DrawColor(SK_ColorBLACK); |
| 614 canvas->DrawColor( |
| 615 GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR)); |
| 616 |
| 617 DrawStatusText(canvas); |
| 618 DrawFilename(canvas); |
| 619 DrawIcon(canvas); |
| 620 OnPaintBorder(canvas); |
| 596 } | 621 } |
| 597 | 622 |
| 598 // The DownloadItemView can be in three major modes (NORMAL_MODE, DANGEROUS_MODE | 623 int DownloadItemView::GetYForFilenameText() const { |
| 599 // and MALICIOUS_MODE). | 624 int text_height = font_list_.GetBaseline(); |
| 600 // | 625 if (!status_text_.empty()) |
| 601 // NORMAL_MODE: We are displaying an in-progress or completed download. | 626 text_height += kVerticalTextPadding + status_font_list_.GetBaseline(); |
| 602 // .-------------------------------+-. | 627 return (height() - text_height) / 2; |
| 603 // | [icon] Filename |v| | 628 } |
| 604 // | [ ] Status | | | |
| 605 // `-------------------------------+-' | |
| 606 // | | \_ Drop down button. Invokes menu. Responds | |
| 607 // | | to mouse. (NORMAL, HOT or PUSHED). | |
| 608 // | \_ Icon is overlaid on top of in-progress animation. | |
| 609 // \_ Both the body and the drop down button respond to mouse hover and can be | |
| 610 // pushed (NORMAL, HOT or PUSHED). | |
| 611 // | |
| 612 // DANGEROUS_MODE: The file could be potentially dangerous. | |
| 613 // .-------------------------------------------------------. | |
| 614 // | [ ! ] [This type of file can ] [ Keep ] [ Discard ] | | |
| 615 // | [ ] [destroy your computer..] [ ] [ ] | | |
| 616 // `-------------------------------------------------------' | |
| 617 // | | | | \_ No drop down button. | |
| 618 // | | | \_ Buttons are views::LabelButtons. | |
| 619 // | | \_ Text is in a label (dangerous_download_label_) | |
| 620 // | \_ Warning icon. No progress animation. | |
| 621 // \_ Body is static. Doesn't respond to mouse hover or press. (NORMAL only) | |
| 622 // | |
| 623 // MALICIOUS_MODE: The file is known malware. | |
| 624 // .---------------------------------------------+-. | |
| 625 // | [ - ] [This file is malicious.] [ Discard ] |v| | |
| 626 // | [ ] [ ] [ ] | |-. | |
| 627 // `---------------------------------------------+-' | | |
| 628 // | | | | Drop down button. Responds to | |
| 629 // | | | | mouse.(NORMAL, HOT or PUSHED) | |
| 630 // | | | \_ Button is a views::LabelButton. | |
| 631 // | | \_ Text is in a label (dangerous_download_label_) | |
| 632 // | \_ Warning icon. No progress animation. | |
| 633 // \_ Body is static. Doesn't respond to mouse hover or press. (NORMAL only) | |
| 634 // | |
| 635 void DownloadItemView::OnPaintBackground(gfx::Canvas* canvas) { | |
| 636 BodyImageSet* body_image_set = NULL; | |
| 637 switch (mode_) { | |
| 638 case NORMAL_MODE: | |
| 639 if (body_state_ == PUSHED) | |
| 640 body_image_set = &pushed_body_image_set_; | |
| 641 else // NORMAL or HOT | |
| 642 body_image_set = &normal_body_image_set_; | |
| 643 break; | |
| 644 case DANGEROUS_MODE: | |
| 645 body_image_set = &dangerous_mode_body_image_set_; | |
| 646 break; | |
| 647 case MALICIOUS_MODE: | |
| 648 body_image_set = &malicious_mode_body_image_set_; | |
| 649 break; | |
| 650 default: | |
| 651 NOTREACHED(); | |
| 652 } | |
| 653 | 629 |
| 654 DropDownImageSet* drop_down_image_set = NULL; | 630 void DownloadItemView::DrawStatusText(gfx::Canvas* canvas) { |
| 655 switch (mode_) { | 631 if (status_text_.empty() || IsShowingWarningDialog()) |
| 656 case NORMAL_MODE: | |
| 657 case MALICIOUS_MODE: | |
| 658 if (drop_down_state_ == PUSHED) | |
| 659 drop_down_image_set = &pushed_drop_down_image_set_; | |
| 660 else // NORMAL or HOT | |
| 661 drop_down_image_set = &normal_drop_down_image_set_; | |
| 662 break; | |
| 663 case DANGEROUS_MODE: | |
| 664 // We don't use a drop down button for mode_ == DANGEROUS_MODE. So we let | |
| 665 // drop_down_image_set == NULL. | |
| 666 break; | |
| 667 default: | |
| 668 NOTREACHED(); | |
| 669 } | |
| 670 | |
| 671 int center_width = width() - kLeftPadding - | |
| 672 body_image_set->left->width() - | |
| 673 body_image_set->right->width() - | |
| 674 (drop_down_image_set ? | |
| 675 normal_drop_down_image_set_.center->width() : | |
| 676 0); | |
| 677 | |
| 678 // May be caused by animation. | |
| 679 if (center_width <= 0) | |
| 680 return; | 632 return; |
| 681 | 633 |
| 682 // Draw status before button image to effectively lighten text. No status for | 634 int mirrored_x = GetMirroredXWithWidthInView( |
| 683 // warning dialogs. | 635 kStartPadding + DownloadShelf::kProgressIndicatorSize + |
| 684 if (!IsShowingWarningDialog()) { | 636 kProgressTextPadding, |
| 685 if (!status_text_.empty()) { | 637 kTextWidth); |
| 686 int mirrored_x = GetMirroredXWithWidthInView( | 638 int y = |
| 687 2 * kProgressPadding + DownloadShelf::kProgressIndicatorSize, | 639 GetYForFilenameText() + font_list_.GetBaseline() + kVerticalTextPadding; |
| 688 kTextWidth); | 640 canvas->DrawStringRect( |
| 689 // Add font_list_.height() to compensate for title, which is drawn later. | 641 status_text_, status_font_list_, GetDimmedTextColor(), |
| 690 int y = box_y_ + kVerticalPadding + font_list_.GetHeight() + | 642 gfx::Rect(mirrored_x, y, kTextWidth, status_font_list_.GetHeight())); |
| 691 kVerticalTextPadding; | 643 } |
| 692 SkColor file_name_color = GetThemeProvider()->GetColor( | |
| 693 ThemeProperties::COLOR_BOOKMARK_TEXT); | |
| 694 // If text is light-on-dark, lightening it alone will do nothing. In this | |
| 695 // case we multiply color components by 80% before drawing. | |
| 696 if (!color_utils::IsDark(file_name_color)) { | |
| 697 file_name_color = | |
| 698 color_utils::AlphaBlend(SK_ColorBLACK, file_name_color, 255 / 5); | |
| 699 } | |
| 700 canvas->DrawStringRect(status_text_, font_list_, file_name_color, | |
| 701 gfx::Rect(mirrored_x, y, kTextWidth, | |
| 702 font_list_.GetHeight())); | |
| 703 } | |
| 704 } | |
| 705 | 644 |
| 706 // Paint the background images. | 645 void DownloadItemView::DrawFilename(gfx::Canvas* canvas) { |
| 707 { | 646 if (IsShowingWarningDialog()) |
| 708 gfx::ScopedRTLFlipCanvas scoped_canvas(canvas, width()); | 647 return; |
| 709 | |
| 710 int x = kLeftPadding; | |
| 711 PaintImages(canvas, | |
| 712 body_image_set->top_left, body_image_set->left, | |
| 713 body_image_set->bottom_left, | |
| 714 x, box_y_, box_height_, body_image_set->top_left->width()); | |
| 715 x += body_image_set->top_left->width(); | |
| 716 PaintImages(canvas, | |
| 717 body_image_set->top, body_image_set->center, | |
| 718 body_image_set->bottom, | |
| 719 x, box_y_, box_height_, center_width); | |
| 720 x += center_width; | |
| 721 PaintImages(canvas, | |
| 722 body_image_set->top_right, body_image_set->right, | |
| 723 body_image_set->bottom_right, | |
| 724 x, box_y_, box_height_, body_image_set->top_right->width()); | |
| 725 | |
| 726 // Overlay our body hot state. Warning dialogs don't display body a hot | |
| 727 // state. | |
| 728 if (!IsShowingWarningDialog() && | |
| 729 body_hover_animation_->GetCurrentValue() > 0) { | |
| 730 canvas->SaveLayerAlpha( | |
| 731 static_cast<int>(body_hover_animation_->GetCurrentValue() * 255)); | |
| 732 | |
| 733 int x = kLeftPadding; | |
| 734 PaintImages(canvas, | |
| 735 hot_body_image_set_.top_left, hot_body_image_set_.left, | |
| 736 hot_body_image_set_.bottom_left, | |
| 737 x, box_y_, box_height_, | |
| 738 hot_body_image_set_.top_left->width()); | |
| 739 x += body_image_set->top_left->width(); | |
| 740 PaintImages(canvas, | |
| 741 hot_body_image_set_.top, hot_body_image_set_.center, | |
| 742 hot_body_image_set_.bottom, | |
| 743 x, box_y_, box_height_, center_width); | |
| 744 x += center_width; | |
| 745 PaintImages(canvas, | |
| 746 hot_body_image_set_.top_right, hot_body_image_set_.right, | |
| 747 hot_body_image_set_.bottom_right, | |
| 748 x, box_y_, box_height_, | |
| 749 hot_body_image_set_.top_right->width()); | |
| 750 canvas->Restore(); | |
| 751 } | |
| 752 | |
| 753 x += body_image_set->top_right->width(); | |
| 754 | |
| 755 // Paint the drop-down. | |
| 756 if (drop_down_image_set) { | |
| 757 PaintImages(canvas, | |
| 758 drop_down_image_set->top, drop_down_image_set->center, | |
| 759 drop_down_image_set->bottom, | |
| 760 x, box_y_, box_height_, drop_down_image_set->top->width()); | |
| 761 | |
| 762 // Overlay our drop-down hot state. | |
| 763 if (drop_hover_animation_->GetCurrentValue() > 0) { | |
| 764 canvas->SaveLayerAlpha( | |
| 765 static_cast<int>(drop_hover_animation_->GetCurrentValue() * 255)); | |
| 766 | |
| 767 PaintImages(canvas, | |
| 768 drop_down_image_set->top, drop_down_image_set->center, | |
| 769 drop_down_image_set->bottom, | |
| 770 x, box_y_, box_height_, drop_down_image_set->top->width()); | |
| 771 | |
| 772 canvas->Restore(); | |
| 773 } | |
| 774 } | |
| 775 } | |
| 776 | 648 |
| 777 // Print the text, left aligned and always print the file extension. | 649 // Print the text, left aligned and always print the file extension. |
| 778 // Last value of x was the end of the right image, just before the button. | 650 // Last value of x was the end of the right image, just before the button. |
| 779 // Note that in dangerous mode we use a label (as the text is multi-line). | 651 // Note that in dangerous mode we use a label (as the text is multi-line). |
| 780 if (!IsShowingWarningDialog()) { | 652 base::string16 filename; |
| 781 base::string16 filename; | 653 if (!disabled_while_opening_) { |
| 782 if (!disabled_while_opening_) { | 654 filename = gfx::ElideFilename(download()->GetFileNameToReportUser(), |
| 783 filename = gfx::ElideFilename(download()->GetFileNameToReportUser(), | 655 font_list_, kTextWidth); |
| 784 font_list_, kTextWidth); | 656 } else { |
| 785 } else { | 657 // First, Calculate the download status opening string width. |
| 786 // First, Calculate the download status opening string width. | 658 base::string16 status_string = l10n_util::GetStringFUTF16( |
| 787 base::string16 status_string = | 659 IDS_DOWNLOAD_STATUS_OPENING, base::string16()); |
| 788 l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_OPENING, | 660 int status_string_width = gfx::GetStringWidth(status_string, font_list_); |
| 789 base::string16()); | 661 // Then, elide the file name. |
| 790 int status_string_width = gfx::GetStringWidth(status_string, font_list_); | 662 base::string16 filename_string = |
| 791 // Then, elide the file name. | 663 gfx::ElideFilename(download()->GetFileNameToReportUser(), font_list_, |
| 792 base::string16 filename_string = | 664 kTextWidth - status_string_width); |
| 793 gfx::ElideFilename(download()->GetFileNameToReportUser(), font_list_, | 665 // Last, concat the whole string. |
| 794 kTextWidth - status_string_width); | 666 filename = l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_OPENING, |
| 795 // Last, concat the whole string. | 667 filename_string); |
| 796 filename = l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_OPENING, | |
| 797 filename_string); | |
| 798 } | |
| 799 | |
| 800 int mirrored_x = GetMirroredXWithWidthInView( | |
| 801 2 * kProgressPadding + DownloadShelf::kProgressIndicatorSize, | |
| 802 kTextWidth); | |
| 803 SkColor file_name_color = GetThemeProvider()->GetColor( | |
| 804 ThemeProperties::COLOR_BOOKMARK_TEXT); | |
| 805 int y = | |
| 806 box_y_ + (status_text_.empty() ? | |
| 807 ((box_height_ - font_list_.GetHeight()) / 2) : kVerticalPadding); | |
| 808 | |
| 809 // Draw the file's name. | |
| 810 canvas->DrawStringRect( | |
| 811 filename, font_list_, | |
| 812 enabled() ? file_name_color : kFileNameDisabledColor, | |
| 813 gfx::Rect(mirrored_x, y, kTextWidth, font_list_.GetHeight())); | |
| 814 } | 668 } |
| 815 | 669 |
| 816 // Load the icon. | 670 int mirrored_x = GetMirroredXWithWidthInView( |
| 817 IconManager* im = g_browser_process->icon_manager(); | 671 kStartPadding + DownloadShelf::kProgressIndicatorSize + |
| 818 gfx::Image* image = im->LookupIconFromFilepath( | 672 kProgressTextPadding, |
| 819 download()->GetTargetFilePath(), IconLoader::SMALL); | 673 kTextWidth); |
| 820 const gfx::ImageSkia* icon = NULL; | 674 canvas->DrawStringRect(filename, font_list_, |
| 821 if (IsShowingWarningDialog()) | 675 enabled() ? GetTextColor() : GetDimmedTextColor(), |
| 822 icon = warning_icon_; | 676 gfx::Rect(mirrored_x, GetYForFilenameText(), |
| 823 else if (image) | 677 kTextWidth, font_list_.GetHeight())); |
| 824 icon = image->ToImageSkia(); | 678 } |
| 825 | 679 |
| 826 // We count on the fact that the icon manager will cache the icons and if one | 680 void DownloadItemView::DrawIcon(gfx::Canvas* canvas) { |
| 827 // is available, it will be cached here. We *don't* want to request the icon | 681 if (IsShowingWarningDialog()) { |
| 828 // to be loaded here, since this will also get called if the icon can't be | 682 int icon_x = base::i18n::IsRTL() |
| 829 // loaded, in which case LookupIcon will always be NULL. The loading will be | 683 ? width() - kWarningIconSize - kStartPadding |
| 830 // triggered only when we think the status might change. | 684 : kStartPadding; |
| 831 if (icon) { | 685 int icon_y = (height() - kWarningIconSize) / 2; |
| 832 int progress_x = | 686 canvas->DrawImageInt(GetWarningIcon(), icon_x, icon_y); |
| 833 base::i18n::IsRTL() | 687 return; |
| 834 ? width() - kProgressPadding - DownloadShelf::kProgressIndicatorSize | 688 } |
| 835 : kProgressPadding; | |
| 836 int progress_y = kProgressPadding; | |
| 837 | 689 |
| 838 if (!IsShowingWarningDialog()) { | 690 // Paint download progress. |
| 839 canvas->Save(); | 691 DownloadItem::DownloadState state = download()->GetState(); |
| 840 canvas->Translate(gfx::Vector2d(progress_x, progress_y)); | 692 canvas->Save(); |
| 693 int progress_x = |
| 694 base::i18n::IsRTL() |
| 695 ? width() - kStartPadding - DownloadShelf::kProgressIndicatorSize |
| 696 : kStartPadding; |
| 697 int progress_y = (height() - DownloadShelf::kProgressIndicatorSize) / 2; |
| 698 canvas->Translate(gfx::Vector2d(progress_x, progress_y)); |
| 841 | 699 |
| 842 DownloadItem::DownloadState state = download()->GetState(); | 700 if (state == DownloadItem::IN_PROGRESS) { |
| 843 if (state == DownloadItem::IN_PROGRESS) { | 701 base::TimeDelta progress_time = previous_progress_elapsed_; |
| 844 base::TimeDelta progress_time = previous_progress_elapsed_; | 702 if (!download()->IsPaused()) |
| 845 if (!download()->IsPaused()) | 703 progress_time += base::TimeTicks::Now() - progress_start_time_; |
| 846 progress_time += base::TimeTicks::Now() - progress_start_time_; | 704 DownloadShelf::PaintDownloadProgress( |
| 847 DownloadShelf::PaintDownloadProgress(canvas, *GetThemeProvider(), | 705 canvas, *GetThemeProvider(), progress_time, model_.PercentComplete()); |
| 848 progress_time, | 706 } else if (complete_animation_.get() && complete_animation_->is_animating()) { |
| 849 model_.PercentComplete()); | 707 if (state == DownloadItem::INTERRUPTED) { |
| 850 } else if (complete_animation_.get() && | 708 DownloadShelf::PaintDownloadInterrupted( |
| 851 complete_animation_->is_animating()) { | 709 canvas, *GetThemeProvider(), complete_animation_->GetCurrentValue()); |
| 852 if (state == DownloadItem::INTERRUPTED) { | |
| 853 DownloadShelf::PaintDownloadInterrupted( | |
| 854 canvas, *GetThemeProvider(), | |
| 855 complete_animation_->GetCurrentValue()); | |
| 856 } else { | |
| 857 DCHECK_EQ(DownloadItem::COMPLETE, state); | |
| 858 DownloadShelf::PaintDownloadComplete( | |
| 859 canvas, *GetThemeProvider(), | |
| 860 complete_animation_->GetCurrentValue()); | |
| 861 } | |
| 862 } | |
| 863 canvas->Restore(); | |
| 864 } | |
| 865 | |
| 866 // Draw the icon image. | |
| 867 int icon_x, icon_y; | |
| 868 | |
| 869 if (IsShowingWarningDialog()) { | |
| 870 icon_x = kLeftPadding + body_image_set->top_left->width(); | |
| 871 icon_x = GetMirroredXWithWidthInView(icon_x, icon->width()); | |
| 872 icon_y = (height() - icon->height()) / 2; | |
| 873 } else { | 710 } else { |
| 874 icon_x = progress_x + DownloadShelf::kFiletypeIconOffset; | 711 DCHECK_EQ(DownloadItem::COMPLETE, state); |
| 875 icon_y = progress_y + DownloadShelf::kFiletypeIconOffset; | 712 DownloadShelf::PaintDownloadComplete( |
| 876 } | 713 canvas, *GetThemeProvider(), complete_animation_->GetCurrentValue()); |
| 877 if (enabled()) { | |
| 878 canvas->DrawImageInt(*icon, icon_x, icon_y); | |
| 879 } else { | |
| 880 // Use an alpha to make the image look disabled. | |
| 881 SkPaint paint; | |
| 882 paint.setAlpha(120); | |
| 883 canvas->DrawImageInt(*icon, icon_x, icon_y, paint); | |
| 884 } | 714 } |
| 885 } | 715 } |
| 716 canvas->Restore(); |
| 717 |
| 718 // Fetch the already-loaded icon. |
| 719 IconManager* im = g_browser_process->icon_manager(); |
| 720 gfx::Image* icon = im->LookupIconFromFilepath(download()->GetTargetFilePath(), |
| 721 IconLoader::SMALL); |
| 722 if (!icon) |
| 723 return; |
| 724 |
| 725 // Draw the icon image. |
| 726 int icon_x = progress_x + DownloadShelf::kFiletypeIconOffset; |
| 727 int icon_y = progress_y + DownloadShelf::kFiletypeIconOffset; |
| 728 SkPaint paint; |
| 729 // Use an alpha to make the image look disabled. |
| 730 if (!enabled()) |
| 731 paint.setAlpha(120); |
| 732 canvas->DrawImageInt(*icon->ToImageSkia(), icon_x, icon_y, paint); |
| 886 } | 733 } |
| 887 | 734 |
| 888 void DownloadItemView::OnFocus() { | 735 void DownloadItemView::OnFocus() { |
| 889 View::OnFocus(); | 736 View::OnFocus(); |
| 890 // We render differently when focused. | 737 // We render differently when focused. |
| 891 SchedulePaint(); | 738 SchedulePaint(); |
| 892 } | 739 } |
| 893 | 740 |
| 894 void DownloadItemView::OnBlur() { | 741 void DownloadItemView::OnBlur() { |
| 895 View::OnBlur(); | 742 View::OnBlur(); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 933 | 780 |
| 934 void DownloadItemView::PossiblySubmitDownloadToFeedbackService(bool enabled) { | 781 void DownloadItemView::PossiblySubmitDownloadToFeedbackService(bool enabled) { |
| 935 if (!enabled || !SubmitDownloadToFeedbackService()) | 782 if (!enabled || !SubmitDownloadToFeedbackService()) |
| 936 download()->Remove(); | 783 download()->Remove(); |
| 937 // WARNING: 'this' is deleted at this point. Don't access 'this'. | 784 // WARNING: 'this' is deleted at this point. Don't access 'this'. |
| 938 } | 785 } |
| 939 | 786 |
| 940 void DownloadItemView::LoadIcon() { | 787 void DownloadItemView::LoadIcon() { |
| 941 IconManager* im = g_browser_process->icon_manager(); | 788 IconManager* im = g_browser_process->icon_manager(); |
| 942 last_download_item_path_ = download()->GetTargetFilePath(); | 789 last_download_item_path_ = download()->GetTargetFilePath(); |
| 943 im->LoadIcon(last_download_item_path_, | 790 im->LoadIcon(last_download_item_path_, IconLoader::SMALL, |
| 944 IconLoader::SMALL, | |
| 945 base::Bind(&DownloadItemView::OnExtractIconComplete, | 791 base::Bind(&DownloadItemView::OnExtractIconComplete, |
| 946 base::Unretained(this)), | 792 base::Unretained(this)), |
| 947 &cancelable_task_tracker_); | 793 &cancelable_task_tracker_); |
| 948 } | 794 } |
| 949 | 795 |
| 950 void DownloadItemView::LoadIconIfItemPathChanged() { | 796 void DownloadItemView::LoadIconIfItemPathChanged() { |
| 951 base::FilePath current_download_path = download()->GetTargetFilePath(); | 797 base::FilePath current_download_path = download()->GetTargetFilePath(); |
| 952 if (last_download_item_path_ == current_download_path) | 798 if (last_download_item_path_ == current_download_path) |
| 953 return; | 799 return; |
| 954 | 800 |
| 955 LoadIcon(); | 801 LoadIcon(); |
| 956 } | 802 } |
| 957 | 803 |
| 958 void DownloadItemView::UpdateColorsFromTheme() { | 804 void DownloadItemView::UpdateColorsFromTheme() { |
| 959 if (dangerous_download_label_ && GetThemeProvider()) { | 805 if (!GetThemeProvider()) |
| 960 dangerous_download_label_->SetEnabledColor( | 806 return; |
| 961 GetThemeProvider()->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)); | 807 |
| 962 } | 808 SetBorder(base::MakeUnique<SeparatorBorder>(GetThemeProvider()->GetColor( |
| 809 ThemeProperties::COLOR_TOOLBAR_VERTICAL_SEPARATOR))); |
| 810 |
| 811 SkColor text_color = GetTextColor(); |
| 812 if (dangerous_download_label_) |
| 813 dangerous_download_label_->SetEnabledColor(text_color); |
| 814 if (save_button_) |
| 815 save_button_->SetEnabledTextColors(text_color); |
| 816 if (discard_button_) |
| 817 discard_button_->SetEnabledTextColors(text_color); |
| 963 } | 818 } |
| 964 | 819 |
| 965 void DownloadItemView::ShowContextMenuImpl(const gfx::Point& p, | 820 void DownloadItemView::ShowContextMenuImpl(const gfx::Rect& rect, |
| 966 ui::MenuSourceType source_type) { | 821 ui::MenuSourceType source_type) { |
| 967 gfx::Point point = p; | |
| 968 gfx::Size size; | |
| 969 | |
| 970 // Similar hack as in MenuButton. | 822 // Similar hack as in MenuButton. |
| 971 // We're about to show the menu from a mouse press. By showing from the | 823 // We're about to show the menu from a mouse press. By showing from the |
| 972 // mouse press event we block RootView in mouse dispatching. This also | 824 // mouse press event we block RootView in mouse dispatching. This also |
| 973 // appears to cause RootView to get a mouse pressed BEFORE the mouse | 825 // appears to cause RootView to get a mouse pressed BEFORE the mouse |
| 974 // release is seen, which means RootView sends us another mouse press no | 826 // release is seen, which means RootView sends us another mouse press no |
| 975 // matter where the user pressed. To force RootView to recalculate the | 827 // matter where the user pressed. To force RootView to recalculate the |
| 976 // mouse target during the mouse press we explicitly set the mouse handler | 828 // mouse target during the mouse press we explicitly set the mouse handler |
| 977 // to NULL. | 829 // to NULL. |
| 978 static_cast<views::internal::RootView*>(GetWidget()->GetRootView())-> | 830 static_cast<views::internal::RootView*>(GetWidget()->GetRootView()) |
| 979 SetMouseHandler(NULL); | 831 ->SetMouseHandler(NULL); |
| 980 | |
| 981 // If |is_mouse_gesture| is false, |p| is ignored. The menu is shown aligned | |
| 982 // to drop down arrow button. | |
| 983 if (source_type != ui::MENU_SOURCE_MOUSE && | |
| 984 source_type != ui::MENU_SOURCE_TOUCH) { | |
| 985 drop_down_pressed_ = true; | |
| 986 SetState(NORMAL, PUSHED); | |
| 987 point.SetPoint(drop_down_x_left_, box_y_); | |
| 988 size.SetSize(drop_down_x_right_ - drop_down_x_left_, box_height_); | |
| 989 } | |
| 990 views::View::ConvertPointToScreen(this, &point); | |
| 991 | 832 |
| 992 if (!context_menu_.get()) | 833 if (!context_menu_.get()) |
| 993 context_menu_.reset(new DownloadShelfContextMenuView(download())); | 834 context_menu_.reset(new DownloadShelfContextMenuView(download())); |
| 994 | 835 context_menu_->Run(GetWidget()->GetTopLevelWidget(), rect, source_type, |
| 995 context_menu_->Run(GetWidget()->GetTopLevelWidget(), gfx::Rect(point, size), | 836 base::Bind(&DownloadItemView::ReleaseDropdown, |
| 996 source_type, base::Bind(&DownloadItemView::ReleaseDropDown, | 837 weak_ptr_factory_.GetWeakPtr())); |
| 997 weak_ptr_factory_.GetWeakPtr())); | |
| 998 } | 838 } |
| 999 | 839 |
| 1000 void DownloadItemView::HandlePressEvent(const ui::LocatedEvent& event, | 840 void DownloadItemView::HandlePressEvent(const ui::LocatedEvent& event, |
| 1001 bool active_event) { | 841 bool active_event) { |
| 1002 // The event should not activate us in dangerous mode. | 842 // The event should not activate us in dangerous/malicious mode. |
| 1003 if (mode_ == DANGEROUS_MODE) | 843 if (IsShowingWarningDialog()) |
| 1004 return; | 844 return; |
| 1005 | 845 |
| 1006 // Stop any completion animation. | 846 // Stop any completion animation. |
| 1007 if (complete_animation_.get() && complete_animation_->is_animating()) | 847 if (complete_animation_.get() && complete_animation_->is_animating()) |
| 1008 complete_animation_->End(); | 848 complete_animation_->End(); |
| 1009 | 849 |
| 1010 if (active_event) { | 850 // Don't show the ripple for right clicks. |
| 1011 if (InDropDownButtonXCoordinateRange(event.x())) { | 851 if (!active_event) |
| 1012 if (context_menu_.get()) { | 852 return; |
| 1013 // Ignore two close clicks. This typically happens when the user clicks | 853 |
| 1014 // the button to close the menu. | 854 AnimateInkDrop(views::InkDropState::ACTION_PENDING, &event); |
| 1015 base::TimeDelta delta = | |
| 1016 base::TimeTicks::Now() - context_menu_->close_time(); | |
| 1017 if (delta.InMilliseconds() < views::kMinimumMsBetweenButtonClicks) | |
| 1018 return; | |
| 1019 } | |
| 1020 drop_down_pressed_ = true; | |
| 1021 SetState(NORMAL, PUSHED); | |
| 1022 // We are setting is_mouse_gesture to false when calling ShowContextMenu | |
| 1023 // so that the positioning of the context menu will be similar to a | |
| 1024 // keyboard invocation. I.e. we want the menu to always be positioned | |
| 1025 // next to the drop down button instead of the next to the pointer. | |
| 1026 ShowContextMenuImpl(event.location(), ui::MENU_SOURCE_KEYBOARD); | |
| 1027 // Once called, it is possible that *this was deleted (e.g.: due to | |
| 1028 // invoking the 'Discard' action.) | |
| 1029 } else if (!IsShowingWarningDialog()) { | |
| 1030 SetState(PUSHED, NORMAL); | |
| 1031 } | |
| 1032 } | |
| 1033 } | 855 } |
| 1034 | 856 |
| 1035 void DownloadItemView::HandleClickEvent(const ui::LocatedEvent& event, | 857 void DownloadItemView::HandleClickEvent(const ui::LocatedEvent& event, |
| 1036 bool active_event) { | 858 bool active_event) { |
| 1037 // Mouse should not activate us in dangerous mode. | 859 // The event should not activate us in dangerous/malicious mode. |
| 1038 if (mode_ == DANGEROUS_MODE) | 860 if (!active_event || IsShowingWarningDialog()) |
| 1039 return; | 861 return; |
| 1040 | 862 |
| 1041 SetState(NORMAL, NORMAL); | 863 AnimateInkDrop(views::InkDropState::ACTION_TRIGGERED, &event); |
| 1042 | |
| 1043 if (!active_event || | |
| 1044 InDropDownButtonXCoordinateRange(event.x()) || | |
| 1045 IsShowingWarningDialog()) { | |
| 1046 return; | |
| 1047 } | |
| 1048 | 864 |
| 1049 // OpenDownload may delete this, so don't add any code after this line. | 865 // OpenDownload may delete this, so don't add any code after this line. |
| 1050 OpenDownload(); | 866 OpenDownload(); |
| 1051 } | 867 } |
| 1052 | 868 |
| 1053 // Load an icon for the file type we're downloading, and animate any in progress | 869 void DownloadItemView::SetDropdownState(State new_state) { |
| 1054 // download state. | 870 // Avoid extra SchedulePaint()s if the state is going to be the same and |
| 1055 void DownloadItemView::PaintImages(gfx::Canvas* canvas, | 871 // |dropdown_button_| has already been initialized. |
| 1056 const gfx::ImageSkia* top_image, | 872 if (dropdown_state_ == new_state && |
| 1057 const gfx::ImageSkia* center_image, | 873 !dropdown_button_->GetImage(views::CustomButton::STATE_NORMAL).isNull()) |
| 1058 const gfx::ImageSkia* bottom_image, | |
| 1059 int x, int y, int height, int width) { | |
| 1060 int middle_height = height - top_image->height() - bottom_image->height(); | |
| 1061 // Draw the top. | |
| 1062 canvas->DrawImageInt(*top_image, | |
| 1063 0, 0, top_image->width(), top_image->height(), | |
| 1064 x, y, width, top_image->height(), false); | |
| 1065 y += top_image->height(); | |
| 1066 // Draw the center. | |
| 1067 canvas->DrawImageInt(*center_image, | |
| 1068 0, 0, center_image->width(), center_image->height(), | |
| 1069 x, y, width, middle_height, false); | |
| 1070 y += middle_height; | |
| 1071 // Draw the bottom. | |
| 1072 canvas->DrawImageInt(*bottom_image, | |
| 1073 0, 0, bottom_image->width(), bottom_image->height(), | |
| 1074 x, y, width, bottom_image->height(), false); | |
| 1075 } | |
| 1076 | |
| 1077 void DownloadItemView::SetState(State new_body_state, State new_drop_state) { | |
| 1078 // If we are showing a warning dialog, we don't change body state. | |
| 1079 if (IsShowingWarningDialog()) { | |
| 1080 new_body_state = NORMAL; | |
| 1081 | |
| 1082 // Current body_state_ should always be NORMAL for warning dialogs. | |
| 1083 DCHECK_EQ(NORMAL, body_state_); | |
| 1084 // We shouldn't be calling SetState if we are in DANGEROUS_MODE. | |
| 1085 DCHECK_NE(DANGEROUS_MODE, mode_); | |
| 1086 } | |
| 1087 // Avoid extra SchedulePaint()s if the state is going to be the same. | |
| 1088 if (body_state_ == new_body_state && drop_down_state_ == new_drop_state) | |
| 1089 return; | 874 return; |
| 1090 | 875 |
| 1091 AnimateStateTransition(body_state_, new_body_state, | 876 dropdown_button_->SetIcon(new_state == PUSHED ? gfx::VectorIconId::FIND_NEXT |
| 1092 body_hover_animation_.get()); | 877 : gfx::VectorIconId::FIND_PREV); |
| 1093 AnimateStateTransition(drop_down_state_, new_drop_state, | 878 if (new_state != dropdown_state_) { |
| 1094 drop_hover_animation_.get()); | 879 dropdown_button_->AnimateInkDrop(new_state == PUSHED |
| 1095 body_state_ = new_body_state; | 880 ? views::InkDropState::ACTIVATED |
| 1096 drop_down_state_ = new_drop_state; | 881 : views::InkDropState::DEACTIVATED); |
| 882 } |
| 883 dropdown_button_->OnThemeChanged(); |
| 884 dropdown_state_ = new_state; |
| 1097 SchedulePaint(); | 885 SchedulePaint(); |
| 1098 } | 886 } |
| 1099 | 887 |
| 1100 void DownloadItemView::ToggleWarningDialog() { | 888 void DownloadItemView::ToggleWarningDialog() { |
| 1101 if (model_.IsDangerous()) | 889 if (model_.IsDangerous()) |
| 1102 ShowWarningDialog(); | 890 ShowWarningDialog(); |
| 1103 else | 891 else |
| 1104 ClearWarningDialog(); | 892 ClearWarningDialog(); |
| 1105 | 893 |
| 1106 UpdateDropDownButtonPosition(); | 894 // We need to load the icon now that the download has the real path. |
| 895 LoadIcon(); |
| 1107 | 896 |
| 1108 // Force the shelf to layout again as our size has changed. | 897 // Force the shelf to layout again as our size has changed. |
| 1109 shelf_->Layout(); | 898 shelf_->Layout(); |
| 1110 shelf_->SchedulePaint(); | 899 shelf_->SchedulePaint(); |
| 1111 } | 900 } |
| 1112 | 901 |
| 1113 void DownloadItemView::ClearWarningDialog() { | 902 void DownloadItemView::ClearWarningDialog() { |
| 1114 DCHECK(download()->GetDangerType() == | 903 DCHECK(download()->GetDangerType() == |
| 1115 content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED); | 904 content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED); |
| 1116 DCHECK(mode_ == DANGEROUS_MODE || mode_ == MALICIOUS_MODE); | 905 DCHECK(IsShowingWarningDialog()); |
| 1117 | 906 |
| 1118 mode_ = NORMAL_MODE; | 907 mode_ = NORMAL_MODE; |
| 1119 body_state_ = NORMAL; | 908 dropdown_state_ = NORMAL; |
| 1120 drop_down_state_ = NORMAL; | |
| 1121 | 909 |
| 1122 // ExperienceSampling: User proceeded through the warning. | 910 // ExperienceSampling: User proceeded through the warning. |
| 1123 if (sampling_event_.get()) { | 911 if (sampling_event_.get()) { |
| 1124 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed); | 912 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed); |
| 1125 sampling_event_.reset(NULL); | 913 sampling_event_.reset(NULL); |
| 1126 } | 914 } |
| 1127 // Remove the views used by the warning dialog. | 915 // Remove the views used by the warning dialog. |
| 1128 if (save_button_) { | 916 if (save_button_) { |
| 1129 RemoveChildView(save_button_); | 917 RemoveChildView(save_button_); |
| 1130 delete save_button_; | 918 delete save_button_; |
| 1131 save_button_ = NULL; | 919 save_button_ = NULL; |
| 1132 } | 920 } |
| 1133 RemoveChildView(discard_button_); | 921 RemoveChildView(discard_button_); |
| 1134 delete discard_button_; | 922 delete discard_button_; |
| 1135 discard_button_ = NULL; | 923 discard_button_ = NULL; |
| 1136 RemoveChildView(dangerous_download_label_); | 924 RemoveChildView(dangerous_download_label_); |
| 1137 delete dangerous_download_label_; | 925 delete dangerous_download_label_; |
| 1138 dangerous_download_label_ = NULL; | 926 dangerous_download_label_ = NULL; |
| 1139 dangerous_download_label_sized_ = false; | 927 dangerous_download_label_sized_ = false; |
| 1140 | 928 |
| 1141 // We need to load the icon now that the download has the real path. | 929 // We need to load the icon now that the download has the real path. |
| 1142 LoadIcon(); | 930 LoadIcon(); |
| 931 |
| 932 dropdown_button_->SetVisible(true); |
| 1143 } | 933 } |
| 1144 | 934 |
| 1145 void DownloadItemView::ShowWarningDialog() { | 935 void DownloadItemView::ShowWarningDialog() { |
| 1146 DCHECK(mode_ != DANGEROUS_MODE && mode_ != MALICIOUS_MODE); | 936 DCHECK(mode_ != DANGEROUS_MODE && mode_ != MALICIOUS_MODE); |
| 1147 time_download_warning_shown_ = base::Time::Now(); | 937 time_download_warning_shown_ = base::Time::Now(); |
| 1148 content::DownloadDangerType danger_type = download()->GetDangerType(); | 938 content::DownloadDangerType danger_type = download()->GetDangerType(); |
| 1149 RecordDangerousDownloadWarningShown(danger_type); | 939 RecordDangerousDownloadWarningShown(danger_type); |
| 1150 #if defined(FULL_SAFE_BROWSING) | 940 #if defined(FULL_SAFE_BROWSING) |
| 1151 if (model_.ShouldAllowDownloadFeedback()) { | 941 if (model_.ShouldAllowDownloadFeedback()) { |
| 1152 safe_browsing::DownloadFeedbackService::RecordEligibleDownloadShown( | 942 safe_browsing::DownloadFeedbackService::RecordEligibleDownloadShown( |
| 1153 danger_type); | 943 danger_type); |
| 1154 } | 944 } |
| 1155 #endif | 945 #endif |
| 1156 mode_ = model_.MightBeMalicious() ? MALICIOUS_MODE : DANGEROUS_MODE; | 946 mode_ = model_.MightBeMalicious() ? MALICIOUS_MODE : DANGEROUS_MODE; |
| 1157 | 947 |
| 1158 // ExperienceSampling: Dangerous or malicious download warning is being shown | 948 // ExperienceSampling: Dangerous or malicious download warning is being shown |
| 1159 // to the user, so we start a new SamplingEvent and track it. | 949 // to the user, so we start a new SamplingEvent and track it. |
| 1160 std::string event_name = model_.MightBeMalicious() | 950 std::string event_name = model_.MightBeMalicious() |
| 1161 ? ExperienceSamplingEvent::kMaliciousDownload | 951 ? ExperienceSamplingEvent::kMaliciousDownload |
| 1162 : ExperienceSamplingEvent::kDangerousDownload; | 952 : ExperienceSamplingEvent::kDangerousDownload; |
| 1163 sampling_event_.reset( | 953 sampling_event_.reset(new ExperienceSamplingEvent( |
| 1164 new ExperienceSamplingEvent(event_name, | 954 event_name, download()->GetURL(), download()->GetReferrerUrl(), |
| 1165 download()->GetURL(), | 955 download()->GetBrowserContext())); |
| 1166 download()->GetReferrerUrl(), | |
| 1167 download()->GetBrowserContext())); | |
| 1168 | 956 |
| 1169 body_state_ = NORMAL; | 957 dropdown_state_ = NORMAL; |
| 1170 drop_down_state_ = NORMAL; | |
| 1171 if (mode_ == DANGEROUS_MODE) { | 958 if (mode_ == DANGEROUS_MODE) { |
| 1172 save_button_ = new views::LabelButton( | 959 save_button_ = |
| 1173 this, model_.GetWarningConfirmButtonText()); | 960 views::MdTextButton::Create(this, model_.GetWarningConfirmButtonText()); |
| 1174 save_button_->SetStyle(views::Button::STYLE_BUTTON); | |
| 1175 AddChildView(save_button_); | 961 AddChildView(save_button_); |
| 1176 } | 962 } |
| 1177 discard_button_ = new views::LabelButton( | 963 discard_button_ = views::MdTextButton::Create( |
| 1178 this, l10n_util::GetStringUTF16(IDS_DISCARD_DOWNLOAD)); | 964 this, l10n_util::GetStringUTF16(IDS_DISCARD_DOWNLOAD)); |
| 1179 discard_button_->SetStyle(views::Button::STYLE_BUTTON); | |
| 1180 AddChildView(discard_button_); | 965 AddChildView(discard_button_); |
| 1181 | 966 |
| 1182 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
| 1183 switch (danger_type) { | |
| 1184 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: | |
| 1185 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: | |
| 1186 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: | |
| 1187 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: | |
| 1188 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: | |
| 1189 warning_icon_ = rb.GetImageSkiaNamed(IDR_SAFEBROWSING_WARNING); | |
| 1190 break; | |
| 1191 | |
| 1192 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS: | |
| 1193 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT: | |
| 1194 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED: | |
| 1195 case content::DOWNLOAD_DANGER_TYPE_MAX: | |
| 1196 NOTREACHED(); | |
| 1197 // fallthrough | |
| 1198 | |
| 1199 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: | |
| 1200 warning_icon_ = rb.GetImageSkiaNamed(IDR_WARNING); | |
| 1201 } | |
| 1202 base::string16 dangerous_label = | 967 base::string16 dangerous_label = |
| 1203 model_.GetWarningText(font_list_, kTextWidth); | 968 model_.GetWarningText(font_list_, kTextWidth); |
| 1204 dangerous_download_label_ = new views::Label(dangerous_label); | 969 dangerous_download_label_ = new views::Label(dangerous_label); |
| 1205 dangerous_download_label_->SetMultiLine(true); | 970 dangerous_download_label_->SetMultiLine(true); |
| 1206 dangerous_download_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); | 971 dangerous_download_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
| 1207 dangerous_download_label_->SetAutoColorReadabilityEnabled(false); | 972 dangerous_download_label_->SetAutoColorReadabilityEnabled(false); |
| 1208 AddChildView(dangerous_download_label_); | 973 AddChildView(dangerous_download_label_); |
| 1209 SizeLabelToMinWidth(); | 974 SizeLabelToMinWidth(); |
| 975 |
| 976 dropdown_button_->SetVisible(mode_ == MALICIOUS_MODE); |
| 977 } |
| 978 |
| 979 gfx::ImageSkia DownloadItemView::GetWarningIcon() { |
| 980 switch (download()->GetDangerType()) { |
| 981 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: |
| 982 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT: |
| 983 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: |
| 984 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: |
| 985 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: |
| 986 return gfx::CreateVectorIcon(gfx::VectorIconId::REMOVE_CIRCLE, |
| 987 kWarningIconSize, gfx::kGoogleRed700); |
| 988 |
| 989 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS: |
| 990 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT: |
| 991 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED: |
| 992 case content::DOWNLOAD_DANGER_TYPE_MAX: |
| 993 NOTREACHED(); |
| 994 break; |
| 995 |
| 996 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: |
| 997 return gfx::CreateVectorIcon(gfx::VectorIconId::WARNING, kWarningIconSize, |
| 998 gfx::kGoogleYellow700); |
| 999 } |
| 1000 return gfx::ImageSkia(); |
| 1210 } | 1001 } |
| 1211 | 1002 |
| 1212 gfx::Size DownloadItemView::GetButtonSize() const { | 1003 gfx::Size DownloadItemView::GetButtonSize() const { |
| 1213 DCHECK(discard_button_ && (mode_ == MALICIOUS_MODE || save_button_)); | 1004 DCHECK(discard_button_ && (mode_ == MALICIOUS_MODE || save_button_)); |
| 1214 gfx::Size size = discard_button_->GetPreferredSize(); | 1005 gfx::Size size = discard_button_->GetPreferredSize(); |
| 1215 if (save_button_) | 1006 if (save_button_) |
| 1216 size.SetToMax(save_button_->GetPreferredSize()); | 1007 size.SetToMax(save_button_->GetPreferredSize()); |
| 1217 return size; | 1008 return size; |
| 1218 } | 1009 } |
| 1219 | 1010 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1271 // If the width is growing again, it means we passed the optimal width spot. | 1062 // If the width is growing again, it means we passed the optimal width spot. |
| 1272 if (size.width() > min_width) { | 1063 if (size.width() > min_width) { |
| 1273 dangerous_download_label_->SetText(prev_text); | 1064 dangerous_download_label_->SetText(prev_text); |
| 1274 break; | 1065 break; |
| 1275 } else { | 1066 } else { |
| 1276 min_width = size.width(); | 1067 min_width = size.width(); |
| 1277 } | 1068 } |
| 1278 prev_text = current_text; | 1069 prev_text = current_text; |
| 1279 } | 1070 } |
| 1280 | 1071 |
| 1281 dangerous_download_label_->SetBounds(0, 0, size.width(), size.height()); | 1072 dangerous_download_label_->SetSize(size); |
| 1282 dangerous_download_label_sized_ = true; | 1073 dangerous_download_label_sized_ = true; |
| 1283 } | 1074 } |
| 1284 | 1075 |
| 1285 void DownloadItemView::Reenable() { | 1076 void DownloadItemView::Reenable() { |
| 1286 disabled_while_opening_ = false; | 1077 disabled_while_opening_ = false; |
| 1287 SetEnabled(true); // Triggers a repaint. | 1078 SetEnabled(true); // Triggers a repaint. |
| 1288 } | 1079 } |
| 1289 | 1080 |
| 1290 void DownloadItemView::ReleaseDropDown() { | 1081 void DownloadItemView::ReleaseDropdown() { |
| 1291 drop_down_pressed_ = false; | 1082 SetDropdownState(NORMAL); |
| 1292 SetState(NORMAL, NORMAL); | |
| 1293 } | |
| 1294 | |
| 1295 bool DownloadItemView::InDropDownButtonXCoordinateRange(int x) { | |
| 1296 if (x > drop_down_x_left_ && x < drop_down_x_right_) | |
| 1297 return true; | |
| 1298 return false; | |
| 1299 } | 1083 } |
| 1300 | 1084 |
| 1301 void DownloadItemView::UpdateAccessibleName() { | 1085 void DownloadItemView::UpdateAccessibleName() { |
| 1302 base::string16 new_name; | 1086 base::string16 new_name; |
| 1303 if (IsShowingWarningDialog()) { | 1087 if (IsShowingWarningDialog()) { |
| 1304 new_name = dangerous_download_label_->text(); | 1088 new_name = dangerous_download_label_->text(); |
| 1305 } else { | 1089 } else { |
| 1306 new_name = status_text_ + base::char16(' ') + | 1090 new_name = status_text_ + base::char16(' ') + |
| 1307 download()->GetFileNameToReportUser().LossyDisplayName(); | 1091 download()->GetFileNameToReportUser().LossyDisplayName(); |
| 1308 } | 1092 } |
| 1309 | 1093 |
| 1310 // If the name has changed, notify assistive technology that the name | 1094 // If the name has changed, notify assistive technology that the name |
| 1311 // has changed so they can announce it immediately. | 1095 // has changed so they can announce it immediately. |
| 1312 if (new_name != accessible_name_) { | 1096 if (new_name != accessible_name_) { |
| 1313 accessible_name_ = new_name; | 1097 accessible_name_ = new_name; |
| 1314 NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true); | 1098 NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true); |
| 1315 } | 1099 } |
| 1316 } | 1100 } |
| 1317 | 1101 |
| 1318 void DownloadItemView::UpdateDropDownButtonPosition() { | 1102 void DownloadItemView::AnimateStateTransition(State from, |
| 1319 gfx::Size size = GetPreferredSize(); | 1103 State to, |
| 1320 if (base::i18n::IsRTL()) { | |
| 1321 // Drop down button is glued to the left of the download shelf. | |
| 1322 drop_down_x_left_ = 0; | |
| 1323 drop_down_x_right_ = normal_drop_down_image_set_.top->width(); | |
| 1324 } else { | |
| 1325 // Drop down button is glued to the right of the download shelf. | |
| 1326 drop_down_x_left_ = | |
| 1327 size.width() - normal_drop_down_image_set_.top->width(); | |
| 1328 drop_down_x_right_ = size.width(); | |
| 1329 } | |
| 1330 } | |
| 1331 | |
| 1332 void DownloadItemView::AnimateStateTransition(State from, State to, | |
| 1333 gfx::SlideAnimation* animation) { | 1104 gfx::SlideAnimation* animation) { |
| 1334 if (from == NORMAL && to == HOT) { | 1105 if (from == NORMAL && to == HOT) { |
| 1335 animation->Show(); | 1106 animation->Show(); |
| 1336 } else if (from == HOT && to == NORMAL) { | 1107 } else if (from == HOT && to == NORMAL) { |
| 1337 animation->Hide(); | 1108 animation->Hide(); |
| 1338 } else if (from != to) { | 1109 } else if (from != to) { |
| 1339 animation->Reset((to == HOT) ? 1.0 : 0.0); | 1110 animation->Reset((to == HOT) ? 1.0 : 0.0); |
| 1340 } | 1111 } |
| 1341 } | 1112 } |
| 1342 | 1113 |
| 1343 void DownloadItemView::ProgressTimerFired() { | 1114 void DownloadItemView::ProgressTimerFired() { |
| 1344 // Only repaint for the indeterminate size case. Otherwise, we'll repaint only | 1115 // Only repaint for the indeterminate size case. Otherwise, we'll repaint only |
| 1345 // when there's an update notified via OnDownloadUpdated(). | 1116 // when there's an update notified via OnDownloadUpdated(). |
| 1346 if (model_.PercentComplete() < 0) | 1117 if (model_.PercentComplete() < 0) |
| 1347 SchedulePaint(); | 1118 SchedulePaint(); |
| 1348 } | 1119 } |
| 1120 |
| 1121 SkColor DownloadItemView::GetTextColor() const { |
| 1122 return GetTextColorForThemeProvider(GetThemeProvider()); |
| 1123 } |
| 1124 |
| 1125 SkColor DownloadItemView::GetDimmedTextColor() const { |
| 1126 return SkColorSetA(GetTextColor(), 0xC7); |
| 1127 } |
| OLD | NEW |