diff options
author | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-27 23:52:32 +0000 |
---|---|---|
committer | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-27 23:52:32 +0000 |
commit | a0a9577b170540cf58981def1c1616070afbd06f (patch) | |
tree | 15ae29176225715048d6fc98dd0598717ae9c78a /chrome/browser/gtk | |
parent | 9d4d1e4dff1bb10542adbdf568b3920f2ba47a4a (diff) | |
download | chromium_src-a0a9577b170540cf58981def1c1616070afbd06f.zip chromium_src-a0a9577b170540cf58981def1c1616070afbd06f.tar.gz chromium_src-a0a9577b170540cf58981def1c1616070afbd06f.tar.bz2 |
Dangerous download dialog for linux.
BUG=11780
TEST=go to cygwin.com, click "install or update now". The download shelf should appear with a dangerous download dialog, which should animate properly and without undue jank. Clicking "cancel" should delete the item and hide the shelf (since it's the only thing in the shelf). Clicking "save" should make it become a normal download item.
Review URL: http://codereview.chromium.org/113920
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17041 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/gtk')
-rw-r--r-- | chrome/browser/gtk/download_item_gtk.cc | 183 | ||||
-rw-r--r-- | chrome/browser/gtk/download_item_gtk.h | 23 | ||||
-rw-r--r-- | chrome/browser/gtk/download_shelf_gtk.cc | 9 | ||||
-rw-r--r-- | chrome/browser/gtk/find_bar_gtk.cc | 4 | ||||
-rw-r--r-- | chrome/browser/gtk/infobar_gtk.cc | 4 | ||||
-rw-r--r-- | chrome/browser/gtk/slide_animator_gtk.cc | 2 |
6 files changed, 201 insertions, 24 deletions
diff --git a/chrome/browser/gtk/download_item_gtk.cc b/chrome/browser/gtk/download_item_gtk.cc index e8d7a26..580db74 100644 --- a/chrome/browser/gtk/download_item_gtk.cc +++ b/chrome/browser/gtk/download_item_gtk.cc @@ -4,9 +4,11 @@ #include "chrome/browser/gtk/download_item_gtk.h" +#include "app/l10n_util.h" #include "app/gfx/canvas.h" #include "app/gfx/font.h" #include "app/gfx/text_elider.h" +#include "app/resource_bundle.h" #include "app/slide_animation.h" #include "base/basictypes.h" #include "base/string_util.h" @@ -30,6 +32,9 @@ namespace { // 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; + // Amount of space we allot to showing the filename. If the filename is too wide // it will be elided. const int kTextWidth = 140; @@ -39,6 +44,9 @@ const int kTextWidth = 140; // make the download item. const int kMinDownloadItemWidth = 13 + download_util::kSmallProgressIconSize; +// As above, but for the dangerous download prompt. +const int kMinDangerousDownloadWidth = 16; + const char* kLabelColorMarkup = "<span color='#%s'>%s</span>"; const char* kFilenameColor = "576C95"; // 87, 108, 149 const char* kStatusColor = "7B8DAE"; // 123, 141, 174 @@ -155,6 +163,8 @@ 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; + DownloadItemGtk::DownloadItemGtk(DownloadShelfGtk* parent_shelf, BaseDownloadItemModel* download_model) : parent_shelf_(parent_shelf), @@ -162,6 +172,7 @@ DownloadItemGtk::DownloadItemGtk(DownloadShelfGtk* parent_shelf, progress_angle_(download_util::kStartAngleDegrees), download_model_(download_model), bounding_widget_(parent_shelf->GetRightBoundingWidget()), + dangerous_prompt_(NULL), icon_(NULL) { InitNineBoxes(); LoadIcon(); @@ -185,7 +196,7 @@ DownloadItemGtk::DownloadItemGtk(DownloadShelfGtk* parent_shelf, // much padding when we set the size request. We need to either use gfx::Font // or somehow extend TextElider. std::wstring elided_filename = gfx::ElideFilename( - download_model_->download()->GetFileName(), + get_download()->GetFileName(), gfx::Font(), kTextWidth); gchar* label_markup = g_markup_printf_escaped(kLabelColorMarkup, kFilenameColor, @@ -198,8 +209,8 @@ DownloadItemGtk::DownloadItemGtk(DownloadShelfGtk* parent_shelf, gtk_misc_set_alignment(GTK_MISC(name_label_), 0, 0.5); gtk_misc_set_alignment(GTK_MISC(status_label_), 0, 0.5); // Until we switch to vector graphics, force the font size. - gtk_util::ForceFontSizePixels(name_label_, 13.4); // 13.4px == 10pt @ 96dpi - gtk_util::ForceFontSizePixels(status_label_, 13.4); // 13.4px == 10pt @ 96dpi + gtk_util::ForceFontSizePixels(name_label_, 13.4); // 13.4px == 10pt @ 96dpi + gtk_util::ForceFontSizePixels(status_label_, 13.4); // 13.4px == 10pt @ 96dpi // Stack the labels on top of one another. GtkWidget* text_stack = gtk_vbox_new(FALSE, 0); @@ -244,11 +255,92 @@ DownloadItemGtk::DownloadItemGtk(DownloadShelfGtk* parent_shelf, resize_handler_id_ = g_signal_connect(G_OBJECT(shelf_hbox), "size-allocate", G_CALLBACK(OnShelfResized), this); - download_model_->download()->AddObserver(this); + get_download()->AddObserver(this); new_item_animation_.reset(new SlideAnimation(this)); new_item_animation_->SetSlideDuration(kNewItemAnimationDurationMs); gtk_widget_show_all(hbox_); + + if (IsDangerous()) { + // Hide the download item components for now. + gtk_widget_hide(body_); + gtk_widget_hide(menu_button_); + + // Create an hbox to hold it all. + dangerous_hbox_ = 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_), empty_label_a, + FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(dangerous_hbox_), empty_label_b, + FALSE, FALSE, 0); + + // Create the warning icon. + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + GdkPixbuf* download_pixbuf = rb.GetPixbufNamed(IDR_WARNING); + GtkWidget* dangerous_image = gtk_image_new_from_pixbuf(download_pixbuf); + gtk_box_pack_start(GTK_BOX(dangerous_hbox_), dangerous_image, + FALSE, FALSE, 0); + + // Create the warning text. + // TODO(estade): the encoding might not be UTF8. + std::string dangerous_warning = + l10n_util::GetStringFUTF8(IDS_PROMPT_DANGEROUS_DOWNLOAD, + UTF8ToUTF16(get_download()->original_name().value())); + gchar* label_markup = + g_markup_printf_escaped(kLabelColorMarkup, kFilenameColor, + dangerous_warning.c_str()); + GtkWidget* dangerous_label = gtk_label_new(NULL); + // Until we switch to vector graphics, force the font size. + // 13.4px == 10pt @ 96dpi + gtk_util::ForceFontSizePixels(dangerous_label, 13.4); + gtk_label_set_markup(GTK_LABEL(dangerous_label), label_markup); + gtk_label_set_line_wrap(GTK_LABEL(dangerous_label), TRUE); + gtk_box_pack_start(GTK_BOX(dangerous_hbox_), dangerous_label, + FALSE, FALSE, 0); + g_free(label_markup); + + // Create the ok button. + GtkWidget* dangerous_accept = gtk_button_new_with_label( + l10n_util::GetStringUTF8(IDS_SAVE_DOWNLOAD).c_str()); + g_signal_connect(dangerous_accept, "clicked", + G_CALLBACK(OnDangerousAccept), this); + GtkWidget* dangerous_accept_vbox = gtk_vbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(dangerous_accept_vbox), dangerous_accept, + TRUE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(dangerous_hbox_), dangerous_accept_vbox, + FALSE, FALSE, 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(OnDangerousDecline), this); + GtkWidget* dangerous_decline_vbox = gtk_vbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(dangerous_decline_vbox), dangerous_decline, + TRUE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(dangerous_hbox_), dangerous_decline_vbox, + FALSE, FALSE, 0); + + // Put it in an alignment so that padding will be added on the left and + // right, and an event box so that drawing will be clipped correctly. + dangerous_prompt_ = gtk_util::CreateGtkBorderBin(dangerous_hbox_, NULL, + 0, 0, kDangerousElementPadding, kDangerousElementPadding); + gtk_box_pack_start(GTK_BOX(hbox_), dangerous_prompt_, FALSE, FALSE, 0); + gtk_widget_set_app_paintable(dangerous_prompt_, TRUE); + g_signal_connect(dangerous_prompt_, "expose-event", + G_CALLBACK(OnDangerousPromptExpose), this); + gtk_widget_show_all(dangerous_prompt_); + + // The full width will depend on the text. + GtkRequisition req; + gtk_widget_size_request(dangerous_hbox_, &req); + dangerous_hbox_full_width_ = req.width; + } + new_item_animation_->Show(); } @@ -256,11 +348,19 @@ DownloadItemGtk::~DownloadItemGtk() { StopDownloadProgress(); g_signal_handler_disconnect(parent_shelf_->GetHBox(), resize_handler_id_); gtk_widget_destroy(hbox_); - download_model_->download()->RemoveObserver(this); + get_download()->RemoveObserver(this); } void DownloadItemGtk::OnDownloadUpdated(DownloadItem* download) { - DCHECK_EQ(download, download_model_->download()); + DCHECK_EQ(download, get_download()); + + if (dangerous_prompt_ != NULL && + download->safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED) { + // We have been approved. + gtk_widget_show_all(hbox_); + gtk_widget_destroy(dangerous_prompt_); + dangerous_prompt_ = NULL; + } switch (download->state()) { case DownloadItem::REMOVING: @@ -277,7 +377,7 @@ void DownloadItemGtk::OnDownloadUpdated(DownloadItem* download) { complete_animation_->Show(); break; case DownloadItem::IN_PROGRESS: - download_model_->download()->is_paused() ? + get_download()->is_paused() ? StopDownloadProgress() : StartDownloadProgress(); break; default: @@ -309,17 +409,32 @@ void DownloadItemGtk::AnimationProgressed(const Animation* animation) { if (animation == complete_animation_.get()) { gtk_widget_queue_draw(progress_area_); } else { - DCHECK(animation == new_item_animation_.get()); - // See above TODO for explanation of the extra 50. - int showing_width = std::max(kMinDownloadItemWidth, - static_cast<int>((kTextWidth + 50 + - download_util::kSmallProgressIconSize) * - new_item_animation_->GetCurrentValue())); - showing_width = std::max(showing_width, kMinDownloadItemWidth); - gtk_widget_set_size_request(body_, showing_width, -1); + if (IsDangerous()) { + int showing_width = std::max(kMinDangerousDownloadWidth, + static_cast<int>(dangerous_hbox_full_width_ * + new_item_animation_->GetCurrentValue())); + gtk_widget_set_size_request(dangerous_hbox_, showing_width, -1); + } else { + DCHECK(animation == new_item_animation_.get()); + // See above TODO for explanation of the extra 50. + int showing_width = std::max(kMinDownloadItemWidth, + static_cast<int>((kTextWidth + 50 + + download_util::kSmallProgressIconSize) * + new_item_animation_->GetCurrentValue())); + showing_width = std::max(showing_width, kMinDownloadItemWidth); + gtk_widget_set_size_request(body_, showing_width, -1); + } } } +DownloadItem* DownloadItemGtk::get_download() { + return download_model_->download(); +} + +bool DownloadItemGtk::IsDangerous() { + return get_download()->safety_state() == DownloadItem::DANGEROUS; +} + // Download progress animation functions. void DownloadItemGtk::UpdateDownloadProgress() { @@ -351,7 +466,7 @@ void DownloadItemGtk::OnLoadIconComplete(IconManager::Handle handle, void DownloadItemGtk::LoadIcon() { IconManager* im = g_browser_process->icon_manager(); - im->LoadIcon(download_model_->download()->full_path(), + im->LoadIcon(get_download()->full_path(), IconLoader::SMALL, &icon_consumer_, NewCallback(this, &DownloadItemGtk::OnLoadIconComplete)); } @@ -408,6 +523,17 @@ void DownloadItemGtk::InitNineBoxes() { 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); } // static @@ -454,7 +580,7 @@ gboolean DownloadItemGtk::OnProgressAreaExpose(GtkWidget* widget, download_util::PaintDownloadProgress(&canvas, widget->allocation.x, widget->allocation.y, download_item->progress_angle_, - download_item->download_model_->download()->PercentComplete(), + download_item->get_download()->PercentComplete(), download_util::SMALL); } @@ -506,3 +632,26 @@ void DownloadItemGtk::OnShelfResized(GtkWidget *widget, else gtk_widget_show(item->hbox_); } + +// static +gboolean DownloadItemGtk::OnDangerousPromptExpose(GtkWidget* widget, + GdkEventExpose* event, DownloadItemGtk* item) { + dangerous_nine_box_->RenderToWidget(widget); + return FALSE; // Continue propagation. +} + +// static +// TODO(estade): here and below, add clickjacking histogram code. +void DownloadItemGtk::OnDangerousAccept(GtkWidget* button, + DownloadItemGtk* item) { + item->get_download()->manager()->DangerousDownloadValidated( + item->get_download()); +} + +// static +void DownloadItemGtk::OnDangerousDecline(GtkWidget* button, + DownloadItemGtk* item) { + if (item->get_download()->state() == DownloadItem::IN_PROGRESS) + item->get_download()->Cancel(true); + item->get_download()->Remove(true); +} diff --git a/chrome/browser/gtk/download_item_gtk.h b/chrome/browser/gtk/download_item_gtk.h index 0a8a09cd..fba3a8a 100644 --- a/chrome/browser/gtk/download_item_gtk.h +++ b/chrome/browser/gtk/download_item_gtk.h @@ -44,6 +44,11 @@ class DownloadItemGtk : public DownloadItem::Observer, private: friend class DownloadShelfContextMenuGtk; + DownloadItem* get_download(); + + // Returns true IFF the download is dangerous and unconfirmed. + bool IsDangerous(); + // Functions for controlling the progress animation. // Repaint the download progress. void UpdateDownloadProgress(); @@ -76,6 +81,14 @@ class DownloadItemGtk : public DownloadItem::Observer, GtkAllocation *allocation, DownloadItemGtk* item); + // Dangerous download related. ----------------------------------------------- + static gboolean OnDangerousPromptExpose(GtkWidget* widget, + GdkEventExpose* event, + DownloadItemGtk* item); + + static void OnDangerousAccept(GtkWidget* button, DownloadItemGtk* item); + static void OnDangerousDecline(GtkWidget* button, DownloadItemGtk* item); + // Nineboxes for the body area. static NineBox* body_nine_box_normal_; static NineBox* body_nine_box_prelight_; @@ -86,6 +99,9 @@ class DownloadItemGtk : public DownloadItem::Observer, static NineBox* menu_nine_box_prelight_; static NineBox* menu_nine_box_active_; + // Ninebox for the background of the dangerous download prompt. + static NineBox* dangerous_nine_box_; + // The shelf on which we are displayed. DownloadShelfGtk* parent_shelf_; @@ -127,6 +143,13 @@ class DownloadItemGtk : public DownloadItem::Observer, // We do not want to overlap it. GtkWidget* bounding_widget_; + // The dangerous download dialog. This will be null for safe downloads. + GtkWidget* dangerous_prompt_; + + // An hbox for holding components of the dangerous download dialog. + GtkWidget* dangerous_hbox_; + int dangerous_hbox_full_width_; + // The ID of the handler for the parent shelf's "size-allocate" event. We save // it so we can disconnect when we are destroyed. gulong resize_handler_id_; diff --git a/chrome/browser/gtk/download_shelf_gtk.cc b/chrome/browser/gtk/download_shelf_gtk.cc index 00e81c8..999ab27 100644 --- a/chrome/browser/gtk/download_shelf_gtk.cc +++ b/chrome/browser/gtk/download_shelf_gtk.cc @@ -37,13 +37,13 @@ const int kLeftPadding = 2; const int kRightPadding = 10; // The background color of the shelf. -static GdkColor kBackgroundColor = GDK_COLOR_RGB(230, 237, 244); +const GdkColor kBackgroundColor = GDK_COLOR_RGB(230, 237, 244); // Border color (the top pixel of the shelf). -static GdkColor kBorderColor = GDK_COLOR_RGB(214, 214, 214); +const GdkColor kBorderColor = GDK_COLOR_RGB(214, 214, 214); // Speed of the shelf show/hide animation. -static const int kShelfAnimationDurationMs = 120; +const int kShelfAnimationDurationMs = 120; } // namespace @@ -117,6 +117,7 @@ DownloadShelfGtk::DownloadShelfGtk(TabContents* tab_contents) SlideAnimatorGtk::UP, kShelfAnimationDurationMs, false, NULL)); + gtk_widget_show_all(shelf_.get()); // Stick ourselves at the bottom of the parent tab contents. GtkWidget* parent_contents = tab_contents->GetNativeView(); gtk_box_pack_end(GTK_BOX(parent_contents), slide_widget_->widget(), @@ -127,7 +128,7 @@ DownloadShelfGtk::DownloadShelfGtk(TabContents* tab_contents) DownloadShelfGtk::~DownloadShelfGtk() { for (std::vector<DownloadItemGtk*>::iterator iter = download_items_.begin(); iter != download_items_.end(); ++iter) { - delete *iter; + delete *iter; } shelf_.Destroy(); diff --git a/chrome/browser/gtk/find_bar_gtk.cc b/chrome/browser/gtk/find_bar_gtk.cc index 73f5c11..7270b2a 100644 --- a/chrome/browser/gtk/find_bar_gtk.cc +++ b/chrome/browser/gtk/find_bar_gtk.cc @@ -185,10 +185,10 @@ void FindBarGtk::InitWidgets() { gtk_box_pack_start(GTK_BOX(centering_vbox), border_bin_aa, TRUE, FALSE, 0); gtk_box_pack_end(GTK_BOX(hbox), centering_vbox, FALSE, FALSE, 0); - // We show just the GtkFixed and |border_| (but not the dialog). + // We take care to avoid showing the slide animator widget. + gtk_widget_show_all(container_); gtk_widget_show(widget()); gtk_widget_show(border_); - gtk_widget_show(match_count_label_); } GtkWidget* FindBarGtk::slide_widget() { diff --git a/chrome/browser/gtk/infobar_gtk.cc b/chrome/browser/gtk/infobar_gtk.cc index 60fa01d..10d6838 100644 --- a/chrome/browser/gtk/infobar_gtk.cc +++ b/chrome/browser/gtk/infobar_gtk.cc @@ -176,6 +176,8 @@ class LinkInfoBar : public InfoBar { gtk_box_pack_start(GTK_BOX(hbox), trailing_label, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox_), hbox, FALSE, FALSE, 0); } + + gtk_widget_show_all(border_bin_.get()); } private: @@ -199,6 +201,8 @@ class ConfirmInfoBar : public AlertInfoBar { : AlertInfoBar(delegate) { AddConfirmButton(ConfirmInfoBarDelegate::BUTTON_CANCEL); AddConfirmButton(ConfirmInfoBarDelegate::BUTTON_OK); + + gtk_widget_show_all(border_bin_.get()); } private: diff --git a/chrome/browser/gtk/slide_animator_gtk.cc b/chrome/browser/gtk/slide_animator_gtk.cc index 1f76457..dc2aa74 100644 --- a/chrome/browser/gtk/slide_animator_gtk.cc +++ b/chrome/browser/gtk/slide_animator_gtk.cc @@ -66,7 +66,7 @@ SlideAnimatorGtk::~SlideAnimatorGtk() { void SlideAnimatorGtk::Open() { is_closing_ = false; - gtk_widget_show_all(widget_.get()); + gtk_widget_show(widget_.get()); animation_->Show(); } |