Index: chrome/browser/ui/gtk/download/download_item_gtk.cc |
diff --git a/chrome/browser/ui/gtk/download/download_item_gtk.cc b/chrome/browser/ui/gtk/download/download_item_gtk.cc |
deleted file mode 100644 |
index 8fe4b9e585bc3ac9aa0fe148120b80e6c0398627..0000000000000000000000000000000000000000 |
--- a/chrome/browser/ui/gtk/download/download_item_gtk.cc |
+++ /dev/null |
@@ -1,946 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome/browser/ui/gtk/download/download_item_gtk.h" |
- |
-#include "base/basictypes.h" |
-#include "base/callback.h" |
-#include "base/debug/trace_event.h" |
-#include "base/metrics/histogram.h" |
-#include "base/strings/string_util.h" |
-#include "base/strings/utf_string_conversions.h" |
-#include "base/time/time.h" |
-#include "chrome/browser/browser_process.h" |
-#include "chrome/browser/chrome_notification_types.h" |
-#include "chrome/browser/download/chrome_download_manager_delegate.h" |
-#include "chrome/browser/download/download_item_model.h" |
-#include "chrome/browser/download/download_stats.h" |
-#include "chrome/browser/themes/theme_properties.h" |
-#include "chrome/browser/ui/browser.h" |
-#include "chrome/browser/ui/gtk/download/download_item_drag.h" |
-#include "chrome/browser/ui/gtk/download/download_shelf_context_menu_gtk.h" |
-#include "chrome/browser/ui/gtk/download/download_shelf_gtk.h" |
-#include "chrome/browser/ui/gtk/gtk_theme_service.h" |
-#include "chrome/browser/ui/gtk/gtk_util.h" |
-#include "chrome/browser/ui/gtk/nine_box.h" |
-#include "content/public/browser/download_manager.h" |
-#include "content/public/browser/notification_source.h" |
-#include "grit/generated_resources.h" |
-#include "grit/theme_resources.h" |
-#include "third_party/skia/include/core/SkBitmap.h" |
-#include "ui/base/l10n/l10n_util.h" |
-#include "ui/base/resource/resource_bundle.h" |
-#include "ui/gfx/animation/slide_animation.h" |
-#include "ui/gfx/canvas_skia_paint.h" |
-#include "ui/gfx/color_utils.h" |
-#include "ui/gfx/image/image.h" |
-#include "ui/gfx/skia_utils_gtk.h" |
-#include "ui/gfx/text_elider.h" |
-#include "ui/gfx/text_utils.h" |
- |
-namespace { |
- |
-// The width of the |menu_button_| widget. It has to be at least as wide as the |
-// bitmap that we use to draw it, i.e. 16, but can be more. |
-const int kMenuButtonWidth = 16; |
- |
-// Padding on left and right of items in dangerous download prompt. |
-const int kDangerousElementPadding = 3; |
- |
-// Minimum width of the dangerous download message at which we will start |
-// wrapping. |
-const int kDangerousTextWidth = 200; |
- |
-// Amount of space we allot to showing the filename. If the filename is too wide |
-// it will be elided. |
-const int kTextWidth = 140; |
- |
-// We only cap the size of the tooltip so we don't crash. |
-const int kTooltipMaxWidth = 1000; |
- |
-// The minimum width we will ever draw the download item. Used as a lower bound |
-// during animation. This number comes from the width of the images used to |
-// make the download item. |
-const int kMinDownloadItemWidth = DownloadShelf::kSmallProgressIconSize; |
- |
-// New download item animation speed in milliseconds. |
-const int kNewItemAnimationDurationMs = 800; |
- |
-// How long the 'download complete/interrupted' animation should last for. |
-const int kCompleteAnimationDurationMs = 2500; |
- |
-// Height of the body. |
-const int kBodyHeight = DownloadShelf::kSmallProgressIconSize; |
- |
-// Width of the body area of the download item. |
-// TODO(estade): get rid of the fudge factor. http://crbug.com/18692 |
-const int kBodyWidth = kTextWidth + 50 + DownloadShelf::kSmallProgressIconSize; |
- |
-// The font size of the text, and that size rounded down to the nearest integer |
-// for the size of the arrow in GTK theme mode. |
-const double kTextSize = 13.4; // 13.4px == 10pt @ 96dpi |
- |
-// Darken light-on-dark download status text by 20% before drawing, thus |
-// creating a "muted" version of title text for both dark-on-light and |
-// light-on-dark themes. |
-static const double kDownloadItemLuminanceMod = 0.8; |
- |
-// How long we keep the item disabled after the user clicked it to open the |
-// downloaded item. |
-static const int kDisabledOnOpenDurationMs = 3000; |
- |
-} // namespace |
- |
-NineBox* DownloadItemGtk::body_nine_box_normal_ = NULL; |
-NineBox* DownloadItemGtk::body_nine_box_prelight_ = NULL; |
-NineBox* DownloadItemGtk::body_nine_box_active_ = NULL; |
- |
-NineBox* DownloadItemGtk::menu_nine_box_normal_ = NULL; |
-NineBox* DownloadItemGtk::menu_nine_box_prelight_ = NULL; |
-NineBox* DownloadItemGtk::menu_nine_box_active_ = NULL; |
- |
-NineBox* DownloadItemGtk::dangerous_nine_box_ = NULL; |
- |
-using content::DownloadItem; |
- |
-DownloadItemGtk::DownloadItemGtk(DownloadShelfGtk* parent_shelf, |
- DownloadItem* download_item) |
- : parent_shelf_(parent_shelf), |
- arrow_(NULL), |
- menu_showing_(false), |
- theme_service_( |
- GtkThemeService::GetFrom(parent_shelf->browser()->profile())), |
- progress_angle_(DownloadShelf::kStartAngleDegrees), |
- download_model_(download_item), |
- dangerous_prompt_(NULL), |
- dangerous_label_(NULL), |
- complete_animation_(this), |
- icon_small_(NULL), |
- icon_large_(NULL), |
- creation_time_(base::Time::Now()), |
- download_complete_(false), |
- disabled_while_opening_(false), |
- weak_ptr_factory_(this) { |
- LoadIcon(); |
- |
- body_.Own(gtk_button_new()); |
- gtk_widget_set_app_paintable(body_.get(), TRUE); |
- UpdateTooltip(); |
- |
- g_signal_connect(body_.get(), "expose-event", |
- G_CALLBACK(OnExposeThunk), this); |
- g_signal_connect(body_.get(), "clicked", |
- G_CALLBACK(OnClickThunk), this); |
- g_signal_connect(body_.get(), "button-press-event", |
- G_CALLBACK(OnButtonPressThunk), this); |
- gtk_widget_set_can_focus(body_.get(), FALSE); |
- // Remove internal padding on the button. |
- GtkRcStyle* no_padding_style = gtk_rc_style_new(); |
- no_padding_style->xthickness = 0; |
- no_padding_style->ythickness = 0; |
- gtk_widget_modify_style(body_.get(), no_padding_style); |
- g_object_unref(no_padding_style); |
- |
- name_label_ = gtk_label_new(NULL); |
- // Left align and vertically center the labels. |
- gtk_misc_set_alignment(GTK_MISC(name_label_), 0, 0.5); |
- // Until we switch to vector graphics, force the font size. |
- gtk_util::ForceFontSizePixels(name_label_, kTextSize); |
- |
- UpdateNameLabel(); |
- |
- status_label_ = NULL; |
- |
- // Stack the labels on top of one another. |
- text_stack_ = gtk_vbox_new(FALSE, 0); |
- g_signal_connect(text_stack_, "destroy", |
- G_CALLBACK(gtk_widget_destroyed), &text_stack_); |
- gtk_box_pack_start(GTK_BOX(text_stack_), name_label_, TRUE, TRUE, 0); |
- |
- // We use a GtkFixed because we don't want it to have its own window. |
- // This choice of widget is not critically important though. |
- progress_area_.Own(gtk_fixed_new()); |
- gtk_widget_set_size_request(progress_area_.get(), |
- DownloadShelf::kSmallProgressIconSize, |
- DownloadShelf::kSmallProgressIconSize); |
- gtk_widget_set_app_paintable(progress_area_.get(), TRUE); |
- g_signal_connect(progress_area_.get(), "expose-event", |
- G_CALLBACK(OnProgressAreaExposeThunk), this); |
- |
- // Put the download progress icon on the left of the labels. |
- GtkWidget* body_hbox = gtk_hbox_new(FALSE, 0); |
- gtk_container_add(GTK_CONTAINER(body_.get()), body_hbox); |
- gtk_box_pack_start(GTK_BOX(body_hbox), progress_area_.get(), FALSE, FALSE, 0); |
- gtk_box_pack_start(GTK_BOX(body_hbox), text_stack_, TRUE, TRUE, 0); |
- |
- menu_button_ = gtk_button_new(); |
- gtk_widget_set_app_paintable(menu_button_, TRUE); |
- gtk_widget_set_can_focus(menu_button_, FALSE); |
- g_signal_connect(menu_button_, "expose-event", |
- G_CALLBACK(OnExposeThunk), this); |
- g_signal_connect(menu_button_, "button-press-event", |
- G_CALLBACK(OnMenuButtonPressEventThunk), this); |
- g_object_set_data(G_OBJECT(menu_button_), "left-align-popup", |
- reinterpret_cast<void*>(true)); |
- |
- GtkWidget* shelf_hbox = parent_shelf->GetHBox(); |
- hbox_.Own(gtk_hbox_new(FALSE, 0)); |
- g_signal_connect(hbox_.get(), "expose-event", |
- G_CALLBACK(OnHboxExposeThunk), this); |
- gtk_box_pack_start(GTK_BOX(hbox_.get()), body_.get(), FALSE, FALSE, 0); |
- gtk_box_pack_start(GTK_BOX(hbox_.get()), menu_button_, FALSE, FALSE, 0); |
- gtk_box_pack_start(GTK_BOX(shelf_hbox), hbox_.get(), FALSE, FALSE, 0); |
- // Insert as the leftmost item. |
- gtk_box_reorder_child(GTK_BOX(shelf_hbox), hbox_.get(), 0); |
- |
- download()->AddObserver(this); |
- |
- new_item_animation_.reset(new gfx::SlideAnimation(this)); |
- new_item_animation_->SetSlideDuration(kNewItemAnimationDurationMs); |
- gtk_widget_show_all(hbox_.get()); |
- |
- if (download_model_.IsDangerous()) { |
- RecordDangerousDownloadWarningShown(download()->GetDangerType()); |
- |
- // Hide the download item components for now. |
- gtk_widget_set_no_show_all(body_.get(), TRUE); |
- gtk_widget_set_no_show_all(menu_button_, TRUE); |
- gtk_widget_hide(body_.get()); |
- gtk_widget_hide(menu_button_); |
- |
- // Create an hbox to hold it all. |
- dangerous_hbox_.Own(gtk_hbox_new(FALSE, kDangerousElementPadding)); |
- |
- // Add padding at the beginning and end. The hbox will add padding between |
- // the empty labels and the other elements. |
- GtkWidget* empty_label_a = gtk_label_new(NULL); |
- GtkWidget* empty_label_b = gtk_label_new(NULL); |
- gtk_box_pack_start(GTK_BOX(dangerous_hbox_.get()), empty_label_a, |
- FALSE, FALSE, 0); |
- gtk_box_pack_end(GTK_BOX(dangerous_hbox_.get()), empty_label_b, |
- FALSE, FALSE, 0); |
- |
- // Create the warning icon. |
- dangerous_image_ = gtk_image_new(); |
- gtk_box_pack_start(GTK_BOX(dangerous_hbox_.get()), dangerous_image_, |
- FALSE, FALSE, 0); |
- |
- dangerous_label_ = gtk_label_new(NULL); |
- // We pass TRUE, TRUE so that the label will condense to less than its |
- // request when the animation is going on. |
- gtk_box_pack_start(GTK_BOX(dangerous_hbox_.get()), dangerous_label_, |
- TRUE, TRUE, 0); |
- |
- // Create the nevermind button. |
- GtkWidget* dangerous_decline = gtk_button_new_with_label( |
- l10n_util::GetStringUTF8(IDS_DISCARD_DOWNLOAD).c_str()); |
- g_signal_connect(dangerous_decline, "clicked", |
- G_CALLBACK(OnDangerousDeclineThunk), this); |
- gtk_util::CenterWidgetInHBox(dangerous_hbox_.get(), dangerous_decline, |
- false, 0); |
- |
- // Create the ok button, if this is the kind that can be bypassed. |
- if (!download_model_.IsMalicious()) { |
- GtkWidget* dangerous_accept = gtk_button_new_with_label( |
- base::UTF16ToUTF8( |
- download_model_.GetWarningConfirmButtonText()).c_str()); |
- g_signal_connect(dangerous_accept, "clicked", |
- G_CALLBACK(OnDangerousAcceptThunk), this); |
- gtk_util::CenterWidgetInHBox( |
- dangerous_hbox_.get(), dangerous_accept, false, 0); |
- } |
- |
- // Put it in an alignment so that padding will be added on the left and |
- // right. |
- dangerous_prompt_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); |
- gtk_alignment_set_padding(GTK_ALIGNMENT(dangerous_prompt_), |
- 0, 0, kDangerousElementPadding, kDangerousElementPadding); |
- gtk_container_add(GTK_CONTAINER(dangerous_prompt_), dangerous_hbox_.get()); |
- gtk_box_pack_start(GTK_BOX(hbox_.get()), dangerous_prompt_, FALSE, FALSE, |
- 0); |
- gtk_widget_set_app_paintable(dangerous_prompt_, TRUE); |
- gtk_widget_set_redraw_on_allocate(dangerous_prompt_, TRUE); |
- g_signal_connect(dangerous_prompt_, "expose-event", |
- G_CALLBACK(OnDangerousPromptExposeThunk), this); |
- gtk_widget_show_all(dangerous_prompt_); |
- } |
- |
- registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED, |
- content::Source<ThemeService>(theme_service_)); |
- theme_service_->InitThemesFor(this); |
- |
- // Set the initial width of the widget to be animated. |
- if (download_model_.IsDangerous()) { |
- gtk_widget_set_size_request(dangerous_hbox_.get(), |
- dangerous_hbox_start_width_, -1); |
- } else { |
- gtk_widget_set_size_request(body_.get(), kMinDownloadItemWidth, -1); |
- } |
- |
- new_item_animation_->Show(); |
- |
- complete_animation_.SetTweenType(gfx::Tween::LINEAR); |
- complete_animation_.SetSlideDuration(kCompleteAnimationDurationMs); |
- |
- // Update the status text and animation state. |
- OnDownloadUpdated(download()); |
-} |
- |
-DownloadItemGtk::~DownloadItemGtk() { |
- // First close the menu and then destroy the GtkWidgets. Bug#97724 |
- if (menu_.get()) |
- menu_.reset(); |
- |
- StopDownloadProgress(); |
- download()->RemoveObserver(this); |
- |
- // We may free some shelf space for showing more download items. |
- parent_shelf_->MaybeShowMoreDownloadItems(); |
- |
- hbox_.Destroy(); |
- progress_area_.Destroy(); |
- body_.Destroy(); |
- dangerous_hbox_.Destroy(); |
- |
- // Make sure this widget has been destroyed and the pointer we hold to it |
- // NULLed. |
- DCHECK(!status_label_); |
-} |
- |
-void DownloadItemGtk::OnDownloadUpdated(DownloadItem* download_item) { |
- DCHECK_EQ(download(), download_item); |
- |
- if (dangerous_prompt_ != NULL && !download_model_.IsDangerous()) { |
- // We have been approved. |
- gtk_widget_set_no_show_all(body_.get(), FALSE); |
- gtk_widget_set_no_show_all(menu_button_, FALSE); |
- gtk_widget_show_all(hbox_.get()); |
- gtk_widget_destroy(dangerous_prompt_); |
- gtk_widget_set_size_request(body_.get(), kBodyWidth, -1); |
- dangerous_prompt_ = NULL; |
- |
- // We may free some shelf space for showing more download items. |
- parent_shelf_->MaybeShowMoreDownloadItems(); |
- } |
- |
- if (download()->GetTargetFilePath() != icon_filepath_) { |
- LoadIcon(); |
- UpdateTooltip(); |
- } |
- |
- switch (download()->GetState()) { |
- case DownloadItem::CANCELLED: |
- StopDownloadProgress(); |
- gtk_widget_queue_draw(progress_area_.get()); |
- break; |
- case DownloadItem::INTERRUPTED: |
- StopDownloadProgress(); |
- UpdateTooltip(); |
- |
- complete_animation_.Show(); |
- break; |
- case DownloadItem::COMPLETE: |
- // ShouldRemoveFromShelfWhenComplete() may change after the download's |
- // initial transition to COMPLETE, so we check it before the idemopotency |
- // shield below. |
- if (download_model_.ShouldRemoveFromShelfWhenComplete()) { |
- parent_shelf_->RemoveDownloadItem(this); // This will delete us! |
- return; |
- } |
- |
- // We've already handled the completion specific actions; skip |
- // doing the non-idempotent ones again. |
- if (download_complete_) |
- break; |
- |
- StopDownloadProgress(); |
- |
- // Set up the widget as a drag source. |
- DownloadItemDrag::SetSource(body_.get(), download(), icon_large_); |
- |
- complete_animation_.Show(); |
- download_complete_ = true; |
- break; |
- case DownloadItem::IN_PROGRESS: |
- download()->IsPaused() ? |
- StopDownloadProgress() : StartDownloadProgress(); |
- break; |
- default: |
- NOTREACHED(); |
- } |
- |
- status_text_ = base::UTF16ToUTF8(download_model_.GetStatusText()); |
- UpdateStatusLabel(status_text_); |
-} |
- |
-void DownloadItemGtk::OnDownloadDestroyed(DownloadItem* download_item) { |
- DCHECK_EQ(download(), download_item); |
- parent_shelf_->RemoveDownloadItem(this); |
- // This will delete us! |
-} |
- |
-void DownloadItemGtk::AnimationProgressed(const gfx::Animation* animation) { |
- if (animation == &complete_animation_) { |
- gtk_widget_queue_draw(progress_area_.get()); |
- } else { |
- DCHECK(animation == new_item_animation_.get()); |
- if (download_model_.IsDangerous()) { |
- int progress = static_cast<int>((dangerous_hbox_full_width_ - |
- dangerous_hbox_start_width_) * |
- animation->GetCurrentValue()); |
- int showing_width = dangerous_hbox_start_width_ + progress; |
- gtk_widget_set_size_request(dangerous_hbox_.get(), showing_width, -1); |
- } else { |
- int showing_width = std::max(kMinDownloadItemWidth, |
- static_cast<int>(kBodyWidth * animation->GetCurrentValue())); |
- gtk_widget_set_size_request(body_.get(), showing_width, -1); |
- } |
- } |
-} |
- |
-void DownloadItemGtk::Observe(int type, |
- const content::NotificationSource& source, |
- const content::NotificationDetails& details) { |
- if (type == chrome::NOTIFICATION_BROWSER_THEME_CHANGED) { |
- // Our GtkArrow is only visible in gtk mode. Otherwise, we let the custom |
- // rendering code do whatever it wants. |
- if (theme_service_->UsingNativeTheme()) { |
- if (!arrow_) { |
- arrow_ = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE); |
- gtk_widget_set_size_request(arrow_, |
- static_cast<int>(kTextSize), |
- static_cast<int>(kTextSize)); |
- gtk_container_add(GTK_CONTAINER(menu_button_), arrow_); |
- } |
- |
- gtk_widget_set_size_request(menu_button_, -1, -1); |
- gtk_widget_show(arrow_); |
- } else { |
- InitNineBoxes(); |
- |
- gtk_widget_set_size_request(menu_button_, kMenuButtonWidth, 0); |
- |
- if (arrow_) |
- gtk_widget_hide(arrow_); |
- } |
- |
- UpdateNameLabel(); |
- UpdateStatusLabel(status_text_); |
- UpdateDangerWarning(); |
- } |
-} |
- |
-// Download progress animation functions. |
- |
-void DownloadItemGtk::UpdateDownloadProgress() { |
- progress_angle_ = |
- (progress_angle_ + DownloadShelf::kUnknownIncrementDegrees) % |
- DownloadShelf::kMaxDegrees; |
- gtk_widget_queue_draw(progress_area_.get()); |
-} |
- |
-void DownloadItemGtk::StartDownloadProgress() { |
- if (progress_timer_.IsRunning()) |
- return; |
- progress_timer_.Start(FROM_HERE, |
- base::TimeDelta::FromMilliseconds(DownloadShelf::kProgressRateMs), this, |
- &DownloadItemGtk::UpdateDownloadProgress); |
-} |
- |
-void DownloadItemGtk::StopDownloadProgress() { |
- progress_timer_.Stop(); |
-} |
- |
-// Icon loading functions. |
- |
-void DownloadItemGtk::OnLoadSmallIconComplete(gfx::Image* image) { |
- icon_small_ = image; |
- gtk_widget_queue_draw(progress_area_.get()); |
-} |
- |
-void DownloadItemGtk::OnLoadLargeIconComplete(gfx::Image* image) { |
- icon_large_ = image; |
- if (download()->GetState() == DownloadItem::COMPLETE) |
- DownloadItemDrag::SetSource(body_.get(), download(), icon_large_); |
- // Else, the download will be made draggable once an OnDownloadUpdated() |
- // notification is received with a download in COMPLETE state. |
-} |
- |
-void DownloadItemGtk::LoadIcon() { |
- cancelable_task_tracker_.TryCancelAll(); |
- IconManager* im = g_browser_process->icon_manager(); |
- icon_filepath_ = download()->GetTargetFilePath(); |
- im->LoadIcon(icon_filepath_, |
- IconLoader::SMALL, |
- base::Bind(&DownloadItemGtk::OnLoadSmallIconComplete, |
- base::Unretained(this)), |
- &cancelable_task_tracker_); |
- im->LoadIcon(icon_filepath_, |
- IconLoader::LARGE, |
- base::Bind(&DownloadItemGtk::OnLoadLargeIconComplete, |
- base::Unretained(this)), |
- &cancelable_task_tracker_); |
-} |
- |
-void DownloadItemGtk::UpdateTooltip() { |
- const gfx::FontList& font_list = |
- ui::ResourceBundle::GetSharedInstance().GetFontList( |
- ui::ResourceBundle::BaseFont); |
- base::string16 tooltip_text = |
- download_model_.GetTooltipText(font_list, kTooltipMaxWidth); |
- gtk_widget_set_tooltip_text(body_.get(), |
- base::UTF16ToUTF8(tooltip_text).c_str()); |
-} |
- |
-void DownloadItemGtk::UpdateNameLabel() { |
- const gfx::FontList& font_list = |
- ui::ResourceBundle::GetSharedInstance().GetFontList( |
- ui::ResourceBundle::BaseFont); |
- base::string16 filename; |
- if (!disabled_while_opening_) { |
- filename = gfx::ElideFilename( |
- download()->GetFileNameToReportUser(), font_list, kTextWidth); |
- } else { |
- // First, Calculate the download status opening string width. |
- base::string16 status_string = |
- l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_OPENING, |
- base::string16()); |
- int status_string_width = gfx::GetStringWidth(status_string, font_list); |
- // Then, elide the file name. |
- base::string16 filename_string = |
- gfx::ElideFilename(download()->GetFileNameToReportUser(), font_list, |
- kTextWidth - status_string_width); |
- // Last, concat the whole string. |
- filename = l10n_util::GetStringFUTF16(IDS_DOWNLOAD_STATUS_OPENING, |
- filename_string); |
- } |
- |
- GdkColor color = theme_service_->GetGdkColor( |
- ThemeProperties::COLOR_BOOKMARK_TEXT); |
- gtk_util::SetLabelColor( |
- name_label_, |
- theme_service_->UsingNativeTheme() ? NULL : &color); |
- gtk_label_set_text(GTK_LABEL(name_label_), |
- base::UTF16ToUTF8(filename).c_str()); |
-} |
- |
-void DownloadItemGtk::UpdateStatusLabel(const std::string& status_text) { |
- if (!text_stack_) { |
- // At least our container has been destroyed, which means that |
- // this item is on the way to being destroyed; don't do anything. |
- return; |
- } |
- |
- // If |status_text| is empty, only |name_label_| is displayed at the |
- // vertical center of |text_stack_|. Otherwise, |name_label_| is displayed |
- // on the upper half of |text_stack_| and |status_label_| is displayed |
- // on the lower half of |text_stack_|. |
- if (status_text.empty()) { |
- if (status_label_) |
- gtk_widget_destroy(status_label_); |
- return; |
- } |
- if (!status_label_) { |
- status_label_ = gtk_label_new(NULL); |
- g_signal_connect(status_label_, "destroy", |
- G_CALLBACK(gtk_widget_destroyed), &status_label_); |
- // Left align and vertically center the labels. |
- gtk_misc_set_alignment(GTK_MISC(status_label_), 0, 0.5); |
- // Until we switch to vector graphics, force the font size. |
- gtk_util::ForceFontSizePixels(status_label_, kTextSize); |
- |
- gtk_box_pack_start(GTK_BOX(text_stack_), status_label_, FALSE, FALSE, 0); |
- gtk_widget_show_all(status_label_); |
- } |
- |
- GdkColor text_color; |
- if (!theme_service_->UsingNativeTheme()) { |
- SkColor color = theme_service_->GetColor( |
- ThemeProperties::COLOR_BOOKMARK_TEXT); |
- if (color_utils::RelativeLuminance(color) > 0.5) { |
- color = SkColorSetRGB( |
- static_cast<int>(kDownloadItemLuminanceMod * |
- SkColorGetR(color)), |
- static_cast<int>(kDownloadItemLuminanceMod * |
- SkColorGetG(color)), |
- static_cast<int>(kDownloadItemLuminanceMod * |
- SkColorGetB(color))); |
- } |
- |
- // Lighten the color by blending it with the download item body color. These |
- // values are taken from IDR_DOWNLOAD_BUTTON. |
- SkColor blend_color = SkColorSetRGB(241, 245, 250); |
- text_color = gfx::SkColorToGdkColor( |
- color_utils::AlphaBlend(blend_color, color, 77)); |
- } |
- |
- gtk_util::SetLabelColor( |
- status_label_, |
- theme_service_->UsingNativeTheme() ? NULL : &text_color); |
- gtk_label_set_text(GTK_LABEL(status_label_), status_text.c_str()); |
-} |
- |
-void DownloadItemGtk::UpdateDangerWarning() { |
- if (dangerous_prompt_) { |
- UpdateDangerIcon(); |
- |
- // We create |dangerous_warning| as a wide string so we can more easily |
- // calculate its length in characters. |
- const gfx::FontList& font_list = |
- ui::ResourceBundle::GetSharedInstance().GetFontList( |
- ui::ResourceBundle::BaseFont); |
- base::string16 dangerous_warning = |
- download_model_.GetWarningText(font_list, kTextWidth); |
- if (theme_service_->UsingNativeTheme()) { |
- gtk_util::SetLabelColor(dangerous_label_, NULL); |
- } else { |
- GdkColor color = theme_service_->GetGdkColor( |
- ThemeProperties::COLOR_BOOKMARK_TEXT); |
- gtk_util::SetLabelColor(dangerous_label_, &color); |
- } |
- |
- gtk_label_set_text(GTK_LABEL(dangerous_label_), |
- base::UTF16ToUTF8(dangerous_warning).c_str()); |
- |
- // Until we switch to vector graphics, force the font size. |
- gtk_util::ForceFontSizePixels(dangerous_label_, kTextSize); |
- |
- gtk_widget_set_size_request(dangerous_label_, -1, -1); |
- gtk_label_set_line_wrap(GTK_LABEL(dangerous_label_), FALSE); |
- |
- GtkRequisition req; |
- gtk_widget_size_request(dangerous_label_, &req); |
- |
- gint label_width = req.width; |
- if (req.width > kDangerousTextWidth) { |
- // If the label width exceeds kDangerousTextWidth, we try line wrapping |
- // starting at 60% and increasing in 10% intervals of the full width until |
- // we have a label that fits within the height constraints of the shelf. |
- gtk_label_set_line_wrap(GTK_LABEL(dangerous_label_), TRUE); |
- int full_width = req.width; |
- int tenths = 6; |
- do { |
- label_width = full_width * tenths / 10; |
- gtk_widget_set_size_request(dangerous_label_, label_width, -1); |
- gtk_widget_size_request(dangerous_label_, &req); |
- } while (req.height > kBodyHeight && ++tenths <= 10); |
- DCHECK(req.height <= kBodyHeight); |
- } |
- |
- // The width will depend on the text. We must do this each time we possibly |
- // change the label above. |
- gtk_widget_size_request(dangerous_hbox_.get(), &req); |
- dangerous_hbox_full_width_ = req.width; |
- dangerous_hbox_start_width_ = dangerous_hbox_full_width_ - label_width; |
- } |
-} |
- |
-void DownloadItemGtk::UpdateDangerIcon() { |
- if (theme_service_->UsingNativeTheme()) { |
- const char* stock = download_model_.MightBeMalicious() ? |
- GTK_STOCK_DIALOG_ERROR : GTK_STOCK_DIALOG_WARNING; |
- gtk_image_set_from_stock( |
- GTK_IMAGE(dangerous_image_), stock, GTK_ICON_SIZE_SMALL_TOOLBAR); |
- } else { |
- // Set the warning icon. |
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
- int pixbuf_id = |
- download_model_.MightBeMalicious() ? IDR_SAFEBROWSING_WARNING |
- : IDR_WARNING; |
- gtk_image_set_from_pixbuf(GTK_IMAGE(dangerous_image_), |
- rb.GetNativeImageNamed(pixbuf_id).ToGdkPixbuf()); |
- } |
-} |
- |
-// static |
-void DownloadItemGtk::InitNineBoxes() { |
- if (body_nine_box_normal_) |
- return; |
- |
- body_nine_box_normal_ = new NineBox( |
- IDR_DOWNLOAD_BUTTON_LEFT_TOP, |
- IDR_DOWNLOAD_BUTTON_CENTER_TOP, |
- IDR_DOWNLOAD_BUTTON_RIGHT_TOP, |
- IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE, |
- IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE, |
- IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE, |
- IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM, |
- IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM, |
- IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM); |
- |
- body_nine_box_prelight_ = new NineBox( |
- IDR_DOWNLOAD_BUTTON_LEFT_TOP_H, |
- IDR_DOWNLOAD_BUTTON_CENTER_TOP_H, |
- IDR_DOWNLOAD_BUTTON_RIGHT_TOP_H, |
- IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE_H, |
- IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE_H, |
- IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_H, |
- IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM_H, |
- IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM_H, |
- IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_H); |
- |
- body_nine_box_active_ = new NineBox( |
- IDR_DOWNLOAD_BUTTON_LEFT_TOP_P, |
- IDR_DOWNLOAD_BUTTON_CENTER_TOP_P, |
- IDR_DOWNLOAD_BUTTON_RIGHT_TOP_P, |
- IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE_P, |
- IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE_P, |
- IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_P, |
- IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM_P, |
- IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM_P, |
- IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_P); |
- |
- menu_nine_box_normal_ = new NineBox( |
- IDR_DOWNLOAD_BUTTON_MENU_TOP, 0, 0, |
- IDR_DOWNLOAD_BUTTON_MENU_MIDDLE, 0, 0, |
- IDR_DOWNLOAD_BUTTON_MENU_BOTTOM, 0, 0); |
- |
- menu_nine_box_prelight_ = new NineBox( |
- IDR_DOWNLOAD_BUTTON_MENU_TOP_H, 0, 0, |
- IDR_DOWNLOAD_BUTTON_MENU_MIDDLE_H, 0, 0, |
- IDR_DOWNLOAD_BUTTON_MENU_BOTTOM_H, 0, 0); |
- |
- menu_nine_box_active_ = new NineBox( |
- IDR_DOWNLOAD_BUTTON_MENU_TOP_P, 0, 0, |
- IDR_DOWNLOAD_BUTTON_MENU_MIDDLE_P, 0, 0, |
- IDR_DOWNLOAD_BUTTON_MENU_BOTTOM_P, 0, 0); |
- |
- dangerous_nine_box_ = new NineBox( |
- IDR_DOWNLOAD_BUTTON_LEFT_TOP, |
- IDR_DOWNLOAD_BUTTON_CENTER_TOP, |
- IDR_DOWNLOAD_BUTTON_RIGHT_TOP_NO_DD, |
- IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE, |
- IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE, |
- IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_NO_DD, |
- IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM, |
- IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM, |
- IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_NO_DD); |
-} |
- |
-gboolean DownloadItemGtk::OnHboxExpose(GtkWidget* widget, GdkEventExpose* e) { |
- TRACE_EVENT0("ui::gtk", "DownloadItemGtk::OnHboxExpose"); |
- if (theme_service_->UsingNativeTheme()) { |
- GtkAllocation allocation; |
- gtk_widget_get_allocation(widget, &allocation); |
- int border_width = gtk_container_get_border_width(GTK_CONTAINER(widget)); |
- int x = allocation.x + border_width; |
- int y = allocation.y + border_width; |
- int width = allocation.width - border_width * 2; |
- int height = allocation.height - border_width * 2; |
- |
- if (download_model_.IsDangerous()) { |
- // Draw a simple frame around the area when we're displaying the warning. |
- gtk_paint_shadow(gtk_widget_get_style(widget), |
- gtk_widget_get_window(widget), |
- gtk_widget_get_state(widget), |
- static_cast<GtkShadowType>(GTK_SHADOW_OUT), |
- &e->area, widget, "frame", |
- x, y, width, height); |
- } else { |
- // Manually draw the GTK button border around the download item. We draw |
- // the left part of the button (the file), a divider, and then the right |
- // part of the button (the menu). We can't draw a button on top of each |
- // other (*cough*Clearlooks*cough*) so instead, to draw the left part of |
- // the button, we instruct GTK to draw the entire button...with a |
- // doctored clip rectangle to the left part of the button sans |
- // separator. We then repeat this for the right button. |
- GtkStyle* style = gtk_widget_get_style(body_.get()); |
- |
- GtkAllocation left_clip; |
- gtk_widget_get_allocation(body_.get(), &left_clip); |
- |
- GtkAllocation right_clip; |
- gtk_widget_get_allocation(menu_button_, &right_clip); |
- |
- GtkShadowType body_shadow = |
- GTK_BUTTON(body_.get())->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT; |
- gtk_paint_box(style, |
- gtk_widget_get_window(widget), |
- gtk_widget_get_state(body_.get()), |
- body_shadow, |
- &left_clip, widget, "button", |
- x, y, width, height); |
- |
- GtkShadowType menu_shadow = |
- GTK_BUTTON(menu_button_)->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT; |
- gtk_paint_box(style, |
- gtk_widget_get_window(widget), |
- gtk_widget_get_state(menu_button_), |
- menu_shadow, |
- &right_clip, widget, "button", |
- x, y, width, height); |
- |
- // Doing the math to reverse engineer where we should be drawing our line |
- // is hard and relies on copying GTK internals, so instead steal the |
- // allocation of the gtk arrow which is close enough (and will error on |
- // the conservative side). |
- GtkAllocation arrow_allocation; |
- gtk_widget_get_allocation(arrow_, &arrow_allocation); |
- gtk_paint_vline(style, |
- gtk_widget_get_window(widget), |
- gtk_widget_get_state(widget), |
- &e->area, widget, "button", |
- arrow_allocation.y, |
- arrow_allocation.y + arrow_allocation.height, |
- left_clip.x + left_clip.width); |
- } |
- } |
- return FALSE; |
-} |
- |
-gboolean DownloadItemGtk::OnExpose(GtkWidget* widget, GdkEventExpose* e) { |
- TRACE_EVENT0("ui::gtk", "DownloadItemGtk::OnExpose"); |
- if (!theme_service_->UsingNativeTheme()) { |
- bool is_body = widget == body_.get(); |
- |
- NineBox* nine_box = NULL; |
- // If true, this widget is |body_|, otherwise it is |menu_button_|. |
- if (gtk_widget_get_state(widget) == GTK_STATE_PRELIGHT) |
- nine_box = is_body ? body_nine_box_prelight_ : menu_nine_box_prelight_; |
- else if (gtk_widget_get_state(widget) == GTK_STATE_ACTIVE) |
- nine_box = is_body ? body_nine_box_active_ : menu_nine_box_active_; |
- else |
- nine_box = is_body ? body_nine_box_normal_ : menu_nine_box_normal_; |
- |
- // When the button is showing, we want to draw it as active. We have to do |
- // this explicitly because the button's state will be NORMAL while the menu |
- // has focus. |
- if (!is_body && menu_showing_) |
- nine_box = menu_nine_box_active_; |
- |
- nine_box->RenderToWidget(widget); |
- } |
- |
- GtkWidget* child = gtk_bin_get_child(GTK_BIN(widget)); |
- if (child) |
- gtk_container_propagate_expose(GTK_CONTAINER(widget), child, e); |
- |
- return TRUE; |
-} |
- |
-void DownloadItemGtk::ReenableHbox() { |
- gtk_widget_set_sensitive(hbox_.get(), true); |
- disabled_while_opening_ = false; |
- UpdateNameLabel(); |
-} |
- |
-void DownloadItemGtk::OnDownloadOpened(DownloadItem* download) { |
- disabled_while_opening_ = true; |
- gtk_widget_set_sensitive(hbox_.get(), false); |
- base::MessageLoop::current()->PostDelayedTask( |
- FROM_HERE, |
- base::Bind(&DownloadItemGtk::ReenableHbox, |
- weak_ptr_factory_.GetWeakPtr()), |
- base::TimeDelta::FromMilliseconds(kDisabledOnOpenDurationMs)); |
- UpdateNameLabel(); |
- parent_shelf_->ItemOpened(); |
-} |
- |
-void DownloadItemGtk::OnClick(GtkWidget* widget) { |
- UMA_HISTOGRAM_LONG_TIMES("clickjacking.open_download", |
- base::Time::Now() - creation_time_); |
- download()->OpenDownload(); |
-} |
- |
-gboolean DownloadItemGtk::OnButtonPress(GtkWidget* button, |
- GdkEventButton* event) { |
- if (event->type == GDK_BUTTON_PRESS && event->button == 3) { |
- ShowPopupMenu(NULL, event); |
- return TRUE; |
- } |
- return FALSE; |
-} |
- |
-gboolean DownloadItemGtk::OnProgressAreaExpose(GtkWidget* widget, |
- GdkEventExpose* event) { |
- TRACE_EVENT0("ui::gtk", "DownloadItemGtk::OnProgressAreaExpose"); |
- |
- GtkAllocation allocation; |
- gtk_widget_get_allocation(widget, &allocation); |
- |
- // Create a transparent canvas. |
- gfx::CanvasSkiaPaint canvas(event, false); |
- DownloadItem::DownloadState state = download()->GetState(); |
- if (complete_animation_.is_animating()) { |
- if (state == DownloadItem::INTERRUPTED) { |
- DownloadShelf::PaintDownloadInterrupted( |
- &canvas, |
- allocation.x, |
- allocation.y, |
- complete_animation_.GetCurrentValue(), |
- DownloadShelf::SMALL); |
- } else { |
- DownloadShelf::PaintDownloadComplete( |
- &canvas, |
- allocation.x, |
- allocation.y, |
- complete_animation_.GetCurrentValue(), |
- DownloadShelf::SMALL); |
- } |
- } else if (state == DownloadItem::IN_PROGRESS) { |
- DownloadShelf::PaintDownloadProgress(&canvas, |
- allocation.x, |
- allocation.y, |
- progress_angle_, |
- download_model_.PercentComplete(), |
- DownloadShelf::SMALL); |
- } |
- |
- // |icon_small_| may be NULL if it is still loading. If the file is an |
- // unrecognized type then we will get back a generic system icon. Hence |
- // there is no need to use the chromium-specific default download item icon. |
- if (icon_small_) { |
- const int offset = DownloadShelf::kSmallProgressIconOffset; |
- canvas.DrawImageInt(icon_small_->AsImageSkia(), |
- allocation.x + offset, allocation.y + offset); |
- } |
- |
- return TRUE; |
-} |
- |
-gboolean DownloadItemGtk::OnMenuButtonPressEvent(GtkWidget* button, |
- GdkEventButton* event) { |
- if (event->type == GDK_BUTTON_PRESS && event->button == 1) { |
- ShowPopupMenu(button, event); |
- menu_showing_ = true; |
- gtk_widget_queue_draw(button); |
- return TRUE; |
- } |
- return FALSE; |
-} |
- |
-void DownloadItemGtk::ShowPopupMenu(GtkWidget* button, |
- GdkEventButton* event) { |
- // Stop any completion animation. |
- if (complete_animation_.is_animating()) |
- complete_animation_.End(); |
- |
- if (!menu_.get()) { |
- menu_.reset(new DownloadShelfContextMenuGtk(this, |
- parent_shelf_->GetNavigator())); |
- } |
- menu_->Popup(button, event); |
-} |
- |
-gboolean DownloadItemGtk::OnDangerousPromptExpose(GtkWidget* widget, |
- GdkEventExpose* event) { |
- TRACE_EVENT0("ui::gtk", "DownloadItemGtk::OnDangerousPromptExpose"); |
- if (!theme_service_->UsingNativeTheme()) { |
- // The hbox renderer will take care of the border when in GTK mode. |
- dangerous_nine_box_->RenderToWidget(widget); |
- } |
- return FALSE; // Continue propagation. |
-} |
- |
-void DownloadItemGtk::OnDangerousAccept(GtkWidget* button) { |
- UMA_HISTOGRAM_LONG_TIMES("clickjacking.save_download", |
- base::Time::Now() - creation_time_); |
- download()->ValidateDangerousDownload(); |
-} |
- |
-void DownloadItemGtk::OnDangerousDecline(GtkWidget* button) { |
- UMA_HISTOGRAM_LONG_TIMES("clickjacking.discard_download", |
- base::Time::Now() - creation_time_); |
- download()->Remove(); |
-} |