Home | History | Annotate | Download | only in gtk
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/validation_message_bubble.h"
      6 
      7 #include "base/strings/utf_string_conversions.h"
      8 #include "chrome/browser/profiles/profile.h"
      9 #include "chrome/browser/ui/gtk/bubble/bubble_gtk.h"
     10 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
     11 #include "chrome/browser/ui/gtk/gtk_util.h"
     12 #include "content/public/browser/render_view_host.h"
     13 #include "content/public/browser/render_widget_host_view.h"
     14 #include "content/public/browser/web_contents.h"
     15 #include "grit/theme_resources.h"
     16 #include "ui/base/resource/resource_bundle.h"
     17 #include "ui/gfx/gtk_util.h"
     18 #include "ui/gfx/image/image_skia.h"
     19 #include "ui/gfx/rect.h"
     20 
     21 namespace {
     22 
     23 const int kPadding = 4;
     24 const int kIconTextMargin = 8;
     25 const int kTextMargin = 4;
     26 const int kTextMaxWidth = 256;
     27 
     28 // A GTK implementation of ValidationMessageBubble.
     29 class ValidationMessageBubbleGtk : public chrome::ValidationMessageBubble,
     30                                    public BubbleDelegateGtk {
     31  public:
     32   ValidationMessageBubbleGtk(content::RenderWidgetHost* widget_host,
     33                              const gfx::Rect& anchor_in_screen,
     34                              const string16& main_text,
     35                              const string16& sub_text);
     36   virtual ~ValidationMessageBubbleGtk();
     37   virtual void SetPositionRelativeToAnchor(
     38       content::RenderWidgetHost* widget_host,
     39       const gfx::Rect& anchor_in_root_view) OVERRIDE;
     40 
     41   // BubbleDelegateGtk override:
     42   virtual void BubbleClosing(BubbleGtk*, bool) OVERRIDE;
     43 
     44  private:
     45   static GtkWidget* ConstructContent(const string16& main_text,
     46                                      const string16& sub_text);
     47 
     48   BubbleGtk* bubble_;
     49 };
     50 
     51 ValidationMessageBubbleGtk::ValidationMessageBubbleGtk(
     52     content::RenderWidgetHost* widget_host,
     53     const gfx::Rect& anchor_in_root_view,
     54     const string16& main_text,
     55     const string16& sub_text)
     56     : bubble_(NULL) {
     57   if (!widget_host->IsRenderView())
     58     return;
     59   Profile* profile = Profile::FromBrowserContext(
     60       content::WebContents::FromRenderViewHost(
     61           content::RenderViewHost::From(widget_host))->GetBrowserContext());
     62   bubble_ = BubbleGtk::Show(widget_host->GetView()->GetNativeView(),
     63                             &anchor_in_root_view,
     64                             ConstructContent(main_text, sub_text),
     65                             BubbleGtk::ANCHOR_TOP_LEFT,
     66                             BubbleGtk::POPUP_WINDOW,
     67                             GtkThemeService::GetFrom(profile),
     68                             this);
     69 }
     70 
     71 ValidationMessageBubbleGtk::~ValidationMessageBubbleGtk() {
     72   if (bubble_)
     73     bubble_->Close();
     74 }
     75 
     76 void ValidationMessageBubbleGtk::SetPositionRelativeToAnchor(
     77     content::RenderWidgetHost* widget_host,
     78     const gfx::Rect& anchor_in_root_view) {
     79   if (bubble_)
     80     bubble_->SetPositionRelativeToAnchor(&anchor_in_root_view);
     81 }
     82 
     83 void ValidationMessageBubbleGtk::BubbleClosing(BubbleGtk*, bool) {
     84   bubble_ = NULL;
     85 }
     86 
     87 // static
     88 GtkWidget* ValidationMessageBubbleGtk::ConstructContent(
     89       const string16& main_text, const string16& sub_text) {
     90   GtkWidget* icon = gtk_image_new();
     91   gtk_misc_set_alignment(GTK_MISC(icon), 0.5, 0);
     92   gtk_misc_set_padding(GTK_MISC(icon), kPadding, kPadding);
     93   ResourceBundle& bundle = ResourceBundle::GetSharedInstance();
     94   GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(
     95       *bundle.GetImageSkiaNamed(IDR_INPUT_ALERT)->bitmap());
     96   gtk_image_set_from_pixbuf(GTK_IMAGE(icon), pixbuf);
     97   g_object_unref(pixbuf);
     98   GtkWidget* icon_text_box = gtk_hbox_new(FALSE, kIconTextMargin);
     99   gtk_container_add(GTK_CONTAINER(icon_text_box), icon);
    100 
    101   GtkWidget* text_box = gtk_vbox_new(FALSE, kTextMargin);
    102   GtkWidget* label = gtk_label_new(UTF16ToUTF8(main_text).c_str());
    103   const gfx::Font& main_font = bundle.GetFont(ResourceBundle::MediumFont);
    104   gtk_util::ForceFontSizePixels(label, main_font.GetHeight());
    105   gtk_box_pack_start(
    106       GTK_BOX(text_box), gtk_util::LeftAlignMisc(label), TRUE, TRUE, 0);
    107 
    108   if (!sub_text.empty()) {
    109     GtkWidget* sub_label = gtk_label_new(UTF16ToUTF8(sub_text).c_str());
    110     const gfx::Font& sub_font = bundle.GetFont(ResourceBundle::BaseFont);
    111     gtk_util::ForceFontSizePixels(sub_label, sub_font.GetHeight());
    112     int max_characters = kTextMaxWidth / sub_font.GetAverageCharacterWidth();
    113     if (sub_text.length() > static_cast<size_t>(max_characters))
    114       gtk_util::SetLabelWidth(sub_label, kTextMaxWidth);
    115     gtk_box_pack_start(
    116         GTK_BOX(text_box), gtk_util::LeftAlignMisc(sub_label), TRUE, TRUE, 0);
    117   }
    118   gtk_container_add(GTK_CONTAINER(icon_text_box), text_box);
    119 
    120   GtkWidget* content = gtk_alignment_new(0, 0, 0, 0);
    121   gtk_alignment_set_padding(
    122       GTK_ALIGNMENT(content), kPadding, kPadding, kPadding, kPadding);
    123   gtk_container_add(GTK_CONTAINER(content), icon_text_box);
    124   return content;
    125 }
    126 
    127 }  // namespace
    128 
    129 namespace chrome {
    130 
    131 scoped_ptr<ValidationMessageBubble> ValidationMessageBubble::CreateAndShow(
    132     content::RenderWidgetHost* widget_host,
    133     const gfx::Rect& anchor_in_root_view,
    134     const string16& main_text,
    135     const string16& sub_text) {
    136   return scoped_ptr<ValidationMessageBubble>(new ValidationMessageBubbleGtk(
    137       widget_host, anchor_in_root_view, main_text, sub_text)).Pass();
    138 }
    139 
    140 }  // namespace chrome
    141