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.
5 #include "chrome/browser/ui/validation_message_bubble.h"
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"
23 const int kPadding
= 4;
24 const int kIconTextMargin
= 8;
25 const int kTextMargin
= 4;
26 const int kTextMaxWidth
= 256;
28 // A GTK implementation of ValidationMessageBubble.
29 class ValidationMessageBubbleGtk
: public chrome::ValidationMessageBubble
,
30 public BubbleDelegateGtk
{
32 ValidationMessageBubbleGtk(content::RenderWidgetHost
* widget_host
,
33 const gfx::Rect
& anchor_in_screen
,
34 const base::string16
& main_text
,
35 const base::string16
& sub_text
);
36 virtual ~ValidationMessageBubbleGtk();
37 virtual void SetPositionRelativeToAnchor(
38 content::RenderWidgetHost
* widget_host
,
39 const gfx::Rect
& anchor_in_root_view
) OVERRIDE
;
41 // BubbleDelegateGtk override:
42 virtual void BubbleClosing(BubbleGtk
*, bool) OVERRIDE
;
45 static GtkWidget
* ConstructContent(const base::string16
& main_text
,
46 const base::string16
& sub_text
);
51 ValidationMessageBubbleGtk::ValidationMessageBubbleGtk(
52 content::RenderWidgetHost
* widget_host
,
53 const gfx::Rect
& anchor_in_root_view
,
54 const base::string16
& main_text
,
55 const base::string16
& sub_text
)
57 if (!widget_host
->IsRenderView())
59 Profile
* profile
= Profile::FromBrowserContext(
60 content::WebContents::FromRenderViewHost(
61 content::RenderViewHost::From(widget_host
))->GetBrowserContext());
62 bubble_
= BubbleGtk::Show(widget_host
->GetView()->GetNativeView(),
64 ConstructContent(main_text
, sub_text
),
65 BubbleGtk::ANCHOR_TOP_LEFT
,
66 BubbleGtk::POPUP_WINDOW
,
67 GtkThemeService::GetFrom(profile
),
71 ValidationMessageBubbleGtk::~ValidationMessageBubbleGtk() {
76 void ValidationMessageBubbleGtk::SetPositionRelativeToAnchor(
77 content::RenderWidgetHost
* widget_host
,
78 const gfx::Rect
& anchor_in_root_view
) {
80 bubble_
->SetPositionRelativeToAnchor(&anchor_in_root_view
);
83 void ValidationMessageBubbleGtk::BubbleClosing(BubbleGtk
*, bool) {
88 GtkWidget
* ValidationMessageBubbleGtk::ConstructContent(
89 const base::string16
& main_text
, const base::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
);
101 GtkWidget
* text_box
= gtk_vbox_new(FALSE
, kTextMargin
);
102 GtkWidget
* label
= gtk_label_new(base::UTF16ToUTF8(main_text
).c_str());
103 const gfx::Font
& main_font
= bundle
.GetFont(ResourceBundle::MediumFont
);
104 gtk_util::ForceFontSizePixels(label
, main_font
.GetHeight());
106 GTK_BOX(text_box
), gtk_util::LeftAlignMisc(label
), TRUE
, TRUE
, 0);
108 if (!sub_text
.empty()) {
109 GtkWidget
* sub_label
= gtk_label_new(base::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
);
116 GTK_BOX(text_box
), gtk_util::LeftAlignMisc(sub_label
), TRUE
, TRUE
, 0);
118 gtk_container_add(GTK_CONTAINER(icon_text_box
), text_box
);
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
);
131 scoped_ptr
<ValidationMessageBubble
> ValidationMessageBubble::CreateAndShow(
132 content::RenderWidgetHost
* widget_host
,
133 const gfx::Rect
& anchor_in_root_view
,
134 const base::string16
& main_text
,
135 const base::string16
& sub_text
) {
136 return scoped_ptr
<ValidationMessageBubble
>(new ValidationMessageBubbleGtk(
137 widget_host
, anchor_in_root_view
, main_text
, sub_text
)).Pass();
140 } // namespace chrome