- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / gtk / sad_tab_gtk.cc
1 // Copyright (c) 2012 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/gtk/sad_tab_gtk.h"
6
7 #include "base/metrics/histogram.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h"
10 #include "chrome/browser/ui/gtk/tab_contents/chrome_web_contents_view_delegate_gtk.h"
11 #include "chrome/common/url_constants.h"
12 #include "content/public/browser/web_contents.h"
13 #include "grit/generated_resources.h"
14 #include "grit/locale_settings.h"
15 #include "grit/theme_resources.h"
16 #include "ui/base/gtk/gtk_hig_constants.h"
17 #include "ui/base/l10n/l10n_util.h"
18 #include "ui/base/resource/resource_bundle.h"
19 #include "ui/gfx/image/image.h"
20
21 using content::OpenURLParams;
22 using content::WebContents;
23
24 namespace {
25
26 // Background color of the content (a grayish blue) for a crashed tab.
27 const GdkColor kCrashedBackgroundColor = GDK_COLOR_RGB(35, 48, 64);
28
29 // Background color of the content (a grayish purple) for a killed
30 // tab.  TODO(gspencer): update this for the "real" color when the UI
31 // team provides one.  See http://crosbug.com/10711
32 const GdkColor kKilledBackgroundColor = GDK_COLOR_RGB(57, 48, 88);
33
34 // Construct a centered GtkLabel with a white foreground.
35 // |format| is a printf-style format containing a %s;
36 // |str| is substituted into the format.
37 GtkWidget* MakeWhiteMarkupLabel(const char* format, const std::string& str) {
38   GtkWidget* label = gtk_label_new(NULL);
39   char* markup = g_markup_printf_escaped(format, str.c_str());
40   gtk_label_set_markup(GTK_LABEL(label), markup);
41   g_free(markup);
42
43   // Center align and justify it.
44   gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
45   gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
46
47   // Set text to white.
48   GdkColor white = ui::kGdkWhite;
49   gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &white);
50
51   return label;
52 }
53
54 }  // namespace
55
56 SadTabGtk::SadTabGtk(WebContents* web_contents, chrome::SadTabKind kind)
57     : web_contents_(web_contents),
58       kind_(kind) {
59   DCHECK(web_contents_);
60
61   switch (kind_) {
62     case chrome::SAD_TAB_KIND_CRASHED: {
63       static int crashed = 0;
64       UMA_HISTOGRAM_CUSTOM_COUNTS(
65           "Tabs.SadTab.CrashCreated", ++crashed, 1, 1000, 50);
66       break;
67     }
68     case chrome::SAD_TAB_KIND_KILLED: {
69       static int killed = 0;
70       UMA_HISTOGRAM_CUSTOM_COUNTS(
71           "Tabs.SadTab.KilledCreated", ++killed, 1, 1000, 50);
72       break;
73     }
74     default:
75       NOTREACHED();
76   }
77
78   // Use an event box to get the background painting correctly.
79   event_box_.Own(gtk_event_box_new());
80   gtk_widget_modify_bg(event_box_.get(), GTK_STATE_NORMAL,
81       (kind == chrome::SAD_TAB_KIND_CRASHED) ?
82           &kCrashedBackgroundColor : &kKilledBackgroundColor);
83   // Allow ourselves to be resized arbitrarily small.
84   gtk_widget_set_size_request(event_box_.get(), 0, 0);
85
86   GtkWidget* centering = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
87   gtk_container_add(GTK_CONTAINER(event_box_.get()), centering);
88
89   // Use a vertical box to contain icon, title, message and link.
90   GtkWidget* vbox = gtk_vbox_new(FALSE, 0);
91   gtk_container_add(GTK_CONTAINER(centering), vbox);
92
93   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
94   // Add center-aligned image.
95   GtkWidget* image = gtk_image_new_from_pixbuf(rb.GetNativeImageNamed(
96       (kind == chrome::SAD_TAB_KIND_CRASHED) ?
97           IDR_SAD_TAB : IDR_KILLED_TAB).ToGdkPixbuf());
98   gtk_misc_set_alignment(GTK_MISC(image), 0.5, 0.5);
99   gtk_box_pack_start(GTK_BOX(vbox), image, FALSE, FALSE, 0);
100
101   // Add spacer between image and title.
102   GtkWidget* spacer = gtk_label_new(NULL);
103   gtk_label_set_markup(GTK_LABEL(spacer), "<span size=\"larger\"> </span>");
104   gtk_box_pack_start(GTK_BOX(vbox), spacer, FALSE, FALSE, 0);
105
106   // Add center-aligned title.
107   GtkWidget* title = MakeWhiteMarkupLabel(
108       "<span size=\"larger\" style=\"normal\"><b>%s</b></span>",
109       l10n_util::GetStringUTF8((kind == chrome::SAD_TAB_KIND_CRASHED) ?
110           IDS_SAD_TAB_TITLE : IDS_KILLED_TAB_TITLE));
111   gtk_box_pack_start(GTK_BOX(vbox), title, FALSE, FALSE, 0);
112
113   // Add spacer between title and message.
114   spacer = gtk_label_new(" ");
115   gtk_box_pack_start(GTK_BOX(vbox), spacer, FALSE, FALSE, 0);
116
117   // Add center-aligned message.
118   GtkWidget* message = MakeWhiteMarkupLabel(
119       "<span style=\"normal\">%s</span>",
120       l10n_util::GetStringUTF8((kind == chrome::SAD_TAB_KIND_CRASHED) ?
121           IDS_SAD_TAB_MESSAGE : IDS_KILLED_TAB_MESSAGE));
122   gtk_label_set_line_wrap(GTK_LABEL(message), TRUE);
123   gtk_box_pack_start(GTK_BOX(vbox), message, FALSE, FALSE, 0);
124
125   // Add spacer between message and link.
126   spacer = gtk_label_new(" ");
127   gtk_box_pack_start(GTK_BOX(vbox), spacer, FALSE, FALSE, 0);
128
129   if (web_contents_) {
130     // Create the help link and alignment.
131     std::string link_text(l10n_util::GetStringUTF8(
132         (kind == chrome::SAD_TAB_KIND_CRASHED) ?
133             IDS_SAD_TAB_HELP_LINK : IDS_LEARN_MORE));
134     GtkWidget* link = gtk_chrome_link_button_new(link_text.c_str());
135     gtk_chrome_link_button_set_normal_color(GTK_CHROME_LINK_BUTTON(link),
136                                             &ui::kGdkWhite);
137     g_signal_connect(link, "clicked", G_CALLBACK(OnLinkButtonClickThunk), this);
138     GtkWidget* help_alignment = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
139
140     if (kind == chrome::SAD_TAB_KIND_CRASHED) {
141       // Use a horizontal box to contain the help text and link.
142       GtkWidget* help_hbox = gtk_hbox_new(FALSE, 0);
143       gtk_container_add(GTK_CONTAINER(vbox), help_hbox);
144
145       size_t offset = 0;
146       string16 help_text(l10n_util::GetStringFUTF16(IDS_SAD_TAB_HELP_MESSAGE,
147                                                     string16(), &offset));
148       std::string help_prefix_text(UTF16ToUTF8(help_text.substr(0, offset)));
149       std::string help_suffix_text(UTF16ToUTF8(help_text.substr(offset)));
150
151       GtkWidget* help_prefix = MakeWhiteMarkupLabel(
152           "<span style=\"normal\">%s</span>", help_prefix_text);
153       GtkWidget* help_suffix = MakeWhiteMarkupLabel(
154           "<span style=\"normal\">%s</span>", help_suffix_text);
155
156       // Add the help link and text to the horizontal box.
157       gtk_box_pack_start(GTK_BOX(help_hbox), help_prefix, FALSE, FALSE, 0);
158       GtkWidget* link_alignment = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
159       gtk_container_add(GTK_CONTAINER(link_alignment), link);
160       gtk_box_pack_start(GTK_BOX(help_hbox), link_alignment, FALSE, FALSE, 0);
161       gtk_box_pack_start(GTK_BOX(help_hbox), help_suffix, FALSE, FALSE, 0);
162     } else {
163       // Add just the help link to a centered alignment.
164       gtk_container_add(GTK_CONTAINER(help_alignment), link);
165     }
166     gtk_box_pack_start(GTK_BOX(vbox), help_alignment, FALSE, FALSE, 0);
167   }
168
169   gtk_widget_show_all(event_box_.get());
170 }
171
172 SadTabGtk::~SadTabGtk() {
173   event_box_.Destroy();
174 }
175
176 void SadTabGtk::Show() {
177   switch (kind_) {
178     case chrome::SAD_TAB_KIND_CRASHED: {
179       static int crashed = 0;
180       UMA_HISTOGRAM_CUSTOM_COUNTS(
181           "Tabs.SadTab.CrashDisplayed", ++crashed, 1, 1000, 50);
182       break;
183     }
184     case chrome::SAD_TAB_KIND_KILLED: {
185       static int killed = 0;
186       UMA_HISTOGRAM_CUSTOM_COUNTS(
187           "Tabs.SadTab.KilledDisplayed", ++killed, 1, 1000, 50);
188       break;
189     }
190     default:
191       NOTREACHED();
192   }
193
194   GtkWidget* expanded_container =
195       ChromeWebContentsViewDelegateGtk::GetFor(web_contents_)->
196           expanded_container();
197   gtk_container_add(GTK_CONTAINER(expanded_container), event_box_.get());
198   gtk_widget_show(event_box_.get());
199 }
200
201 void SadTabGtk::Close() {
202   GtkWidget* expanded_container =
203       ChromeWebContentsViewDelegateGtk::GetFor(web_contents_)->
204           expanded_container();
205   gtk_container_remove(GTK_CONTAINER(expanded_container), event_box_.get());
206 }
207
208 void SadTabGtk::OnLinkButtonClick(GtkWidget* sender) {
209   if (web_contents_) {
210     GURL help_url((kind_ == chrome::SAD_TAB_KIND_CRASHED) ?
211         chrome::kCrashReasonURL : chrome::kKillReasonURL);
212     OpenURLParams params(help_url, content::Referrer(), CURRENT_TAB,
213                          content::PAGE_TRANSITION_LINK, false);
214     web_contents_->OpenURL(params);
215   }
216 }
217
218 namespace chrome {
219
220 SadTab* SadTab::Create(content::WebContents* web_contents, SadTabKind kind) {
221   return new SadTabGtk(web_contents, kind);
222 }
223
224 }  // namespace chrome