OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 <string> | 7 #include <string> |
8 | 8 |
9 #include "base/metrics/field_trial.h" | 9 #include "base/metrics/field_trial.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
12 #include "chrome/browser/ui/browser.h" | 12 #include "chrome/browser/ui/browser.h" |
13 #include "chrome/browser/ui/browser_finder.h" | 13 #include "chrome/browser/ui/browser_finder.h" |
14 #include "chrome/browser/ui/chrome_pages.h" | 14 #include "chrome/browser/ui/chrome_pages.h" |
15 #include "chrome/common/url_constants.h" | 15 #include "chrome/common/url_constants.h" |
16 #include "chrome/grit/generated_resources.h" | 16 #include "chrome/grit/generated_resources.h" |
17 #include "components/feedback/feedback_util.h" | 17 #include "components/feedback/feedback_util.h" |
18 #include "content/public/browser/navigation_controller.h" | 18 #include "content/public/browser/navigation_controller.h" |
19 #include "content/public/browser/web_contents.h" | 19 #include "content/public/browser/web_contents.h" |
20 #include "grit/components_strings.h" | 20 #include "grit/components_strings.h" |
21 #include "grit/theme_resources.h" | 21 #include "grit/theme_resources.h" |
22 #include "ui/base/l10n/l10n_util.h" | 22 #include "ui/base/l10n/l10n_util.h" |
23 #include "ui/base/resource/resource_bundle.h" | 23 #include "ui/base/resource/resource_bundle.h" |
24 #include "ui/views/background.h" | 24 #include "ui/views/background.h" |
| 25 #include "ui/views/controls/button/blue_button.h" |
25 #include "ui/views/controls/button/label_button.h" | 26 #include "ui/views/controls/button/label_button.h" |
26 #include "ui/views/controls/button/label_button_border.h" | 27 #include "ui/views/controls/button/label_button_border.h" |
27 #include "ui/views/controls/image_view.h" | 28 #include "ui/views/controls/image_view.h" |
28 #include "ui/views/controls/label.h" | 29 #include "ui/views/controls/label.h" |
29 #include "ui/views/controls/link.h" | 30 #include "ui/views/controls/link.h" |
| 31 #include "ui/views/controls/styled_label.h" |
30 #include "ui/views/layout/grid_layout.h" | 32 #include "ui/views/layout/grid_layout.h" |
| 33 #include "ui/views/layout/layout_constants.h" |
31 #include "ui/views/widget/widget.h" | 34 #include "ui/views/widget/widget.h" |
32 | 35 |
33 using content::OpenURLParams; | 36 using content::OpenURLParams; |
34 using content::WebContents; | 37 using content::WebContents; |
35 | 38 |
36 namespace { | 39 namespace { |
37 | 40 |
38 const int kPadding = 20; | 41 const int kMaxContentWidth = 600; |
39 const float kMessageSize = 0.65f; | 42 const int kMinColumnWidth = 120; |
40 const SkColor kTextColor = SK_ColorWHITE; | |
41 const SkColor kCrashColor = SkColorSetRGB(35, 48, 64); | |
42 const SkColor kKillColor = SkColorSetRGB(57, 48, 88); | |
43 | |
44 const char kCategoryTagCrash[] = "Crash"; | 43 const char kCategoryTagCrash[] = "Crash"; |
45 | 44 |
46 } // namespace | 45 } // namespace |
47 | 46 |
48 SadTabView::SadTabView(WebContents* web_contents, chrome::SadTabKind kind) | 47 SadTabView::SadTabView(WebContents* web_contents, chrome::SadTabKind kind) |
49 : web_contents_(web_contents), | 48 : web_contents_(web_contents), |
50 kind_(kind), | 49 kind_(kind), |
51 painted_(false), | 50 painted_(false), |
52 message_(NULL), | 51 message_(nullptr), |
53 help_link_(NULL), | 52 help_link_(nullptr), |
54 feedback_link_(NULL), | 53 feedback_link_(nullptr), |
55 reload_button_(NULL) { | 54 reload_button_(nullptr), |
| 55 title_(nullptr), |
| 56 help_message_(nullptr) { |
56 DCHECK(web_contents); | 57 DCHECK(web_contents); |
57 | 58 |
58 // Sometimes the user will never see this tab, so keep track of the total | 59 // Sometimes the user will never see this tab, so keep track of the total |
59 // number of creation events to compare to display events. | 60 // number of creation events to compare to display events. |
60 // TODO(jamescook): Remove this after R20 stable. Keep it for now so we can | 61 // TODO(jamescook): Remove this after R20 stable. Keep it for now so we can |
61 // compare R20 to earlier versions. | 62 // compare R20 to earlier versions. |
62 UMA_HISTOGRAM_COUNTS("SadTab.Created", kind_); | 63 UMA_HISTOGRAM_COUNTS("SadTab.Created", kind_); |
63 | 64 |
64 // These stats should use the same counting approach and bucket size used for | 65 // These stats should use the same counting approach and bucket size used for |
65 // tab discard events in chromeos::OomPriorityManager so they can be | 66 // tab discard events in chromeos::OomPriorityManager so they can be |
(...skipping 12 matching lines...) Expand all Loading... |
78 killed++; | 79 killed++; |
79 UMA_HISTOGRAM_CUSTOM_COUNTS( | 80 UMA_HISTOGRAM_CUSTOM_COUNTS( |
80 "Tabs.SadTab.KillCreated", killed, 1, 1000, 50); | 81 "Tabs.SadTab.KillCreated", killed, 1, 1000, 50); |
81 break; | 82 break; |
82 } | 83 } |
83 default: | 84 default: |
84 NOTREACHED(); | 85 NOTREACHED(); |
85 } | 86 } |
86 | 87 |
87 // Set the background color. | 88 // Set the background color. |
88 set_background(views::Background::CreateSolidBackground( | 89 set_background( |
89 (kind_ == chrome::SAD_TAB_KIND_CRASHED) ? kCrashColor : kKillColor)); | 90 views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor( |
| 91 ui::NativeTheme::kColorId_DialogBackground))); |
90 | 92 |
91 views::GridLayout* layout = new views::GridLayout(this); | 93 views::GridLayout* layout = new views::GridLayout(this); |
92 SetLayoutManager(layout); | 94 SetLayoutManager(layout); |
93 | 95 |
94 const int column_set_id = 0; | 96 const int column_set_id = 0; |
95 views::ColumnSet* columns = layout->AddColumnSet(column_set_id); | 97 views::ColumnSet* columns = layout->AddColumnSet(column_set_id); |
96 columns->AddPaddingColumn(1, kPadding); | 98 columns->AddPaddingColumn(1, views::kPanelSubVerticalSpacing); |
97 columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, | 99 columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::LEADING, 0, |
98 0, views::GridLayout::USE_PREF, 0, 0); | 100 views::GridLayout::USE_PREF, 0, kMinColumnWidth); |
99 columns->AddPaddingColumn(1, kPadding); | 101 columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::LEADING, 0, |
| 102 views::GridLayout::USE_PREF, 0, kMinColumnWidth); |
| 103 columns->AddPaddingColumn(1, views::kPanelSubVerticalSpacing); |
100 | 104 |
101 views::ImageView* image = new views::ImageView(); | 105 views::ImageView* image = new views::ImageView(); |
102 image->SetImage(ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( | 106 image->SetImage( |
103 (kind_ == chrome::SAD_TAB_KIND_CRASHED) ? IDR_SAD_TAB : IDR_KILLED_TAB)); | 107 ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(IDR_SAD_TAB)); |
104 layout->StartRowWithPadding(0, column_set_id, 1, kPadding); | 108 layout->AddPaddingRow(1, views::kPanelVerticalSpacing); |
105 layout->AddView(image); | 109 layout->StartRow(0, column_set_id); |
| 110 layout->AddView(image, 2, 1); |
106 | 111 |
107 views::Label* title = CreateLabel(l10n_util::GetStringUTF16( | 112 const bool is_crashed_type = kind_ == chrome::SAD_TAB_KIND_CRASHED; |
108 (kind_ == chrome::SAD_TAB_KIND_CRASHED) ? | |
109 IDS_SAD_TAB_TITLE : IDS_KILLED_TAB_TITLE)); | |
110 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 113 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
111 title->SetFontList(rb.GetFontList(ui::ResourceBundle::MediumFont)); | 114 |
112 layout->StartRowWithPadding(0, column_set_id, 0, kPadding); | 115 title_ = CreateLabel(l10n_util::GetStringUTF16( |
113 layout->AddView(title); | 116 is_crashed_type ? IDS_SAD_TAB_TITLE : IDS_KILLED_TAB_TITLE)); |
| 117 title_->SetFontList(rb.GetFontList(ui::ResourceBundle::LargeFont)); |
| 118 title_->SetMultiLine(true); |
| 119 title_->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
| 120 layout->StartRowWithPadding(0, column_set_id, 0, |
| 121 views::kPanelVerticalSpacing); |
| 122 layout->AddView(title_, 2, 1); |
| 123 |
| 124 const SkColor text_color = GetNativeTheme()->GetSystemColor( |
| 125 ui::NativeTheme::kColorId_LabelDisabledColor); |
114 | 126 |
115 message_ = CreateLabel(l10n_util::GetStringUTF16( | 127 message_ = CreateLabel(l10n_util::GetStringUTF16( |
116 (kind_ == chrome::SAD_TAB_KIND_CRASHED) ? | 128 is_crashed_type ? IDS_SAD_TAB_MESSAGE : IDS_KILLED_TAB_MESSAGE)); |
117 IDS_SAD_TAB_MESSAGE : IDS_KILLED_TAB_MESSAGE)); | |
118 message_->SetMultiLine(true); | 129 message_->SetMultiLine(true); |
119 layout->StartRowWithPadding(0, column_set_id, 0, kPadding); | 130 message_->SetEnabledColor(text_color); |
120 layout->AddView(message_); | 131 message_->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
| 132 message_->SetLineHeight(views::kPanelSubVerticalSpacing); |
| 133 |
| 134 layout->StartRowWithPadding(0, column_set_id, 0, views::kPanelVertMargin); |
| 135 layout->AddView(message_, 2, 1, views::GridLayout::LEADING, |
| 136 views::GridLayout::LEADING); |
121 | 137 |
122 if (web_contents_) { | 138 if (web_contents_) { |
123 layout->StartRowWithPadding(0, column_set_id, 0, kPadding); | 139 reload_button_ = new views::BlueButton( |
124 reload_button_ = new views::LabelButton( | 140 this, l10n_util::GetStringUTF16(IDS_SAD_TAB_RELOAD_LABEL)); |
125 this, | |
126 l10n_util::GetStringUTF16(IDS_SAD_TAB_RELOAD_LABEL)); | |
127 reload_button_->SetStyle(views::Button::STYLE_BUTTON); | |
128 // Always render the reload button with chrome style borders; never rely on | |
129 // native styles. | |
130 reload_button_->SetBorder(scoped_ptr<views::Border>( | |
131 new views::LabelButtonBorder(reload_button_->style()))); | |
132 layout->AddView(reload_button_); | |
133 | 141 |
134 help_link_ = CreateLink(l10n_util::GetStringUTF16( | 142 if (is_crashed_type) { |
135 (kind_ == chrome::SAD_TAB_KIND_CRASHED) ? | |
136 IDS_SAD_TAB_HELP_LINK : IDS_LEARN_MORE)); | |
137 | |
138 if (kind_ == chrome::SAD_TAB_KIND_CRASHED) { | |
139 size_t offset = 0; | 143 size_t offset = 0; |
140 base::string16 help_text( | 144 base::string16 help_text( |
141 l10n_util::GetStringFUTF16(IDS_SAD_TAB_HELP_MESSAGE, | 145 l10n_util::GetStringFUTF16(IDS_SAD_TAB_HELP_MESSAGE, |
142 base::string16(), &offset)); | 146 base::string16(), &offset)); |
143 views::Label* help_prefix = CreateLabel(help_text.substr(0, offset)); | |
144 views::Label* help_suffix = CreateLabel(help_text.substr(offset)); | |
145 | 147 |
146 const int help_column_set_id = 1; | 148 base::string16 link_text = |
147 views::ColumnSet* help_columns = layout->AddColumnSet(help_column_set_id); | 149 l10n_util::GetStringUTF16(IDS_SAD_TAB_HELP_LINK); |
148 help_columns->AddPaddingColumn(1, kPadding); | |
149 // Center three middle columns for the help's [prefix][link][suffix]. | |
150 for (size_t column = 0; column < 3; column++) | |
151 help_columns->AddColumn(views::GridLayout::CENTER, | |
152 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); | |
153 help_columns->AddPaddingColumn(1, kPadding); | |
154 | 150 |
155 layout->StartRowWithPadding(0, help_column_set_id, 0, kPadding); | 151 base::string16 help_prefix = help_text.substr(0, offset); |
156 layout->AddView(help_prefix); | 152 base::string16 help_suffix = help_text.substr(offset); |
157 layout->AddView(help_link_); | 153 base::string16 help_message_string = help_prefix; |
158 layout->AddView(help_suffix); | 154 help_message_string.append(link_text).append(help_suffix); |
| 155 |
| 156 help_message_ = new views::StyledLabel(help_message_string, this); |
| 157 |
| 158 views::StyledLabel::RangeStyleInfo link_style = |
| 159 views::StyledLabel::RangeStyleInfo::CreateForLink(); |
| 160 link_style.font_style = gfx::Font::UNDERLINE; |
| 161 link_style.color = text_color; |
| 162 |
| 163 views::StyledLabel::RangeStyleInfo normal_style = |
| 164 views::StyledLabel::RangeStyleInfo(); |
| 165 normal_style.color = text_color; |
| 166 |
| 167 help_message_->SetDefaultStyle(normal_style); |
| 168 help_message_->SetLineHeight(views::kPanelSubVerticalSpacing); |
| 169 |
| 170 help_message_->AddStyleRange( |
| 171 gfx::Range(help_prefix.length(), |
| 172 help_prefix.length() + link_text.length()), |
| 173 link_style); |
| 174 |
| 175 layout->StartRowWithPadding(0, column_set_id, 0, views::kPanelVertMargin); |
| 176 layout->AddView(help_message_, 2, 1, views::GridLayout::LEADING, |
| 177 views::GridLayout::TRAILING); |
| 178 layout->StartRowWithPadding(0, column_set_id, 0, |
| 179 views::kPanelVerticalSpacing); |
| 180 layout->SkipColumns(1); |
159 } else { | 181 } else { |
160 layout->StartRowWithPadding(0, column_set_id, 0, kPadding); | 182 feedback_link_ = CreateLink( |
161 layout->AddView(help_link_); | 183 l10n_util::GetStringUTF16(IDS_KILLED_TAB_FEEDBACK_LINK), text_color); |
| 184 feedback_link_->SetLineHeight(views::kPanelSubVerticalSpacing); |
| 185 feedback_link_->SetMultiLine(true); |
| 186 feedback_link_->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
162 | 187 |
163 feedback_link_ = CreateLink( | 188 layout->StartRowWithPadding(0, column_set_id, 0, |
164 l10n_util::GetStringUTF16(IDS_KILLED_TAB_FEEDBACK_LINK)); | 189 views::kPanelSubVerticalSpacing); |
165 layout->StartRowWithPadding(0, column_set_id, 0, kPadding); | 190 layout->AddView(feedback_link_, 2, 1, views::GridLayout::LEADING, |
166 layout->AddView(feedback_link_); | 191 views::GridLayout::LEADING); |
| 192 |
| 193 help_link_ = |
| 194 CreateLink(l10n_util::GetStringUTF16(IDS_LEARN_MORE), text_color); |
| 195 layout->StartRowWithPadding(0, column_set_id, 0, |
| 196 views::kPanelVerticalSpacing); |
| 197 layout->AddView(help_link_, 1, 1, views::GridLayout::LEADING, |
| 198 views::GridLayout::CENTER); |
167 } | 199 } |
| 200 layout->AddView(reload_button_, 1, 1, views::GridLayout::TRAILING, |
| 201 views::GridLayout::LEADING); |
168 } | 202 } |
169 layout->AddPaddingRow(1, kPadding); | 203 layout->AddPaddingRow(2, views::kPanelSubVerticalSpacing); |
170 } | 204 } |
171 | 205 |
172 SadTabView::~SadTabView() {} | 206 SadTabView::~SadTabView() {} |
173 | 207 |
174 void SadTabView::LinkClicked(views::Link* source, int event_flags) { | 208 void SadTabView::LinkClicked(views::Link* source, int event_flags) { |
175 DCHECK(web_contents_); | 209 DCHECK(web_contents_); |
176 if (source == help_link_) { | 210 if (source == help_link_) { |
177 GURL help_url((kind_ == chrome::SAD_TAB_KIND_CRASHED) ? | 211 GURL help_url((kind_ == chrome::SAD_TAB_KIND_CRASHED) ? |
178 chrome::kCrashReasonURL : chrome::kKillReasonURL); | 212 chrome::kCrashReasonURL : chrome::kKillReasonURL); |
179 OpenURLParams params( | 213 OpenURLParams params( |
180 help_url, content::Referrer(), CURRENT_TAB, | 214 help_url, content::Referrer(), CURRENT_TAB, |
181 ui::PAGE_TRANSITION_LINK, false); | 215 ui::PAGE_TRANSITION_LINK, false); |
182 web_contents_->OpenURL(params); | 216 web_contents_->OpenURL(params); |
183 } else if (source == feedback_link_) { | 217 } else if (source == feedback_link_) { |
184 chrome::ShowFeedbackPage( | 218 chrome::ShowFeedbackPage( |
185 chrome::FindBrowserWithWebContents(web_contents_), | 219 chrome::FindBrowserWithWebContents(web_contents_), |
186 l10n_util::GetStringUTF8(IDS_KILLED_TAB_FEEDBACK_MESSAGE), | 220 l10n_util::GetStringUTF8(IDS_KILLED_TAB_FEEDBACK_MESSAGE), |
187 std::string(kCategoryTagCrash)); | 221 std::string(kCategoryTagCrash)); |
188 } | 222 } |
189 } | 223 } |
190 | 224 |
| 225 void SadTabView::StyledLabelLinkClicked(const gfx::Range& range, |
| 226 int event_flags) { |
| 227 LinkClicked(help_link_, event_flags); |
| 228 } |
| 229 |
191 void SadTabView::ButtonPressed(views::Button* sender, | 230 void SadTabView::ButtonPressed(views::Button* sender, |
192 const ui::Event& event) { | 231 const ui::Event& event) { |
193 DCHECK(web_contents_); | 232 DCHECK(web_contents_); |
194 DCHECK_EQ(reload_button_, sender); | 233 DCHECK_EQ(reload_button_, sender); |
195 web_contents_->GetController().Reload(true); | 234 web_contents_->GetController().Reload(true); |
196 } | 235 } |
197 | 236 |
198 void SadTabView::Layout() { | 237 void SadTabView::Layout() { |
199 // Specify the maximum message width explicitly. | 238 // Specify the maximum message width explicitly. |
200 message_->SizeToFit(static_cast<int>(width() * kMessageSize)); | 239 const int max_width = |
| 240 std::min(width() - views::kPanelSubVerticalSpacing * 2, kMaxContentWidth); |
| 241 message_->SizeToFit(max_width); |
| 242 title_->SizeToFit(max_width); |
| 243 |
| 244 if (feedback_link_ != nullptr) |
| 245 feedback_link_->SizeToFit(max_width); |
| 246 |
| 247 if (help_message_ != nullptr) |
| 248 help_message_->SizeToFit(max_width); |
| 249 |
201 View::Layout(); | 250 View::Layout(); |
202 } | 251 } |
203 | 252 |
204 void SadTabView::OnPaint(gfx::Canvas* canvas) { | 253 void SadTabView::OnPaint(gfx::Canvas* canvas) { |
205 if (!painted_) { | 254 if (!painted_) { |
206 // User actually saw the error, keep track for user experience stats. | 255 // User actually saw the error, keep track for user experience stats. |
207 // TODO(jamescook): Remove this after R20 stable. Keep it for now so we can | 256 // TODO(jamescook): Remove this after R20 stable. Keep it for now so we can |
208 // compare R20 to earlier versions. | 257 // compare R20 to earlier versions. |
209 UMA_HISTOGRAM_COUNTS("SadTab.Displayed", kind_); | 258 UMA_HISTOGRAM_COUNTS("SadTab.Displayed", kind_); |
210 | 259 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 } | 303 } |
255 | 304 |
256 void SadTabView::Close() { | 305 void SadTabView::Close() { |
257 if (GetWidget()) | 306 if (GetWidget()) |
258 GetWidget()->Close(); | 307 GetWidget()->Close(); |
259 } | 308 } |
260 | 309 |
261 views::Label* SadTabView::CreateLabel(const base::string16& text) { | 310 views::Label* SadTabView::CreateLabel(const base::string16& text) { |
262 views::Label* label = new views::Label(text); | 311 views::Label* label = new views::Label(text); |
263 label->SetBackgroundColor(background()->get_color()); | 312 label->SetBackgroundColor(background()->get_color()); |
264 label->SetEnabledColor(kTextColor); | |
265 return label; | 313 return label; |
266 } | 314 } |
267 | 315 |
268 views::Link* SadTabView::CreateLink(const base::string16& text) { | 316 views::Link* SadTabView::CreateLink(const base::string16& text, |
| 317 const SkColor& color) { |
269 views::Link* link = new views::Link(text); | 318 views::Link* link = new views::Link(text); |
270 link->SetBackgroundColor(background()->get_color()); | 319 link->SetBackgroundColor(background()->get_color()); |
271 link->SetEnabledColor(kTextColor); | 320 link->SetEnabledColor(color); |
272 link->set_listener(this); | 321 link->set_listener(this); |
273 return link; | 322 return link; |
274 } | 323 } |
275 | 324 |
276 namespace chrome { | 325 namespace chrome { |
277 | 326 |
278 SadTab* SadTab::Create(content::WebContents* web_contents, | 327 SadTab* SadTab::Create(content::WebContents* web_contents, |
279 SadTabKind kind) { | 328 SadTabKind kind) { |
280 return new SadTabView(web_contents, kind); | 329 return new SadTabView(web_contents, kind); |
281 } | 330 } |
282 | 331 |
283 } // namespace chrome | 332 } // namespace chrome |
OLD | NEW |