Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / views / profile_reset_bubble_view.cc
blobcf7c2ff251900adfe0501790000dce36f625a4fa
1 // Copyright 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/views/profile_reset_bubble_view.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/values.h"
9 #include "chrome/app/chrome_command_ids.h"
10 #include "chrome/browser/google/google_util.h"
11 #include "chrome/browser/profile_resetter/profile_reset_global_error.h"
12 #include "chrome/browser/profile_resetter/resettable_settings_snapshot.h"
13 #include "chrome/browser/ui/global_error/global_error_service.h"
14 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
15 #include "chrome/browser/ui/profile_reset_bubble.h"
16 #include "chrome/browser/ui/views/frame/browser_view.h"
17 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
18 #include "chrome/common/url_constants.h"
19 #include "content/public/browser/page_navigator.h"
20 #include "content/public/browser/user_metrics.h"
21 #include "grit/chromium_strings.h"
22 #include "grit/generated_resources.h"
23 #include "grit/theme_resources.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/base/resource/resource_bundle.h"
26 #include "ui/gfx/image/image_skia_operations.h"
27 #include "ui/views/background.h"
28 #include "ui/views/controls/button/checkbox.h"
29 #include "ui/views/controls/button/image_button.h"
30 #include "ui/views/controls/button/label_button.h"
31 #include "ui/views/controls/label.h"
32 #include "ui/views/controls/link.h"
33 #include "ui/views/controls/scroll_view.h"
34 #include "ui/views/controls/separator.h"
35 #include "ui/views/layout/grid_layout.h"
36 #include "ui/views/layout/layout_constants.h"
38 using views::GridLayout;
40 namespace {
42 // Fixed width of the column holding the description label of the bubble.
43 const int kWidthOfDescriptionText = 370;
45 // Margins width for the top rows to compensate for the bottom panel for which
46 // we don't want any margin.
47 const int kMarginWidth = 12;
48 const int kMarginHeight = kMarginWidth;
50 // Width of a colum in the FeedbackView.
51 const int kFeedbackViewColumnWidth = kWidthOfDescriptionText / 2 + kMarginWidth;
53 // Width of the column used to disaplay the help button.
54 const int kHelpButtonColumnWidth = 30;
56 // Width of the reporting checkbox column.
57 const int kReportingCheckboxColumnWidth =
58 kWidthOfDescriptionText + 2 * kMarginWidth;
60 // Full width including all columns.
61 const int kAllColumnsWidth =
62 kReportingCheckboxColumnWidth + kHelpButtonColumnWidth;
64 // Maximum height of the scrollable feedback view.
65 const int kMaxFeedbackViewHeight = 450;
67 // The vertical padding between two values in the feedback view.
68 const int kInterFeedbackValuePadding = 4;
70 // We subtract 2 to account for the natural button padding, and
71 // to bring the separation visually in line with the row separation
72 // height.
73 const int kButtonPadding = views::kRelatedButtonHSpacing - 2;
75 // The color of the background of the sub panel to report current settings.
76 const SkColor kLightGrayBackgroundColor = 0xFFF5F5F5;
78 // This view is used to contain the scrollable contents that are shown the user
79 // to expose what feedback will be sent back to Google.
80 class FeedbackView : public views::View {
81 public:
82 FeedbackView() {}
84 // Setup the layout manager of the Feedback view using the content of the
85 // |feedback| ListValue which contains a list of key/value pairs stored in
86 // DictionaryValues. The key is to be displayed right aligned on the left, and
87 // the value as a left aligned multiline text on the right.
88 void SetupLayoutManager(const base::ListValue& feedback) {
89 RemoveAllChildViews(true);
90 set_background(views::Background::CreateSolidBackground(
91 kLightGrayBackgroundColor));
93 GridLayout* layout = new GridLayout(this);
94 SetLayoutManager(layout);
96 // We only need a single column set for left/right text and middle margin.
97 views::ColumnSet* cs = layout->AddColumnSet(0);
98 cs->AddColumn(GridLayout::FILL, GridLayout::LEADING, 1,
99 GridLayout::FIXED, kFeedbackViewColumnWidth, 0);
100 cs->AddPaddingColumn(0, kMarginWidth);
101 cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
102 GridLayout::FIXED, kFeedbackViewColumnWidth, 0);
103 for (size_t i = 0; i < feedback.GetSize(); ++i) {
104 const base::DictionaryValue* dictionary = NULL;
105 if (!feedback.GetDictionary(i, &dictionary) || !dictionary)
106 continue;
108 base::string16 key;
109 if (!dictionary->GetString("key", &key))
110 continue;
112 base::string16 value;
113 if (!dictionary->GetString("value", &value))
114 continue;
116 // The key is shown on the left, multi-line (required to allow wrapping in
117 // case the key name does not fit), and right-aligned.
118 views::Label* left_text_label = new views::Label(key);
119 left_text_label->SetMultiLine(true);
120 left_text_label->SetEnabledColor(SK_ColorGRAY);
121 left_text_label->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
123 // The value is shown on the right, multi-line, left-aligned.
124 views::Label* right_text_label = new views::Label(value);
125 right_text_label->SetMultiLine(true);
126 right_text_label->SetEnabledColor(SK_ColorDKGRAY);
127 right_text_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
129 layout->StartRow(0, 0);
130 layout->AddView(left_text_label);
131 layout->AddView(right_text_label);
132 layout->AddPaddingRow(0, kInterFeedbackValuePadding);
135 // We need to set our size to our preferred size because our parent is a
136 // scroll view and doesn't know which size to set us to. Also since our
137 // parent scrolls, we are not bound to its size. So our size is based on the
138 // size computed by the our layout manager, which is what
139 // SizeToPreferredSize() does.
140 SizeToPreferredSize();
143 private:
144 DISALLOW_COPY_AND_ASSIGN(FeedbackView);
147 } // namespace
149 // ProfileResetBubbleView ---------------------------------------------------
151 // static
152 ProfileResetBubbleView* ProfileResetBubbleView::ShowBubble(
153 const base::WeakPtr<ProfileResetGlobalError>& global_error,
154 Browser* browser) {
155 views::View* anchor_view =
156 BrowserView::GetBrowserViewForBrowser(browser)->toolbar()->app_menu();
157 ProfileResetBubbleView* reset_bubble = new ProfileResetBubbleView(
158 global_error, anchor_view, browser, browser->profile());
159 views::BubbleDelegateView::CreateBubble(reset_bubble);
160 reset_bubble->StartFade(true);
161 content::RecordAction(base::UserMetricsAction("SettingsResetBubble.Show"));
162 return reset_bubble;
165 ProfileResetBubbleView::~ProfileResetBubbleView() {}
167 views::View* ProfileResetBubbleView::GetInitiallyFocusedView() {
168 return controls_.reset_button;
171 void ProfileResetBubbleView::WindowClosing() {
172 if (global_error_)
173 global_error_->OnBubbleViewDidClose();
176 ProfileResetBubbleView::ProfileResetBubbleView(
177 const base::WeakPtr<ProfileResetGlobalError>& global_error,
178 views::View* anchor_view,
179 content::PageNavigator* navigator,
180 Profile* profile)
181 : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT),
182 navigator_(navigator),
183 profile_(profile),
184 global_error_(global_error),
185 resetting_(false),
186 chose_to_reset_(false),
187 show_help_pane_(false),
188 weak_factory_(this) {
191 void ProfileResetBubbleView::ResetAllChildren() {
192 controls_.Reset();
193 SetLayoutManager(NULL);
194 RemoveAllChildViews(true);
197 void ProfileResetBubbleView::Init() {
198 set_margins(gfx::Insets(kMarginHeight, 0, 0, 0));
199 SetupLayoutManager(true);
202 void ProfileResetBubbleView::SetupLayoutManager(bool report_checked) {
203 ResetAllChildren();
205 base::string16 product_name(
206 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME));
207 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
209 // Bubble title label.
210 views::Label* title_label = new views::Label(
211 l10n_util::GetStringFUTF16(IDS_RESET_BUBBLE_TITLE, product_name),
212 rb.GetFontList(ui::ResourceBundle::BoldFont));
213 title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
215 // Description text label.
216 views::Label* text_label = new views::Label(
217 l10n_util::GetStringFUTF16(IDS_RESET_BUBBLE_TEXT, product_name));
218 text_label->SetMultiLine(true);
219 text_label->SetLineHeight(20);
220 text_label->SetEnabledColor(SK_ColorDKGRAY);
221 text_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
223 // Learn more link.
224 views::Link* learn_more_link = new views::Link(
225 l10n_util::GetStringUTF16(IDS_LEARN_MORE));
226 learn_more_link->SetHorizontalAlignment(gfx::ALIGN_LEFT);
227 learn_more_link->set_listener(this);
228 learn_more_link->SetUnderline(false);
230 // Reset button's name is based on |resetting_| state.
231 int reset_button_string_id = IDS_RESET_PROFILE_SETTINGS_COMMIT_BUTTON;
232 if (resetting_)
233 reset_button_string_id = IDS_RESETTING;
234 controls_.reset_button = new views::LabelButton(
235 this, l10n_util::GetStringUTF16(reset_button_string_id));
236 controls_.reset_button->SetStyle(views::Button::STYLE_BUTTON);
237 controls_.reset_button->SetIsDefault(true);
238 controls_.reset_button->SetFontList(
239 rb.GetFontList(ui::ResourceBundle::BoldFont));
240 controls_.reset_button->SetEnabled(!resetting_);
241 // For the Resetting... text to fit.
242 gfx::Size reset_button_size = controls_.reset_button->GetPreferredSize();
243 reset_button_size.set_width(100);
244 controls_.reset_button->set_min_size(reset_button_size);
246 // No thanks button.
247 controls_.no_thanks_button = new views::LabelButton(
248 this, l10n_util::GetStringUTF16(IDS_NO_THANKS));
249 controls_.no_thanks_button->SetStyle(views::Button::STYLE_BUTTON);
250 controls_.no_thanks_button->SetEnabled(!resetting_);
252 // Checkbox for reporting settings or not.
253 controls_.report_settings_checkbox = new views::Checkbox(
254 l10n_util::GetStringUTF16(IDS_REPORT_BUBBLE_TEXT));
255 controls_.report_settings_checkbox->SetTextColor(
256 views::Button::STATE_NORMAL, SK_ColorGRAY);
257 controls_.report_settings_checkbox->SetChecked(report_checked);
258 controls_.report_settings_checkbox->SetTextMultiLine(true);
259 controls_.report_settings_checkbox->set_background(
260 views::Background::CreateSolidBackground(kLightGrayBackgroundColor));
261 // Have a smaller margin on the right, to have the |controls_.help_button|
262 // closer to the edge.
263 controls_.report_settings_checkbox->set_border(
264 views::Border::CreateSolidSidedBorder(
265 kMarginWidth, kMarginWidth, kMarginWidth, kMarginWidth / 2,
266 kLightGrayBackgroundColor));
268 // Help button to toggle the bottom panel on or off.
269 controls_.help_button = new views::ImageButton(this);
270 const gfx::ImageSkia* help_image = rb.GetImageSkiaNamed(IDR_QUESTION_MARK);
271 color_utils::HSL hsl_shift = { -1, 0, 0.8 };
272 brighter_help_image_ = gfx::ImageSkiaOperations::CreateHSLShiftedImage(
273 *help_image, hsl_shift);
274 controls_.help_button->SetImage(
275 views::Button::STATE_NORMAL, &brighter_help_image_);
276 controls_.help_button->SetImage(views::Button::STATE_HOVERED, help_image);
277 controls_.help_button->SetImage(views::Button::STATE_PRESSED, help_image);
278 controls_.help_button->set_background(
279 views::Background::CreateSolidBackground(kLightGrayBackgroundColor));
280 controls_.help_button->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
281 views::ImageButton::ALIGN_MIDDLE);
283 GridLayout* layout = new GridLayout(this);
284 SetLayoutManager(layout);
286 // Title row.
287 const int kTitleColumnSetId = 0;
288 views::ColumnSet* cs = layout->AddColumnSet(kTitleColumnSetId);
289 cs->AddPaddingColumn(0, kMarginWidth);
290 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
291 GridLayout::USE_PREF, 0, 0);
292 cs->AddPaddingColumn(0, kMarginWidth);
294 // Text row.
295 const int kTextColumnSetId = 1;
296 cs = layout->AddColumnSet(kTextColumnSetId);
297 cs->AddPaddingColumn(0, kMarginWidth);
298 cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
299 GridLayout::FIXED, kWidthOfDescriptionText, 0);
300 cs->AddPaddingColumn(0, kMarginWidth);
302 // Learn more link & buttons row.
303 const int kButtonsColumnSetId = 2;
304 cs = layout->AddColumnSet(kButtonsColumnSetId);
305 cs->AddPaddingColumn(0, kMarginWidth);
306 cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
307 GridLayout::USE_PREF, 0, 0);
308 cs->AddPaddingColumn(1, views::kRelatedControlHorizontalSpacing);
309 cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
310 GridLayout::USE_PREF, 0, 0);
311 cs->AddPaddingColumn(0, kButtonPadding);
312 cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
313 GridLayout::USE_PREF, 0, 0);
314 cs->AddPaddingColumn(0, kMarginWidth);
316 // Separator.
317 const int kSeparatorColumnSetId = 3;
318 cs = layout->AddColumnSet(kSeparatorColumnSetId);
319 cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
320 GridLayout::FIXED, kAllColumnsWidth, 0);
322 // Reporting row.
323 const int kReportColumnSetId = 4;
324 cs = layout->AddColumnSet(kReportColumnSetId);
325 cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
326 GridLayout::FIXED, kReportingCheckboxColumnWidth, 0);
327 cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
328 GridLayout::FIXED, kHelpButtonColumnWidth, 0);
330 layout->StartRow(0, kTitleColumnSetId);
331 layout->AddView(title_label);
332 layout->AddPaddingRow(0, kMarginHeight);
334 layout->StartRow(0, kTextColumnSetId);
335 layout->AddView(text_label);
336 layout->AddPaddingRow(0, kMarginHeight);
338 layout->StartRow(0, kButtonsColumnSetId);
339 layout->AddView(learn_more_link);
340 layout->AddView(controls_.reset_button);
341 layout->AddView(controls_.no_thanks_button);
342 layout->AddPaddingRow(0, kMarginHeight);
344 layout->StartRow(0, kSeparatorColumnSetId);
345 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
347 layout->StartRow(0, kReportColumnSetId);
348 layout->AddView(controls_.report_settings_checkbox);
349 layout->AddView(controls_.help_button);
351 if (show_help_pane_) {
352 scoped_ptr<base::ListValue> feedback(GetReadableFeedback(profile_));
353 if (feedback.get()) {
354 // We need a single row to add the scroll view containing the feedback.
355 const int kReportDetailsColumnSetId = 5;
356 cs = layout->AddColumnSet(kReportDetailsColumnSetId);
357 cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
358 GridLayout::USE_PREF, 0, 0);
360 FeedbackView* feedback_view = new FeedbackView();
361 feedback_view->SetupLayoutManager(*feedback.get());
363 views::ScrollView* scroll_view = new views::ScrollView();
364 scroll_view->set_background(views::Background::CreateSolidBackground(
365 kLightGrayBackgroundColor));
366 scroll_view->SetContents(feedback_view);
368 layout->StartRow(1, kReportDetailsColumnSetId);
369 layout->AddView(scroll_view, 1, 1, GridLayout::FILL,
370 GridLayout::FILL, kAllColumnsWidth,
371 std::min(feedback_view->height() + kMarginHeight,
372 kMaxFeedbackViewHeight));
376 Layout();
377 AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE));
380 void ProfileResetBubbleView::ButtonPressed(views::Button* sender,
381 const ui::Event& event) {
382 if (sender == controls_.reset_button) {
383 DCHECK(!resetting_);
384 content::RecordAction(
385 base::UserMetricsAction("SettingsResetBubble.Reset"));
387 // Remember that the user chose to reset, and that resetting is underway.
388 chose_to_reset_ = true;
389 resetting_ = true;
391 controls_.reset_button->SetText(l10n_util::GetStringUTF16(IDS_RESETTING));
392 controls_.reset_button->SetEnabled(false);
393 controls_.no_thanks_button->SetEnabled(false);
394 SchedulePaint();
396 if (global_error_) {
397 global_error_->OnBubbleViewResetButtonPressed(
398 controls_.report_settings_checkbox->checked());
400 } else if (sender == controls_.no_thanks_button) {
401 DCHECK(!resetting_);
402 content::RecordAction(
403 base::UserMetricsAction("SettingsResetBubble.NoThanks"));
405 if (global_error_)
406 global_error_->OnBubbleViewNoThanksButtonPressed();
407 StartFade(false);
408 return;
409 } else if (sender == controls_.help_button) {
410 show_help_pane_ = !show_help_pane_;
412 SetupLayoutManager(controls_.report_settings_checkbox->checked());
413 SizeToContents();
417 void ProfileResetBubbleView::LinkClicked(views::Link* source, int flags) {
418 content::RecordAction(
419 base::UserMetricsAction("SettingsResetBubble.LearnMore"));
420 navigator_->OpenURL(content::OpenURLParams(
421 GURL(chrome::kResetProfileSettingsLearnMoreURL), content::Referrer(),
422 NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK, false));
425 void ProfileResetBubbleView::CloseBubbleView() {
426 resetting_ = false;
427 StartFade(false);
430 bool IsProfileResetBubbleSupported() {
431 return true;
434 GlobalErrorBubbleViewBase* ShowProfileResetBubble(
435 const base::WeakPtr<ProfileResetGlobalError>& global_error,
436 Browser* browser) {
437 return ProfileResetBubbleView::ShowBubble(global_error, browser);