// Copyright (c) 2013 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/validation_message_bubble.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/gtk/bubble/bubble_gtk.h" #include "chrome/browser/ui/gtk/gtk_theme_service.h" #include "chrome/browser/ui/gtk/gtk_util.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" #include "grit/theme_resources.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/gtk_util.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/rect.h" namespace { const int kPadding = 4; const int kIconTextMargin = 8; const int kTextMargin = 4; const int kTextMaxWidth = 256; // A GTK implementation of ValidationMessageBubble. class ValidationMessageBubbleGtk : public chrome::ValidationMessageBubble, public BubbleDelegateGtk { public: ValidationMessageBubbleGtk(content::RenderWidgetHost* widget_host, const gfx::Rect& anchor_in_screen, const base::string16& main_text, const base::string16& sub_text); virtual ~ValidationMessageBubbleGtk(); virtual void SetPositionRelativeToAnchor( content::RenderWidgetHost* widget_host, const gfx::Rect& anchor_in_root_view) OVERRIDE; // BubbleDelegateGtk override: virtual void BubbleClosing(BubbleGtk*, bool) OVERRIDE; private: static GtkWidget* ConstructContent(const base::string16& main_text, const base::string16& sub_text); BubbleGtk* bubble_; }; ValidationMessageBubbleGtk::ValidationMessageBubbleGtk( content::RenderWidgetHost* widget_host, const gfx::Rect& anchor_in_root_view, const base::string16& main_text, const base::string16& sub_text) : bubble_(NULL) { if (!widget_host->IsRenderView()) return; Profile* profile = Profile::FromBrowserContext( content::WebContents::FromRenderViewHost( content::RenderViewHost::From(widget_host))->GetBrowserContext()); bubble_ = BubbleGtk::Show(widget_host->GetView()->GetNativeView(), &anchor_in_root_view, ConstructContent(main_text, sub_text), BubbleGtk::ANCHOR_TOP_LEFT, BubbleGtk::POPUP_WINDOW, GtkThemeService::GetFrom(profile), this); } ValidationMessageBubbleGtk::~ValidationMessageBubbleGtk() { if (bubble_) bubble_->Close(); } void ValidationMessageBubbleGtk::SetPositionRelativeToAnchor( content::RenderWidgetHost* widget_host, const gfx::Rect& anchor_in_root_view) { if (bubble_) bubble_->SetPositionRelativeToAnchor(&anchor_in_root_view); } void ValidationMessageBubbleGtk::BubbleClosing(BubbleGtk*, bool) { bubble_ = NULL; } // static GtkWidget* ValidationMessageBubbleGtk::ConstructContent( const base::string16& main_text, const base::string16& sub_text) { GtkWidget* icon = gtk_image_new(); gtk_misc_set_alignment(GTK_MISC(icon), 0.5, 0); gtk_misc_set_padding(GTK_MISC(icon), kPadding, kPadding); ResourceBundle& bundle = ResourceBundle::GetSharedInstance(); GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap( *bundle.GetImageSkiaNamed(IDR_INPUT_ALERT)->bitmap()); gtk_image_set_from_pixbuf(GTK_IMAGE(icon), pixbuf); g_object_unref(pixbuf); GtkWidget* icon_text_box = gtk_hbox_new(FALSE, kIconTextMargin); gtk_container_add(GTK_CONTAINER(icon_text_box), icon); GtkWidget* text_box = gtk_vbox_new(FALSE, kTextMargin); GtkWidget* label = gtk_label_new(base::UTF16ToUTF8(main_text).c_str()); const gfx::Font& main_font = bundle.GetFont(ResourceBundle::MediumFont); gtk_util::ForceFontSizePixels(label, main_font.GetHeight()); gtk_box_pack_start( GTK_BOX(text_box), gtk_util::LeftAlignMisc(label), TRUE, TRUE, 0); if (!sub_text.empty()) { GtkWidget* sub_label = gtk_label_new(base::UTF16ToUTF8(sub_text).c_str()); const gfx::Font& sub_font = bundle.GetFont(ResourceBundle::BaseFont); gtk_util::ForceFontSizePixels(sub_label, sub_font.GetHeight()); int max_characters = kTextMaxWidth / sub_font.GetExpectedTextWidth(1); if (sub_text.length() > static_cast(max_characters)) gtk_util::SetLabelWidth(sub_label, kTextMaxWidth); gtk_box_pack_start( GTK_BOX(text_box), gtk_util::LeftAlignMisc(sub_label), TRUE, TRUE, 0); } gtk_container_add(GTK_CONTAINER(icon_text_box), text_box); GtkWidget* content = gtk_alignment_new(0, 0, 0, 0); gtk_alignment_set_padding( GTK_ALIGNMENT(content), kPadding, kPadding, kPadding, kPadding); gtk_container_add(GTK_CONTAINER(content), icon_text_box); return content; } } // namespace namespace chrome { scoped_ptr ValidationMessageBubble::CreateAndShow( content::RenderWidgetHost* widget_host, const gfx::Rect& anchor_in_root_view, const base::string16& main_text, const base::string16& sub_text) { return scoped_ptr(new ValidationMessageBubbleGtk( widget_host, anchor_in_root_view, main_text, sub_text)).Pass(); } } // namespace chrome