OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/views/sad_tab_view.h" | 5 #include "chrome/browser/ui/views/sad_tab_view.h" |
6 | 6 |
7 #include "base/metrics/histogram.h" | 7 #include "base/metrics/histogram.h" |
8 #include "base/utf_string_conversions.h" | 8 #include "base/utf_string_conversions.h" |
9 #include "chrome/browser/google/google_util.h" | 9 #include "chrome/browser/google/google_util.h" |
10 #include "chrome/browser/ui/browser.h" | 10 #include "chrome/browser/ui/browser.h" |
11 #include "chrome/browser/ui/webui/bug_report_ui.h" | 11 #include "chrome/browser/ui/webui/bug_report_ui.h" |
12 #include "chrome/browser/userfeedback/proto/extension.pb.h" | 12 #include "chrome/browser/userfeedback/proto/extension.pb.h" |
13 #include "chrome/common/url_constants.h" | 13 #include "chrome/common/url_constants.h" |
14 #include "content/browser/tab_contents/tab_contents.h" | 14 #include "content/browser/tab_contents/tab_contents.h" |
15 #include "content/browser/tab_contents/tab_contents_delegate.h" | |
16 #include "grit/generated_resources.h" | 15 #include "grit/generated_resources.h" |
17 #include "grit/locale_settings.h" | |
18 #include "grit/theme_resources.h" | 16 #include "grit/theme_resources.h" |
19 #include "third_party/skia/include/effects/SkGradientShader.h" | |
20 #include "ui/base/l10n/l10n_util.h" | 17 #include "ui/base/l10n/l10n_util.h" |
21 #include "ui/base/resource/resource_bundle.h" | 18 #include "ui/base/resource/resource_bundle.h" |
22 #include "ui/gfx/canvas.h" | |
23 #include "ui/gfx/canvas_skia.h" | |
24 #include "ui/gfx/font.h" | 19 #include "ui/gfx/font.h" |
25 #include "ui/gfx/size.h" | |
26 #include "ui/gfx/skia_util.h" | |
27 #include "views/controls/link.h" | 20 #include "views/controls/link.h" |
21 #include "views/controls/label.h" | |
22 #include "views/controls/image_view.h" | |
23 #include "views/layout/box_layout.h" | |
24 #include "views/layout/center_layout.h" | |
28 | 25 |
29 static const int kSadTabOffset = -64; | 26 static const int kSadTabOffset = -64; |
30 static const int kIconTitleSpacing = 20; | 27 static const int kSpacing = 20; |
31 static const int kTitleMessageSpacing = 15; | |
32 static const int kMessageBottomMargin = 20; | |
33 static const float kMessageSize = 0.65f; | 28 static const float kMessageSize = 0.65f; |
34 static const SkColor kTitleColor = SK_ColorWHITE; | 29 static const SkColor kTextColor = SK_ColorWHITE; |
35 static const SkColor kMessageColor = SK_ColorWHITE; | 30 static const SkColor kCrashColor1 = SkColorSetRGB(35, 48, 64); |
Peter Kasting
2011/08/31 17:28:34
Seems like we can do away with one of the copies o
msw
2011/09/01 03:30:49
Done.
| |
36 static const SkColor kLinkColor = SK_ColorWHITE; | 31 static const SkColor kCrashColor2 = SkColorSetRGB(35, 48, 64); |
37 static const SkColor kCrashBackgroundColor = SkColorSetRGB(35, 48, 64); | |
38 static const SkColor kCrashBackgroundEndColor = SkColorSetRGB(35, 48, 64); | |
39 // TODO(gspencer): update these colors when the UI team has picked | 32 // TODO(gspencer): update these colors when the UI team has picked |
40 // official versions. See http://crosbug.com/10711. | 33 // official versions. See http://crosbug.com/10711. |
41 static const SkColor kKillBackgroundColor = SkColorSetRGB(57, 48, 88); | 34 static const SkColor kKillColor1 = SkColorSetRGB(57, 48, 88); |
42 static const SkColor kKillBackgroundEndColor = SkColorSetRGB(57, 48, 88); | 35 static const SkColor kKillColor2 = SkColorSetRGB(57, 48, 88); |
43 static const int kMessageFlags = gfx::Canvas::MULTI_LINE | | |
44 gfx::Canvas::NO_ELLIPSIS | gfx::Canvas::TEXT_ALIGN_CENTER; | |
45 | 36 |
46 // Font size correction. | 37 // Font size correction. |
47 #if defined(CROS_FONTS_USING_BCI) | 38 #if defined(CROS_FONTS_USING_BCI) |
48 static const int kTitleFontSizeDelta = 1; | 39 static const int kTitleFontSizeDelta = 1; |
49 static const int kMessageFontSizeDelta = 0; | 40 static const int kMessageFontSizeDelta = 0; |
50 #else | 41 #else |
51 static const int kTitleFontSizeDelta = 2; | 42 static const int kTitleFontSizeDelta = 2; |
52 static const int kMessageFontSizeDelta = 1; | 43 static const int kMessageFontSizeDelta = 1; |
53 #endif | 44 #endif |
54 | 45 |
55 SadTabView::SadTabView(TabContents* tab_contents, Kind kind) | 46 SadTabView::SadTabView(TabContents* tab_contents, Kind kind) |
56 : tab_contents_(tab_contents), | 47 : tab_contents_(tab_contents), |
57 learn_more_link_(NULL), | |
58 feedback_link_(NULL), | |
59 kind_(kind), | 48 kind_(kind), |
60 painted_(false) { | 49 painted_(false) { |
61 DCHECK(tab_contents); | 50 DCHECK(tab_contents); |
62 | 51 |
63 // Sometimes the user will never see this tab, so keep track of the total | 52 // Sometimes the user will never see this tab, so keep track of the total |
64 // number of creation events to compare to display events. | 53 // number of creation events to compare to display events. |
65 UMA_HISTOGRAM_COUNTS("SadTab.Created", kind); | 54 UMA_HISTOGRAM_COUNTS("SadTab.Created", kind_); |
66 | 55 |
67 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 56 // Set the background gradient. |
68 title_font_ = new gfx::Font( | 57 SkColor color1 = (kind_ == CRASHED) ? kCrashColor1 : kKillColor1; |
69 rb.GetFont(ResourceBundle::BaseFont).DeriveFont(kTitleFontSizeDelta, | 58 SkColor color2 = (kind_ == CRASHED) ? kCrashColor2 : kKillColor2; |
70 gfx::Font::BOLD)); | 59 set_background( |
71 message_font_ = new gfx::Font( | 60 views::Background::CreateVerticalGradientBackground(color1, color2)); |
72 rb.GetFont(ResourceBundle::BaseFont).DeriveFont(kMessageFontSizeDelta)); | |
73 sad_tab_bitmap_ = rb.GetBitmapNamed( | |
74 kind == CRASHED ? IDR_SAD_TAB : IDR_KILLED_TAB); | |
75 | |
76 title_ = l10n_util::GetStringUTF16( | |
77 kind == CRASHED ? IDS_SAD_TAB_TITLE : IDS_KILLED_TAB_TITLE); | |
78 title_width_ = title_font_->GetStringWidth(title_); | |
79 message_ = l10n_util::GetStringUTF16( | |
80 kind == CRASHED ? IDS_SAD_TAB_MESSAGE : IDS_KILLED_TAB_MESSAGE); | |
81 | |
82 if (tab_contents != NULL) { | |
83 learn_more_link_ = | |
84 new views::Link(UTF16ToWide(l10n_util::GetStringUTF16(IDS_LEARN_MORE))); | |
85 learn_more_link_->SetFont(*message_font_); | |
86 learn_more_link_->SetNormalColor(kLinkColor); | |
87 learn_more_link_->set_listener(this); | |
88 AddChildView(learn_more_link_); | |
89 | |
90 if (kind == KILLED) { | |
91 feedback_link_ = new views::Link( | |
92 UTF16ToWide(l10n_util::GetStringUTF16(IDS_KILLED_TAB_FEEDBACK_LINK))); | |
93 feedback_link_->SetFont(*message_font_); | |
94 feedback_link_->SetNormalColor(kLinkColor); | |
95 feedback_link_->set_listener(this); | |
96 AddChildView(feedback_link_); | |
97 } | |
98 } | |
99 } | 61 } |
100 | 62 |
101 SadTabView::~SadTabView() {} | 63 SadTabView::~SadTabView() {} |
102 | 64 |
103 void SadTabView::OnPaint(gfx::Canvas* canvas) { | |
104 if (!painted_) { | |
105 // User actually saw the error, keep track for user experience stats. | |
106 UMA_HISTOGRAM_COUNTS("SadTab.Displayed", kind_); | |
107 painted_ = true; | |
108 } | |
109 SkPaint paint; | |
110 SkSafeUnref(paint.setShader( | |
111 gfx::CreateGradientShader( | |
112 0, | |
113 height(), | |
114 kind_ == CRASHED ? kCrashBackgroundColor : kKillBackgroundColor, | |
115 kind_ == CRASHED ? | |
116 kCrashBackgroundEndColor : kKillBackgroundEndColor))); | |
117 paint.setStyle(SkPaint::kFill_Style); | |
118 canvas->AsCanvasSkia()->drawRectCoords( | |
119 0, 0, SkIntToScalar(width()), SkIntToScalar(height()), paint); | |
120 | |
121 canvas->DrawBitmapInt(*sad_tab_bitmap_, icon_bounds_.x(), icon_bounds_.y()); | |
122 | |
123 canvas->DrawStringInt(title_, *title_font_, kTitleColor, | |
124 title_bounds_.x(), title_bounds_.y(), | |
125 title_bounds_.width(), title_bounds_.height(), | |
126 gfx::Canvas::TEXT_ALIGN_CENTER); | |
127 | |
128 canvas->DrawStringInt(message_, *message_font_, | |
129 kMessageColor, message_bounds_.x(), message_bounds_.y(), | |
130 message_bounds_.width(), message_bounds_.height(), | |
131 kMessageFlags); | |
132 | |
133 if (learn_more_link_ != NULL) { | |
134 learn_more_link_->SetBounds( | |
135 learn_more_bounds_.x(), learn_more_bounds_.y(), | |
136 learn_more_bounds_.width(), learn_more_bounds_.height()); | |
137 } | |
138 if (feedback_link_ != NULL) { | |
139 feedback_link_->SetBounds( | |
140 feedback_bounds_.x(), feedback_bounds_.y(), | |
141 feedback_bounds_.width(), feedback_bounds_.height()); | |
142 } | |
143 } | |
144 | |
145 void SadTabView::Layout() { | |
146 int icon_width = sad_tab_bitmap_->width(); | |
147 int icon_height = sad_tab_bitmap_->height(); | |
148 int icon_x = (width() - icon_width) / 2; | |
149 int icon_y = ((height() - icon_height) / 2) + kSadTabOffset; | |
150 icon_bounds_.SetRect(icon_x, icon_y, icon_width, icon_height); | |
151 | |
152 int title_x = (width() - title_width_) / 2; | |
153 int title_y = icon_bounds_.bottom() + kIconTitleSpacing; | |
154 int title_height = title_font_->GetHeight(); | |
155 title_bounds_.SetRect(title_x, title_y, title_width_, title_height); | |
156 | |
157 int message_width = static_cast<int>(width() * kMessageSize); | |
158 int message_height = 0; | |
159 gfx::CanvasSkia::SizeStringInt(message_, | |
160 *message_font_, &message_width, | |
161 &message_height, kMessageFlags); | |
162 int message_x = (width() - message_width) / 2; | |
163 int message_y = title_bounds_.bottom() + kTitleMessageSpacing; | |
164 message_bounds_.SetRect(message_x, message_y, message_width, message_height); | |
165 int bottom = message_bounds_.bottom(); | |
166 | |
167 if (learn_more_link_ != NULL) { | |
168 gfx::Size sz = learn_more_link_->GetPreferredSize(); | |
169 gfx::Insets insets = learn_more_link_->GetInsets(); | |
170 learn_more_bounds_.SetRect((width() - sz.width()) / 2, | |
171 bottom + kTitleMessageSpacing - insets.top(), | |
172 sz.width(), | |
173 sz.height()); | |
174 bottom = learn_more_bounds_.bottom(); | |
175 } | |
176 | |
177 if (feedback_link_ != NULL) { | |
178 gfx::Size sz = feedback_link_->GetPreferredSize(); | |
179 gfx::Insets insets = feedback_link_->GetInsets(); | |
180 feedback_bounds_.SetRect((width() - sz.width()) / 2, | |
181 bottom + kTitleMessageSpacing - insets.top(), | |
182 sz.width(), | |
183 sz.height()); | |
184 } | |
185 } | |
186 | |
187 void SadTabView::LinkClicked(views::Link* source, int event_flags) { | 65 void SadTabView::LinkClicked(views::Link* source, int event_flags) { |
188 if (tab_contents_ != NULL && source == learn_more_link_) { | 66 if (tab_contents_ != NULL && source == help_link_) { |
189 GURL help_url = | 67 GURL help_url = |
190 google_util::AppendGoogleLocaleParam(GURL(kind_ == CRASHED ? | 68 google_util::AppendGoogleLocaleParam(GURL(kind_ == CRASHED ? |
191 chrome::kCrashReasonURL : | 69 chrome::kCrashReasonURL : |
192 chrome::kKillReasonURL)); | 70 chrome::kKillReasonURL)); |
193 tab_contents_->OpenURL(help_url, GURL(), CURRENT_TAB, PageTransition::LINK); | 71 tab_contents_->OpenURL(help_url, GURL(), CURRENT_TAB, PageTransition::LINK); |
194 } else if (tab_contents_ != NULL && source == feedback_link_) { | 72 } else if (tab_contents_ != NULL && source == feedback_link_) { |
195 browser::ShowHtmlBugReportView( | 73 browser::ShowHtmlBugReportView( |
196 Browser::GetBrowserForController(&tab_contents_->controller(), NULL), | 74 Browser::GetBrowserForController(&tab_contents_->controller(), NULL), |
197 l10n_util::GetStringUTF8(IDS_KILLED_TAB_FEEDBACK_MESSAGE), | 75 l10n_util::GetStringUTF8(IDS_KILLED_TAB_FEEDBACK_MESSAGE), |
198 userfeedback::ChromeOsData_ChromeOsCategory_CRASH); | 76 userfeedback::ChromeOsData_ChromeOsCategory_CRASH); |
199 } | 77 } |
200 } | 78 } |
79 | |
80 void SadTabView::Layout() { | |
81 // Specify the maximum message width explicitly. | |
82 message_->SizeToFit(static_cast<int>(width() * kMessageSize)); | |
83 // Layout centers |contents_view_| and |message_view_| in the SadTabView. | |
84 View::Layout(); | |
85 // Run |message_view_| layout explicity, to center |message_|. | |
86 message_view_->Layout(); | |
Peter Kasting
2011/08/31 17:28:34
Why is this necessary? Shouldn't the Layout() cal
msw
2011/09/01 03:30:49
I'm glad sky joined the review... The new GridLayo
| |
87 } | |
88 | |
89 void SadTabView::ViewHierarchyChanged(bool is_add, | |
90 views::View* parent, | |
91 views::View* child) { | |
92 if (child != this || !is_add) | |
93 return; | |
94 | |
95 // Center the actual contents in |contents_view_| within the SadTabView. | |
96 SetLayoutManager(new views::CenterLayout()); | |
97 contents_view_ = new views::View(); | |
98 contents_view_->SetLayoutManager( | |
99 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, kSpacing)); | |
100 AddChildView(contents_view_); | |
101 | |
102 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
Peter Kasting
2011/08/31 17:28:34
Nit: Push each of these down to just above their f
msw
2011/09/01 03:30:49
Done.
| |
103 const gfx::Font& base_font = rb.GetFont(ResourceBundle::BaseFont); | |
104 | |
105 int image = (kind_ == CRASHED) ? IDR_SAD_TAB : IDR_KILLED_TAB; | |
Peter Kasting
2011/08/31 17:28:34
Nit: Just roll this into the call below and avoid
msw
2011/09/01 03:30:49
Done.
| |
106 image_ = new views::ImageView(); | |
107 image_->SetImage(rb.GetBitmapNamed(image)); | |
108 contents_view_->AddChildView(image_); | |
109 | |
110 int title = (kind_ == CRASHED) ? IDS_SAD_TAB_TITLE : IDS_KILLED_TAB_TITLE; | |
111 title_ = new views::Label(UTF16ToWide(l10n_util::GetStringUTF16(title))); | |
112 title_->SetFont(base_font.DeriveFont(kTitleFontSizeDelta, gfx::Font::BOLD)); | |
113 title_->SetColor(kTextColor); | |
114 contents_view_->AddChildView(title_); | |
115 | |
116 int msg = (kind_ == CRASHED) ? IDS_SAD_TAB_MESSAGE : IDS_KILLED_TAB_MESSAGE; | |
117 message_ = new views::Label(UTF16ToWide(l10n_util::GetStringUTF16(msg))); | |
118 message_->SetFont(base_font.DeriveFont(kMessageFontSizeDelta)); | |
119 message_->SetColor(kTextColor); | |
120 message_->SetMultiLine(true); | |
121 // Center the label horizontally for when it's less wide than other views. | |
122 // Otherwise, the box layout will expand the label to the full sad tab width. | |
123 message_view_ = new views::View(); | |
124 message_view_->SetLayoutManager(new views::CenterLayout()); | |
125 message_view_->AddChildView(message_); | |
126 contents_view_->AddChildView(message_view_); | |
127 | |
128 if (tab_contents_) { | |
129 size_t link = (kind_ == CRASHED) ? IDS_SAD_TAB_HELP_LINK : IDS_LEARN_MORE; | |
130 std::wstring help_link(UTF16ToWide(l10n_util::GetStringUTF16(link))); | |
131 help_link_ = new views::Link(help_link); | |
132 help_link_->SetFont(base_font.DeriveFont(kMessageFontSizeDelta)); | |
133 help_link_->SetNormalColor(kTextColor); | |
134 help_link_->set_listener(this); | |
135 | |
136 if (kind_ == CRASHED) { | |
137 // |help_view_| centers |help_contents_view_|. | |
138 help_view_ = new views::View(); | |
139 help_view_->SetLayoutManager(new views::CenterLayout()); | |
140 contents_view_->AddChildView(help_view_); | |
141 | |
142 // |help_contents_view_| lays out [HELP PREFIX][HELP LINK][HELP SUFFIX]. | |
143 help_contents_view_ = new views::View(); | |
144 help_contents_view_->SetLayoutManager( | |
145 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0)); | |
146 help_view_->AddChildView(help_contents_view_); | |
147 | |
148 size_t offset = 0; | |
149 int help = IDS_SAD_TAB_HELP_MESSAGE; | |
150 string16 help_text(l10n_util::GetStringFUTF16(help, string16(), &offset)); | |
151 | |
152 help_prefix_ = new views::Label(UTF16ToWide(help_text.substr(0, offset))); | |
153 help_prefix_->SetFont(base_font.DeriveFont(kMessageFontSizeDelta)); | |
154 help_prefix_->SetColor(kTextColor); | |
155 help_contents_view_->AddChildView(help_prefix_); | |
156 | |
157 help_contents_view_->AddChildView(help_link_); | |
158 | |
159 help_suffix_ = new views::Label(UTF16ToWide(help_text.substr(offset))); | |
160 help_suffix_->SetFont(base_font.DeriveFont(kMessageFontSizeDelta)); | |
161 help_suffix_->SetColor(kTextColor); | |
162 help_contents_view_->AddChildView(help_suffix_); | |
163 } else { | |
164 contents_view_->AddChildView(help_link_); | |
165 | |
166 feedback_link_ = new views::Link(UTF16ToWide( | |
167 l10n_util::GetStringUTF16(IDS_KILLED_TAB_FEEDBACK_LINK))); | |
168 feedback_link_->SetFont(base_font.DeriveFont(kMessageFontSizeDelta)); | |
169 feedback_link_->SetNormalColor(kTextColor); | |
170 feedback_link_->set_listener(this); | |
171 contents_view_->AddChildView(feedback_link_); | |
172 } | |
173 } | |
174 } | |
175 | |
176 void SadTabView::OnPaint(gfx::Canvas* canvas) { | |
177 if (!painted_) { | |
178 // User actually saw the error, keep track for user experience stats. | |
179 UMA_HISTOGRAM_COUNTS("SadTab.Displayed", kind_); | |
180 painted_ = true; | |
181 } | |
182 View::OnPaint(canvas); | |
183 } | |
OLD | NEW |