BookmarkManager: Fix 'new folder text field size changes on clicking it' issue.
[chromium-blink-merge.git] / chrome / browser / ui / views / sad_tab_view.cc
blob4a4821bd258788c0871305056f128e57a176f46a
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.
5 #include "chrome/browser/ui/views/sad_tab_view.h"
7 #include <string>
9 #include "base/metrics/histogram.h"
10 #include "chrome/browser/ui/browser_finder.h"
11 #include "chrome/browser/ui/chrome_pages.h"
12 #include "chrome/common/url_constants.h"
13 #include "chrome/grit/generated_resources.h"
14 #include "components/feedback/feedback_util.h"
15 #include "content/public/browser/navigation_controller.h"
16 #include "content/public/browser/web_contents.h"
17 #include "grit/components_strings.h"
18 #include "ui/base/l10n/l10n_util.h"
19 #include "ui/base/resource/resource_bundle.h"
20 #include "ui/gfx/paint_vector_icon.h"
21 #include "ui/gfx/vector_icons_public.h"
22 #include "ui/native_theme/common_theme.h"
23 #include "ui/native_theme/native_theme.h"
24 #include "ui/views/background.h"
25 #include "ui/views/controls/button/blue_button.h"
26 #include "ui/views/controls/image_view.h"
27 #include "ui/views/controls/label.h"
28 #include "ui/views/controls/link.h"
29 #include "ui/views/layout/grid_layout.h"
30 #include "ui/views/layout/layout_constants.h"
31 #include "ui/views/widget/widget.h"
33 #if defined(OS_CHROMEOS)
34 #include "chrome/browser/memory/oom_memory_details.h"
35 #endif
37 using content::OpenURLParams;
38 using content::WebContents;
40 namespace {
42 const int kMaxContentWidth = 600;
43 const int kMinColumnWidth = 120;
44 const char kCategoryTagCrash[] = "Crash";
45 const int kCrashesBeforeFeedbackIsDisplayed = 1;
47 void RecordKillCreated() {
48 static int killed = 0;
49 killed++;
50 UMA_HISTOGRAM_CUSTOM_COUNTS(
51 "Tabs.SadTab.KillCreated", killed, 1, 1000, 50);
54 void RecordKillDisplayed() {
55 static int killed = 0;
56 killed++;
57 UMA_HISTOGRAM_CUSTOM_COUNTS(
58 "Tabs.SadTab.KillDisplayed", killed, 1, 1000, 50);
61 #if defined(OS_CHROMEOS)
62 void RecordKillCreatedOOM() {
63 static int oom_killed = 0;
64 oom_killed++;
65 UMA_HISTOGRAM_CUSTOM_COUNTS(
66 "Tabs.SadTab.KillCreated.OOM", oom_killed, 1, 1000, 50);
69 void RecordKillDisplayedOOM() {
70 static int oom_killed = 0;
71 oom_killed++;
72 UMA_HISTOGRAM_CUSTOM_COUNTS(
73 "Tabs.SadTab.KillDisplayed.OOM", oom_killed, 1, 1000, 50);
75 #endif
77 } // namespace
79 int SadTabView::total_crashes_ = 0;
81 SadTabView::SadTabView(WebContents* web_contents, chrome::SadTabKind kind)
82 : web_contents_(web_contents),
83 kind_(kind),
84 painted_(false),
85 message_(nullptr),
86 help_link_(nullptr),
87 action_button_(nullptr),
88 title_(nullptr),
89 help_message_(nullptr) {
90 DCHECK(web_contents);
92 // These stats should use the same counting approach and bucket size used for
93 // tab discard events in memory::OomPriorityManager so they can be directly
94 // compared.
95 // TODO(jamescook): Maybe track time between sad tabs?
96 total_crashes_++;
98 switch (kind_) {
99 case chrome::SAD_TAB_KIND_CRASHED: {
100 static int crashed = 0;
101 crashed++;
102 UMA_HISTOGRAM_CUSTOM_COUNTS(
103 "Tabs.SadTab.CrashCreated", crashed, 1, 1000, 50);
104 break;
106 case chrome::SAD_TAB_KIND_KILLED: {
107 RecordKillCreated();
108 LOG(WARNING) << "Tab Killed: "
109 << web_contents->GetURL().GetOrigin().spec();
110 break;
112 #if defined(OS_CHROMEOS)
113 case chrome::SAD_TAB_KIND_KILLED_BY_OOM: {
114 RecordKillCreated();
115 RecordKillCreatedOOM();
116 const std::string spec = web_contents->GetURL().GetOrigin().spec();
117 memory::OomMemoryDetails::Log(
118 "Tab OOM-Killed Memory details: " + spec + ", ", base::Closure());
119 break;
121 #endif
124 // Set the background color.
125 set_background(
126 views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor(
127 ui::NativeTheme::kColorId_DialogBackground)));
129 views::GridLayout* layout = new views::GridLayout(this);
130 SetLayoutManager(layout);
132 const int column_set_id = 0;
133 views::ColumnSet* columns = layout->AddColumnSet(column_set_id);
134 columns->AddPaddingColumn(1, views::kPanelSubVerticalSpacing);
135 columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::LEADING, 0,
136 views::GridLayout::USE_PREF, 0, kMinColumnWidth);
137 columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::LEADING, 0,
138 views::GridLayout::USE_PREF, 0, kMinColumnWidth);
139 columns->AddPaddingColumn(1, views::kPanelSubVerticalSpacing);
141 views::ImageView* image = new views::ImageView();
143 SkColor icon_color;
144 ui::CommonThemeGetSystemColor(ui::NativeTheme::kColorId_ChromeIconGrey,
145 &icon_color);
146 image->SetImage(
147 gfx::CreateVectorIcon(gfx::VectorIconId::CRASHED_TAB, 48, icon_color));
148 layout->AddPaddingRow(1, views::kPanelVerticalSpacing);
149 layout->StartRow(0, column_set_id);
150 layout->AddView(image, 2, 1);
152 title_ = CreateLabel(l10n_util::GetStringUTF16(IDS_SAD_TAB_TITLE));
153 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
154 title_->SetFontList(rb.GetFontList(ui::ResourceBundle::LargeFont));
155 title_->SetMultiLine(true);
156 title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
157 layout->StartRowWithPadding(0, column_set_id, 0,
158 views::kPanelVerticalSpacing);
159 layout->AddView(title_, 2, 1);
161 const SkColor text_color = GetNativeTheme()->GetSystemColor(
162 ui::NativeTheme::kColorId_LabelDisabledColor);
164 int message_id = IDS_SAD_TAB_MESSAGE;
165 #if defined(OS_CHROMEOS)
166 if (kind_ == chrome::SAD_TAB_KIND_KILLED_BY_OOM)
167 message_id = IDS_KILLED_TAB_BY_OOM_MESSAGE;
168 #endif
170 message_ = CreateLabel(l10n_util::GetStringUTF16(message_id));
172 message_->SetMultiLine(true);
173 message_->SetEnabledColor(text_color);
174 message_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
175 message_->SetLineHeight(views::kPanelSubVerticalSpacing);
177 layout->StartRowWithPadding(0, column_set_id, 0, views::kPanelVertMargin);
178 layout->AddView(message_, 2, 1, views::GridLayout::LEADING,
179 views::GridLayout::LEADING);
181 if (web_contents_) {
182 // In the cases of multiple crashes in a session the 'Feedback' button
183 // replaces the 'Reload' button as primary action.
184 int button_type = total_crashes_ > kCrashesBeforeFeedbackIsDisplayed ?
185 SAD_TAB_BUTTON_FEEDBACK : SAD_TAB_BUTTON_RELOAD;
186 action_button_ = new views::BlueButton(this,
187 l10n_util::GetStringUTF16(button_type == SAD_TAB_BUTTON_FEEDBACK
188 ? IDS_CRASHED_TAB_FEEDBACK_LINK
189 : IDS_SAD_TAB_RELOAD_LABEL));
190 action_button_->set_tag(button_type);
191 help_link_ =
192 CreateLink(l10n_util::GetStringUTF16(IDS_LEARN_MORE), text_color);
193 layout->StartRowWithPadding(0, column_set_id, 0,
194 views::kPanelVerticalSpacing);
195 layout->AddView(help_link_, 1, 1, views::GridLayout::LEADING,
196 views::GridLayout::CENTER);
197 layout->AddView(action_button_, 1, 1, views::GridLayout::TRAILING,
198 views::GridLayout::LEADING);
200 layout->AddPaddingRow(2, views::kPanelSubVerticalSpacing);
203 SadTabView::~SadTabView() {}
205 void SadTabView::LinkClicked(views::Link* source, int event_flags) {
206 DCHECK(web_contents_);
207 OpenURLParams params(GURL(total_crashes_ > kCrashesBeforeFeedbackIsDisplayed ?
208 chrome::kCrashReasonFeedbackDisplayedURL :
209 chrome::kCrashReasonURL), content::Referrer(),
210 CURRENT_TAB, ui::PAGE_TRANSITION_LINK, false);
211 web_contents_->OpenURL(params);
214 void SadTabView::ButtonPressed(views::Button* sender,
215 const ui::Event& event) {
216 DCHECK(web_contents_);
217 DCHECK_EQ(action_button_, sender);
219 if (action_button_->tag() == SAD_TAB_BUTTON_FEEDBACK) {
220 chrome::ShowFeedbackPage(
221 chrome::FindBrowserWithWebContents(web_contents_),
222 l10n_util::GetStringUTF8(kind_ == chrome::SAD_TAB_KIND_CRASHED ?
223 IDS_CRASHED_TAB_FEEDBACK_MESSAGE : IDS_KILLED_TAB_FEEDBACK_MESSAGE),
224 std::string(kCategoryTagCrash));
225 } else {
226 web_contents_->GetController().Reload(true);
230 void SadTabView::Layout() {
231 // Specify the maximum message width explicitly.
232 const int max_width =
233 std::min(width() - views::kPanelSubVerticalSpacing * 2, kMaxContentWidth);
234 message_->SizeToFit(max_width);
235 title_->SizeToFit(max_width);
237 if (help_message_ != nullptr)
238 help_message_->SizeToFit(max_width);
240 View::Layout();
243 void SadTabView::OnPaint(gfx::Canvas* canvas) {
244 if (!painted_) {
245 // These stats should use the same counting approach and bucket size used
246 // for tab discard events in memory::OomPriorityManager so they can be
247 // directly compared.
248 switch (kind_) {
249 case chrome::SAD_TAB_KIND_CRASHED: {
250 static int crashed = 0;
251 UMA_HISTOGRAM_CUSTOM_COUNTS(
252 "Tabs.SadTab.CrashDisplayed", ++crashed, 1, 1000, 50);
253 break;
255 case chrome::SAD_TAB_KIND_KILLED:
256 RecordKillDisplayed();
257 break;
258 #if defined(OS_CHROMEOS)
259 case chrome::SAD_TAB_KIND_KILLED_BY_OOM:
260 RecordKillDisplayed();
261 RecordKillDisplayedOOM();
262 break;
263 #endif
265 painted_ = true;
267 View::OnPaint(canvas);
270 void SadTabView::Show() {
271 views::Widget::InitParams sad_tab_params(
272 views::Widget::InitParams::TYPE_CONTROL);
274 // It is not possible to create a native_widget_win that has no parent in
275 // and later re-parent it.
276 // TODO(avi): This is a cheat. Can this be made cleaner?
277 sad_tab_params.parent = web_contents_->GetNativeView();
279 set_owned_by_client();
281 views::Widget* sad_tab = new views::Widget;
282 sad_tab->Init(sad_tab_params);
283 sad_tab->SetContentsView(this);
285 views::Widget::ReparentNativeView(sad_tab->GetNativeView(),
286 web_contents_->GetNativeView());
287 gfx::Rect bounds = web_contents_->GetContainerBounds();
288 sad_tab->SetBounds(gfx::Rect(bounds.size()));
291 void SadTabView::Close() {
292 if (GetWidget())
293 GetWidget()->Close();
296 views::Label* SadTabView::CreateLabel(const base::string16& text) {
297 views::Label* label = new views::Label(text);
298 label->SetBackgroundColor(background()->get_color());
299 return label;
302 views::Link* SadTabView::CreateLink(const base::string16& text,
303 const SkColor& color) {
304 views::Link* link = new views::Link(text);
305 link->SetBackgroundColor(background()->get_color());
306 link->SetEnabledColor(color);
307 link->set_listener(this);
308 return link;
311 namespace chrome {
313 SadTab* SadTab::Create(content::WebContents* web_contents,
314 SadTabKind kind) {
315 return new SadTabView(web_contents, kind);
318 } // namespace chrome