summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authormad@chromium.org <mad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-01 05:59:23 +0000
committermad@chromium.org <mad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-01 05:59:23 +0000
commit9b46b6c0059f6968bee08c87020548a7e0a7d720 (patch)
tree01a3cc1e43fe9c42c4df25a18ebf68fd940222e8 /chrome
parent02f97168c182dc3297f76995cc0460b3cc8ab9e1 (diff)
downloadchromium_src-9b46b6c0059f6968bee08c87020548a7e0a7d720.zip
chromium_src-9b46b6c0059f6968bee08c87020548a7e0a7d720.tar.gz
chromium_src-9b46b6c0059f6968bee08c87020548a7e0a7d720.tar.bz2
Add a new Profile Settings Reset Bubble and Global Error to make it available from the Chrome menu.
BUG=264861 Review URL: https://codereview.chromium.org/24301005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@226157 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/app/chrome_command_ids.h1
-rw-r--r--chrome/app/theme/theme_resources.grd1
-rw-r--r--chrome/browser/profile_resetter/profile_reset_callback.h17
-rw-r--r--chrome/browser/profile_resetter/profile_reset_global_error.cc73
-rw-r--r--chrome/browser/profile_resetter/profile_reset_global_error.h46
-rw-r--r--chrome/browser/ui/show_profile_reset_bubble.h17
-rw-r--r--chrome/browser/ui/show_profile_reset_bubble_stub.cc15
-rw-r--r--chrome/browser/ui/views/profile_reset_bubble_view.cc449
-rw-r--r--chrome/browser/ui/views/profile_reset_bubble_view.h136
-rw-r--r--chrome/browser/ui/webui/options/reset_profile_settings_handler.cc11
-rw-r--r--chrome/chrome_browser.gypi3
-rw-r--r--chrome/chrome_browser_ui.gypi9
-rw-r--r--chrome/common/url_constants.cc3
-rw-r--r--chrome/common/url_constants.h3
14 files changed, 775 insertions, 9 deletions
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h
index 04715f3..39090e45 100644
--- a/chrome/app/chrome_command_ids.h
+++ b/chrome/app/chrome_command_ids.h
@@ -203,6 +203,7 @@
#define IDC_EXTERNAL_EXTENSION_ALERT 40238
#define IDC_RECENT_TABS_MENU 40239
#define IDC_RECENT_TABS_NO_DEVICE_TABS 40240
+#define IDC_SHOW_SETTINGS_RESET_BUBBLE 40241
// Spell-check
// Insert any additional suggestions before _LAST; these have to be consecutive.
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index 475ab3a..95701ce 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -717,6 +717,7 @@
<structure type="chrome_scaled_image" name="IDR_PROFILE_PICTURE_LOADING" file="profile_loading.png" />
<structure type="chrome_scaled_image" name="IDR_RESET_WARNING" file="reset_warning.png" />
</if>
+ <structure type="chrome_scaled_image" name="IDR_QUESTION_MARK" file="common/question_mark.png" />
<structure type="chrome_scaled_image" name="IDR_PROFILE_SELECTED" file="common/profile_selected.png" />
<structure type="chrome_scaled_image" name="IDR_REGISTER_PROTOCOL_HANDLER" file="register_protocol_handler.png" />
<if expr="not pp_ifdef('toolkit_views') and not is_macosx and not is_ios">
diff --git a/chrome/browser/profile_resetter/profile_reset_callback.h b/chrome/browser/profile_resetter/profile_reset_callback.h
new file mode 100644
index 0000000..b0aa19a
--- /dev/null
+++ b/chrome/browser/profile_resetter/profile_reset_callback.h
@@ -0,0 +1,17 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PROFILE_RESETTER_PROFILE_RESET_CALLBACK_H_
+#define CHROME_BROWSER_PROFILE_RESETTER_PROFILE_RESET_CALLBACK_H_
+
+#include "base/callback_forward.h"
+
+// A callback invoked by the settings reset bubble when the user chooses to
+// reset her preferences. The bool provided in the first argument is true when
+// the user has consented to provide feedback to Google. Implementations are
+// responsible for running the closure provided in the second argument when the
+// reset has completed.
+typedef base::Callback<void(bool, const base::Closure&)> ProfileResetCallback;
+
+#endif // CHROME_BROWSER_PROFILE_RESETTER_PROFILE_RESET_CALLBACK_H_
diff --git a/chrome/browser/profile_resetter/profile_reset_global_error.cc b/chrome/browser/profile_resetter/profile_reset_global_error.cc
new file mode 100644
index 0000000..e4c1ce4
--- /dev/null
+++ b/chrome/browser/profile_resetter/profile_reset_global_error.cc
@@ -0,0 +1,73 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/profile_resetter/profile_reset_global_error.h"
+
+#include "base/logging.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/ui/show_profile_reset_bubble.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+ProfileResetGlobalError::ProfileResetGlobalError() {
+}
+
+ProfileResetGlobalError::~ProfileResetGlobalError() {
+}
+
+bool ProfileResetGlobalError::HasMenuItem() {
+ return true;
+}
+
+int ProfileResetGlobalError::MenuItemCommandID() {
+ return IDC_SHOW_SETTINGS_RESET_BUBBLE;
+}
+
+string16 ProfileResetGlobalError::MenuItemLabel() {
+ return l10n_util::GetStringFUTF16(IDS_RESET_SETTINGS_MENU_ITEM,
+ l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME));
+}
+
+void ProfileResetGlobalError::ExecuteMenuItem(Browser* browser) {
+ ShowProfileResetBubble(browser, reset_callback_);
+}
+
+// We don't use the GlobalErrorBubbleViewBase since it is not flexible enough
+// for our needs.
+bool ProfileResetGlobalError::HasBubbleView() {
+ return false;
+}
+
+string16 ProfileResetGlobalError::GetBubbleViewTitle() {
+ NOTREACHED();
+ return string16();
+}
+
+std::vector<string16> ProfileResetGlobalError::GetBubbleViewMessages() {
+ NOTREACHED();
+ return std::vector<string16>();
+}
+
+string16 ProfileResetGlobalError::GetBubbleViewAcceptButtonLabel() {
+ NOTREACHED();
+ return string16();
+}
+
+string16 ProfileResetGlobalError::GetBubbleViewCancelButtonLabel() {
+ NOTREACHED();
+ return string16();
+}
+
+void ProfileResetGlobalError::OnBubbleViewDidClose(Browser* browser) {
+ NOTREACHED();
+}
+
+void ProfileResetGlobalError::BubbleViewAcceptButtonPressed(Browser* browser) {
+ NOTREACHED();
+}
+
+void ProfileResetGlobalError::BubbleViewCancelButtonPressed(Browser* browser) {
+ NOTREACHED();
+}
diff --git a/chrome/browser/profile_resetter/profile_reset_global_error.h b/chrome/browser/profile_resetter/profile_reset_global_error.h
new file mode 100644
index 0000000..cf9dfaa
--- /dev/null
+++ b/chrome/browser/profile_resetter/profile_reset_global_error.h
@@ -0,0 +1,46 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PROFILE_RESETTER_PROFILE_RESET_GLOBAL_ERROR_H_
+#define CHROME_BROWSER_PROFILE_RESETTER_PROFILE_RESET_GLOBAL_ERROR_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "chrome/browser/profile_resetter/profile_reset_callback.h"
+#include "chrome/browser/ui/global_error/global_error.h"
+
+// Shows preferences reset errors on the wrench menu and exposes a menu item to
+// launch a bubble view.
+class ProfileResetGlobalError : public GlobalError {
+ public:
+ ProfileResetGlobalError();
+ virtual ~ProfileResetGlobalError();
+
+ // GlobalError overrides.
+ virtual bool HasMenuItem() OVERRIDE;
+ virtual int MenuItemCommandID() OVERRIDE;
+ virtual string16 MenuItemLabel() OVERRIDE;
+ virtual void ExecuteMenuItem(Browser* browser) OVERRIDE;
+ virtual bool HasBubbleView() OVERRIDE;
+ virtual string16 GetBubbleViewTitle() OVERRIDE;
+ virtual std::vector<string16> GetBubbleViewMessages() OVERRIDE;
+ virtual string16 GetBubbleViewAcceptButtonLabel() OVERRIDE;
+ virtual string16 GetBubbleViewCancelButtonLabel() OVERRIDE;
+ virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE;
+ virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE;
+ virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE;
+
+ // Sets a callback to be given to the bubble to be called when the user
+ // chooses to reset the settings.
+ void set_reset_callback(const ProfileResetCallback& reset_callback) {
+ reset_callback_ = reset_callback;
+ }
+
+ private:
+ ProfileResetCallback reset_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileResetGlobalError);
+};
+
+#endif // CHROME_BROWSER_PROFILE_RESETTER_PROFILE_RESET_GLOBAL_ERROR_H_
diff --git a/chrome/browser/ui/show_profile_reset_bubble.h b/chrome/browser/ui/show_profile_reset_bubble.h
new file mode 100644
index 0000000..de69662
--- /dev/null
+++ b/chrome/browser/ui/show_profile_reset_bubble.h
@@ -0,0 +1,17 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_SHOW_PROFILE_RESET_BUBBLE_H_
+#define CHROME_BROWSER_UI_SHOW_PROFILE_RESET_BUBBLE_H_
+
+#include "chrome/browser/profile_resetter/profile_reset_callback.h"
+
+class Browser;
+
+// Shows the prefs reset bubble on the platforms that support it. The callback
+// is run when the user chooses to reset preferences.
+void ShowProfileResetBubble(Browser* browser,
+ const ProfileResetCallback& reset_callback);
+
+#endif // CHROME_BROWSER_UI_SHOW_PROFILE_RESET_BUBBLE_H_
diff --git a/chrome/browser/ui/show_profile_reset_bubble_stub.cc b/chrome/browser/ui/show_profile_reset_bubble_stub.cc
new file mode 100644
index 0000000..f98667c
--- /dev/null
+++ b/chrome/browser/ui/show_profile_reset_bubble_stub.cc
@@ -0,0 +1,15 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/show_profile_reset_bubble.h"
+
+#include "base/logging.h"
+
+// This is for the code in ProfileResetGlobalError to compile on platforms where
+// the profile reset bubble is not implemented yet.
+void ShowProfileResetBubble(
+ Browser* browser,
+ const ProfileResetCallback& reset_callback) {
+ NOTREACHED();
+}
diff --git a/chrome/browser/ui/views/profile_reset_bubble_view.cc b/chrome/browser/ui/views/profile_reset_bubble_view.cc
new file mode 100644
index 0000000..4484dfd
--- /dev/null
+++ b/chrome/browser/ui/views/profile_reset_bubble_view.cc
@@ -0,0 +1,449 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/profile_reset_bubble_view.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/values.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/google/google_util.h"
+#include "chrome/browser/profile_resetter/profile_reset_global_error.h"
+#include "chrome/browser/profile_resetter/resettable_settings_snapshot.h"
+#include "chrome/browser/ui/global_error/global_error_service.h"
+#include "chrome/browser/ui/global_error/global_error_service_factory.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/toolbar_view.h"
+#include "chrome/common/url_constants.h"
+#include "content/public/browser/page_navigator.h"
+#include "content/public/browser/user_metrics.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image_skia_operations.h"
+#include "ui/views/background.h"
+#include "ui/views/controls/button/checkbox.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/link.h"
+#include "ui/views/controls/scroll_view.h"
+#include "ui/views/controls/separator.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/layout/layout_constants.h"
+
+using views::GridLayout;
+
+namespace {
+
+// Fixed width of the column holding the description label of the bubble.
+const int kWidthOfDescriptionText = 370;
+
+// Margins width for the top rows to compensate for the bottom panel for which
+// we don't want any margin.
+const int kMarginWidth = 12;
+const int kMarginHeight = kMarginWidth;
+
+// Width of a colum in the FeedbackView.
+const int kFeedbackViewColumnWidth = kWidthOfDescriptionText / 2 + kMarginWidth;
+
+// Width of the column used to disaplay the help button.
+const int kHelpButtonColumnWidth = 30;
+
+// Width of the reporting checkbox column.
+const int kReportingCheckboxColumnWidth =
+ kWidthOfDescriptionText + 2 * kMarginWidth;
+
+// Full width including all columns.
+const int kAllColumnsWidth =
+ kReportingCheckboxColumnWidth + kHelpButtonColumnWidth;
+
+// Maximum height of the scrollable feedback view.
+const int kMaxFeedbackViewHeight = 450;
+
+// The vertical padding between two values in the feedback view.
+const int kInterFeedbackValuePadding = 4;
+
+// We subtract 2 to account for the natural button padding, and
+// to bring the separation visually in line with the row separation
+// height.
+const int kButtonPadding = views::kRelatedButtonHSpacing - 2;
+
+// The maximum number of ignored bubbles we track in the NumNoThanksPerReset
+// histogram.
+const int kMaxIgnored = 50;
+
+// The number of buckets we want the NumNoThanksPerReset histogram to use.
+const int kNumIgnoredBuckets = 5;
+
+// The color of the background of the sub panel to report current settings.
+const SkColor kLightGrayBackgroundColor = 0xFFF5F5F5;
+
+// This view is used to contain the scrollable contents that are shown the user
+// to expose what feedback will be sent back to Google.
+class FeedbackView : public views::View {
+ public:
+ FeedbackView() {}
+
+ // Setup the layout manager of the Feedback view using the content of the
+ // |feedback| ListValue which contains a list of key/value pairs stored in
+ // DictionaryValues. The key is to be displayed right aligned on the left, and
+ // the value as a left aligned multiline text on the right.
+ void SetupLayoutManager(const ListValue& feedback) {
+ RemoveAllChildViews(true);
+ set_background(views::Background::CreateSolidBackground(
+ kLightGrayBackgroundColor));
+
+ GridLayout* layout = new GridLayout(this);
+ SetLayoutManager(layout);
+
+ // We only need a single column set for left/right text and middle margin.
+ views::ColumnSet* cs = layout->AddColumnSet(0);
+ cs->AddColumn(GridLayout::FILL, GridLayout::LEADING, 1,
+ GridLayout::FIXED, kFeedbackViewColumnWidth, 0);
+ cs->AddPaddingColumn(0, kMarginWidth);
+ cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
+ GridLayout::FIXED, kFeedbackViewColumnWidth, 0);
+ for (size_t i = 0; i < feedback.GetSize(); ++i) {
+ const DictionaryValue* dictionary = NULL;
+ if (!feedback.GetDictionary(i, &dictionary) || !dictionary)
+ continue;
+
+ string16 key;
+ if (!dictionary->GetString("key", &key))
+ continue;
+
+ string16 value;
+ if (!dictionary->GetString("value", &value))
+ continue;
+
+ // The key is shown on the left, single line, right-aligned.
+ views::Label* left_text_label = new views::Label(key);
+ left_text_label->SetEnabledColor(SK_ColorGRAY);
+ left_text_label->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
+
+ // The value is shown on the right, multi-line, left-aligned.
+ views::Label* right_text_label = new views::Label(value);
+ right_text_label->SetMultiLine(true);
+ right_text_label->SetEnabledColor(SK_ColorDKGRAY);
+ right_text_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+
+ layout->StartRow(0, 0);
+ layout->AddView(left_text_label);
+ layout->AddView(right_text_label);
+ layout->AddPaddingRow(0, kInterFeedbackValuePadding);
+ }
+
+ // We need to set our size to our preferred size because our parent is a
+ // scroll view and doesn't know which size to set us to. Also since our
+ // parent scrolls, we are not bound to its size. So our size is based on the
+ // size computed by the our layout manager, which is what
+ // SizeToPreferredSize() does.
+ SizeToPreferredSize();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FeedbackView);
+};
+
+} // namespace
+
+// ProfileResetBubbleView ---------------------------------------------------
+
+// static
+ProfileResetBubbleView* ProfileResetBubbleView::reset_bubble_ = NULL;
+int ProfileResetBubbleView::num_ignored_bubbles_ = 0;
+
+// static
+void ProfileResetBubbleView::ShowBubble(
+ views::View* anchor_view,
+ content::PageNavigator* navigator,
+ Profile* profile,
+ const ProfileResetCallback& reset_callback) {
+ if (IsShowing())
+ return;
+ reset_bubble_ = new ProfileResetBubbleView(
+ anchor_view, navigator, profile, reset_callback);
+ views::BubbleDelegateView::CreateBubble(reset_bubble_);
+ reset_bubble_->StartFade(true);
+ content::RecordAction(content::UserMetricsAction("SettingsResetBubble.Show"));
+}
+
+ProfileResetBubbleView::~ProfileResetBubbleView() {
+ if (!chose_to_reset_ && num_ignored_bubbles_ < kMaxIgnored)
+ ++num_ignored_bubbles_;
+}
+
+views::View* ProfileResetBubbleView::GetInitiallyFocusedView() {
+ return controls_.reset_button;
+}
+
+void ProfileResetBubbleView::WindowClosing() {
+ // Reset |reset_bubble_| here, not in destructor, because destruction is
+ // asynchronous and ShowBubble may be called before full destruction and
+ // would attempt to show a bubble that is closing.
+ DCHECK_EQ(reset_bubble_, this);
+ reset_bubble_ = NULL;
+}
+
+ProfileResetBubbleView::ProfileResetBubbleView(
+ views::View* anchor_view,
+ content::PageNavigator* navigator,
+ Profile* profile,
+ const ProfileResetCallback& reset_callback)
+ : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT),
+ navigator_(navigator),
+ profile_(profile),
+ reset_callback_(reset_callback),
+ resetting_(false),
+ chose_to_reset_(false),
+ show_help_pane_(false),
+ weak_factory_(this) {
+}
+
+void ProfileResetBubbleView::ResetAllChildren() {
+ controls_.Reset();
+ SetLayoutManager(NULL);
+ RemoveAllChildViews(true);
+}
+
+void ProfileResetBubbleView::Init() {
+ set_margins(gfx::Insets(kMarginHeight, 0, 0, 0));
+ SetupLayoutManager(true);
+}
+
+void ProfileResetBubbleView::SetupLayoutManager(bool report_checked) {
+ ResetAllChildren();
+
+ string16 product_name(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME));
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+
+ // Bubble title label.
+ views::Label* title_label = new views::Label(
+ l10n_util::GetStringFUTF16(IDS_RESET_BUBBLE_TITLE, product_name));
+ title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+ title_label->SetFont(rb.GetFont(ui::ResourceBundle::BoldFont));
+
+ // Description text label.
+ views::Label* text_label = new views::Label(
+ l10n_util::GetStringFUTF16(IDS_RESET_BUBBLE_TEXT, product_name));
+ text_label->SetMultiLine(true);
+ text_label->SetLineHeight(20);
+ text_label->SetEnabledColor(SK_ColorDKGRAY);
+ text_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+
+ // Learn more link.
+ views::Link* learn_more_link = new views::Link(
+ l10n_util::GetStringUTF16(IDS_LEARN_MORE));
+ learn_more_link->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+ learn_more_link->set_listener(this);
+ learn_more_link->SetUnderline(false);
+
+ // Reset button's name is based on |resetting_| state.
+ int reset_button_string_id = IDS_RESET_PROFILE_SETTINGS_COMMIT_BUTTON;
+ if (resetting_)
+ reset_button_string_id = IDS_RESETTING;
+ controls_.reset_button = new views::LabelButton(
+ this, l10n_util::GetStringUTF16(reset_button_string_id));
+ controls_.reset_button->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
+ controls_.reset_button->SetIsDefault(true);
+ controls_.reset_button->SetFont(rb.GetFont(ui::ResourceBundle::BoldFont));
+ controls_.reset_button->SetEnabled(!resetting_);
+ // For the Resetting... text to fit.
+ gfx::Size reset_button_size = controls_.reset_button->GetPreferredSize();
+ reset_button_size.set_width(100);
+ controls_.reset_button->set_min_size(reset_button_size);
+
+ // No thanks button.
+ controls_.no_thanks_button = new views::LabelButton(
+ this, l10n_util::GetStringUTF16(IDS_NO_THANKS));
+ controls_.no_thanks_button->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
+ controls_.no_thanks_button->SetEnabled(!resetting_);
+
+ // Checkbox for reporting settings or not.
+ controls_.report_settings_checkbox = new views::Checkbox(
+ l10n_util::GetStringUTF16(IDS_REPORT_BUBBLE_TEXT));
+ controls_.report_settings_checkbox->SetTextColor(
+ views::Button::STATE_NORMAL, SK_ColorGRAY);
+ controls_.report_settings_checkbox->SetChecked(report_checked);
+ controls_.report_settings_checkbox->SetTextMultiLine(true);
+ controls_.report_settings_checkbox->set_background(
+ views::Background::CreateSolidBackground(kLightGrayBackgroundColor));
+ // Have a smaller margin on the right, to have the |controls_.help_button|
+ // closer to the edge.
+ controls_.report_settings_checkbox->set_border(
+ views::Border::CreateSolidSidedBorder(
+ kMarginWidth, kMarginWidth, kMarginWidth, kMarginWidth / 2,
+ kLightGrayBackgroundColor));
+
+ // Help button to toggle the bottom panel on or off.
+ controls_.help_button = new views::ImageButton(this);
+ const gfx::ImageSkia* help_image = rb.GetImageSkiaNamed(IDR_QUESTION_MARK);
+ color_utils::HSL hsl_shift = { -1, 0, 0.8 };
+ brighter_help_image_ = gfx::ImageSkiaOperations::CreateHSLShiftedImage(
+ *help_image, hsl_shift);
+ controls_.help_button->SetImage(
+ views::Button::STATE_NORMAL, &brighter_help_image_);
+ controls_.help_button->SetImage(views::Button::STATE_HOVERED, help_image);
+ controls_.help_button->SetImage(views::Button::STATE_PRESSED, help_image);
+ controls_.help_button->set_background(
+ views::Background::CreateSolidBackground(kLightGrayBackgroundColor));
+ controls_.help_button->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
+ views::ImageButton::ALIGN_MIDDLE);
+
+ GridLayout* layout = new GridLayout(this);
+ SetLayoutManager(layout);
+
+ // Title row.
+ const int kTitleColumnSetId = 0;
+ views::ColumnSet* cs = layout->AddColumnSet(kTitleColumnSetId);
+ cs->AddPaddingColumn(0, kMarginWidth);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
+ GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(0, kMarginWidth);
+
+ // Text row.
+ const int kTextColumnSetId = 1;
+ cs = layout->AddColumnSet(kTextColumnSetId);
+ cs->AddPaddingColumn(0, kMarginWidth);
+ cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
+ GridLayout::FIXED, kWidthOfDescriptionText, 0);
+ cs->AddPaddingColumn(0, kMarginWidth);
+
+ // Learn more link & buttons row.
+ const int kButtonsColumnSetId = 2;
+ cs = layout->AddColumnSet(kButtonsColumnSetId);
+ cs->AddPaddingColumn(0, kMarginWidth);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
+ GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(1, views::kRelatedControlHorizontalSpacing);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
+ GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(0, kButtonPadding);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
+ GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(0, kMarginWidth);
+
+ // Separator.
+ const int kSeparatorColumnSetId = 3;
+ cs = layout->AddColumnSet(kSeparatorColumnSetId);
+ cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
+ GridLayout::FIXED, kAllColumnsWidth, 0);
+
+ // Reporting row.
+ const int kReportColumnSetId = 4;
+ cs = layout->AddColumnSet(kReportColumnSetId);
+ cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
+ GridLayout::FIXED, kReportingCheckboxColumnWidth, 0);
+ cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
+ GridLayout::FIXED, kHelpButtonColumnWidth, 0);
+
+ layout->StartRow(0, kTitleColumnSetId);
+ layout->AddView(title_label);
+ layout->AddPaddingRow(0, kMarginHeight);
+
+ layout->StartRow(0, kTextColumnSetId);
+ layout->AddView(text_label);
+ layout->AddPaddingRow(0, kMarginHeight);
+
+ layout->StartRow(0, kButtonsColumnSetId);
+ layout->AddView(learn_more_link);
+ layout->AddView(controls_.reset_button);
+ layout->AddView(controls_.no_thanks_button);
+ layout->AddPaddingRow(0, kMarginHeight);
+
+ layout->StartRow(0, kSeparatorColumnSetId);
+ layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
+
+ layout->StartRow(0, kReportColumnSetId);
+ layout->AddView(controls_.report_settings_checkbox);
+ layout->AddView(controls_.help_button);
+
+ if (show_help_pane_) {
+ scoped_ptr<ListValue> feedback(GetReadableFeedback(profile_));
+ if (feedback.get()) {
+ // We need a single row to add the scroll view containing the feedback.
+ const int kReportDetailsColumnSetId = 5;
+ cs = layout->AddColumnSet(kReportDetailsColumnSetId);
+ cs->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
+ GridLayout::USE_PREF, 0, 0);
+
+ FeedbackView* feedback_view = new FeedbackView();
+ feedback_view->SetupLayoutManager(*feedback.get());
+
+ views::ScrollView* scroll_view = new views::ScrollView();
+ scroll_view->set_background(views::Background::CreateSolidBackground(
+ kLightGrayBackgroundColor));
+ scroll_view->SetContents(feedback_view);
+
+ layout->StartRow(1, kReportDetailsColumnSetId);
+ layout->AddView(scroll_view, 1, 1, GridLayout::FILL,
+ GridLayout::FILL, kAllColumnsWidth,
+ std::min(feedback_view->height() + kMarginHeight,
+ kMaxFeedbackViewHeight));
+ }
+ }
+
+ Layout();
+ AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE));
+}
+
+void ProfileResetBubbleView::ButtonPressed(views::Button* sender,
+ const ui::Event& event) {
+ if (sender == controls_.reset_button) {
+ DCHECK(!resetting_);
+ UMA_HISTOGRAM_CUSTOM_COUNTS("SettingsResetBubble.NumNoThanksPerReset",
+ num_ignored_bubbles_, 0, kMaxIgnored,
+ kNumIgnoredBuckets);
+ content::RecordAction(content::UserMetricsAction(
+ "SettingsResetBubble.Reset"));
+
+ // Remember that the user chose to reset, and that resetting is underway.
+ chose_to_reset_ = true;
+ resetting_ = true;
+
+ controls_.reset_button->SetText(l10n_util::GetStringUTF16(IDS_RESETTING));
+ controls_.reset_button->SetEnabled(false);
+ controls_.no_thanks_button->SetEnabled(false);
+ SchedulePaint();
+
+ reset_callback_.Run(
+ controls_.report_settings_checkbox->checked(),
+ base::Bind(&ProfileResetBubbleView::OnResetProfileSettingsDone,
+ weak_factory_.GetWeakPtr()));
+ } else if (sender == controls_.no_thanks_button) {
+ DCHECK(!resetting_);
+ content::RecordAction(content::UserMetricsAction(
+ "SettingsResetBubble.NoThanks"));
+ StartFade(false);
+ return;
+ } else if (sender == controls_.help_button) {
+ show_help_pane_ = !show_help_pane_;
+
+ SetupLayoutManager(controls_.report_settings_checkbox->checked());
+ SizeToContents();
+ }
+}
+
+void ProfileResetBubbleView::LinkClicked(views::Link* source, int flags) {
+ content::RecordAction(content::UserMetricsAction(
+ "SettingsResetBubble.LearnMore"));
+ navigator_->OpenURL(content::OpenURLParams(
+ GURL(chrome::kResetProfileSettingsLearnMoreURL), content::Referrer(),
+ NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_LINK, false));
+}
+
+void ProfileResetBubbleView::OnResetProfileSettingsDone() {
+ resetting_ = false;
+ StartFade(false);
+}
+
+void ShowProfileResetBubble(Browser* browser,
+ const ProfileResetCallback& reset_callback) {
+ ProfileResetBubbleView::ShowBubble(
+ BrowserView::GetBrowserViewForBrowser(browser)->toolbar()->app_menu(),
+ browser, browser->profile(), reset_callback);
+}
diff --git a/chrome/browser/ui/views/profile_reset_bubble_view.h b/chrome/browser/ui/views/profile_reset_bubble_view.h
new file mode 100644
index 0000000..61878a8
--- /dev/null
+++ b/chrome/browser/ui/views/profile_reset_bubble_view.h
@@ -0,0 +1,136 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_PROFILE_RESET_BUBBLE_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_PROFILE_RESET_BUBBLE_VIEW_H_
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/profile_resetter/profile_reset_callback.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/views/bubble/bubble_delegate.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/link_listener.h"
+
+namespace content {
+class PageNavigator;
+}
+
+namespace views {
+class Checkbox;
+class ImageButton;
+class LabelButton;
+class Link;
+}
+
+class Profile;
+
+// ProfileResetBubbleView warns the user that a settings reset might be needed.
+// It is intended to be used as the content of a bubble anchored off of the
+// Chrome toolbar.
+class ProfileResetBubbleView : public views::BubbleDelegateView,
+ public views::ButtonListener,
+ public views::LinkListener {
+ public:
+ static void ShowBubble(views::View* anchor_view,
+ content::PageNavigator* navigator,
+ Profile* profile,
+ const ProfileResetCallback& reset_callback);
+
+ // views::BubbleDelegateView methods.
+ virtual views::View* GetInitiallyFocusedView() OVERRIDE;
+ virtual void Init() OVERRIDE;
+
+ // views::WidgetDelegate method.
+ virtual void WindowClosing() OVERRIDE;
+
+ private:
+ ProfileResetBubbleView(views::View* anchor_view,
+ content::PageNavigator* navigator,
+ Profile* profile,
+ const ProfileResetCallback& reset_callback);
+
+ virtual ~ProfileResetBubbleView();
+
+ static bool IsShowing() { return reset_bubble_ != NULL; }
+
+ // Reset all child views members and remove children from view hierarchy.
+ void ResetAllChildren();
+
+ // Sets up the layout manager and set the report checkbox to the value passed
+ // in |report_checked|.
+ void SetupLayoutManager(bool report_checked);
+
+ // views::ButtonListener method.
+ virtual void ButtonPressed(views::Button* sender,
+ const ui::Event& event) OVERRIDE;
+
+ // views::LinkListener method.
+ virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE;
+
+ // Callback from the profile resetter, once it's done.
+ void OnResetProfileSettingsDone();
+
+ // The reset bubble, if we're showing one.
+ static ProfileResetBubbleView* reset_bubble_;
+
+ // The numer of times the user ignored the bubble before finally choosing to
+ // reset.
+ static int num_ignored_bubbles_;
+
+ struct Controls {
+ Controls() {
+ Reset();
+ }
+ void Reset() {
+ reset_button = NULL;
+ no_thanks_button = NULL;
+ help_button = NULL;
+ report_settings_checkbox = NULL;
+ }
+
+ // Button for the user to confirm a settings reset.
+ views::LabelButton* reset_button;
+
+ // Button for the user to refuse a settings reset.
+ views::LabelButton* no_thanks_button;
+
+ // Button for the user to get more info about reporting settings.
+ views::ImageButton* help_button;
+
+ // Checkbox for the user to choose to report the settings or not.
+ views::Checkbox* report_settings_checkbox;
+ } controls_;
+
+ // A version of the help image that is brighter.
+ gfx::ImageSkia brighter_help_image_;
+
+ // Used for opening the learn more link.
+ content::PageNavigator* navigator_;
+
+ // Used to access profile specific stuff like the global error or readable
+ // feedback.
+ Profile* profile_;
+
+ // Callback to the code that takes care of the profile reset.
+ ProfileResetCallback reset_callback_;
+
+ // Remembers if we are currently resetting or not.
+ bool resetting_;
+
+ // Remembers if the reset button was hit before closing the bubble.
+ bool chose_to_reset_;
+
+ // Toggles when the user clicks on the |help_button_| to identify if we should
+ // show the help pane or not.
+ bool show_help_pane_;
+
+ // To cancel pending callbacks after destruction.
+ base::WeakPtrFactory<ProfileResetBubbleView> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileResetBubbleView);
+};
+
+#endif // CHROME_BROWSER_UI_VIEWS_PROFILE_RESET_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/webui/options/reset_profile_settings_handler.cc b/chrome/browser/ui/webui/options/reset_profile_settings_handler.cc
index 3356eea..50ecced 100644
--- a/chrome/browser/ui/webui/options/reset_profile_settings_handler.cc
+++ b/chrome/browser/ui/webui/options/reset_profile_settings_handler.cc
@@ -17,18 +17,12 @@
#include "chrome/browser/profile_resetter/resettable_settings_snapshot.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_ui.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
-namespace {
-
-const char kResetProfileSettingsLearnMoreUrl[] =
- "https://support.google.com/chrome/?p=ui_reset_settings";
-
-} // namespace
-
namespace options {
ResetProfileSettingsHandler::ResetProfileSettingsHandler() {
@@ -65,8 +59,7 @@ void ResetProfileSettingsHandler::GetLocalizedValues(
IDS_RESET_PROFILE_SETTINGS_TITLE);
localized_strings->SetString(
"resetProfileSettingsLearnMoreUrl",
- google_util::StringAppendGoogleLocaleParam(
- kResetProfileSettingsLearnMoreUrl));
+ chrome::kResetProfileSettingsLearnMoreURL);
}
void ResetProfileSettingsHandler::RegisterMessages() {
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index ad5fc5d..d726ed7 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1700,6 +1700,9 @@
'browser/profile_resetter/brandcoded_default_settings.cc',
'browser/profile_resetter/brandcode_config_fetcher.h',
'browser/profile_resetter/brandcode_config_fetcher.cc',
+ 'browser/profile_resetter/profile_reset_callback.h',
+ 'browser/profile_resetter/profile_reset_global_error.h',
+ 'browser/profile_resetter/profile_reset_global_error.cc',
'browser/profile_resetter/profile_resetter.h',
'browser/profile_resetter/profile_resetter.cc',
'browser/profile_resetter/jtl_foundation.h',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index b2e1490..d41e46a 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -1449,6 +1449,8 @@
'browser/ui/search_engines/template_url_fetcher_ui_callbacks.h',
'browser/ui/search_engines/template_url_table_model.cc',
'browser/ui/search_engines/template_url_table_model.h',
+ 'browser/ui/show_profile_reset_bubble.h',
+ 'browser/ui/show_profile_reset_bubble_stub.cc',
'browser/ui/simple_message_box.h',
'browser/ui/singleton_tabs.cc',
'browser/ui/singleton_tabs.h',
@@ -1929,6 +1931,8 @@
'browser/ui/views/pdf_password_dialog.cc',
'browser/ui/views/profile_chooser_view.cc',
'browser/ui/views/profile_chooser_view.h',
+ 'browser/ui/views/profile_reset_bubble_view.cc',
+ 'browser/ui/views/profile_reset_bubble_view.h',
'browser/ui/views/user_manager_view.cc',
'browser/ui/views/user_manager_view.h',
'browser/ui/views/reload_button.cc',
@@ -2611,6 +2615,11 @@
'browser/ui/tabs/tab_strip_layout_type_prefs.h',
],
}],
+ ['toolkit_views == 1', {
+ 'sources!': [
+ 'browser/ui/show_profile_reset_bubble_stub.cc',
+ ],
+ }],
['OS=="linux"', {
'dependencies': [
'../build/linux/system.gyp:udev',
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index c84731e..db326e2 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -384,6 +384,9 @@ const char kChromeSyncLearnMoreURL[] =
const char kChromeEnterpriseSignInLearnMoreURL[] =
"http://support.google.com/chromeos/bin/answer.py?hl=en&answer=1331549";
+const char kResetProfileSettingsLearnMoreURL[] =
+ "https://support.google.com/chrome/?p=ui_reset_settings";
+
const char kSupervisedUserManagementURL[] = "https://www.chrome.com/manage";
const char kSupervisedUserManagementDisplayURL[] = "www.chrome.com/manage";
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index 3acb602..a122f83 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -335,6 +335,9 @@ extern const char kChromeSyncLearnMoreURL[];
// "Learn more" URL for the enterprise sign-in confirmation dialog.
extern const char kChromeEnterpriseSignInLearnMoreURL[];
+// "Learn more" URL for resetting profile preferences.
+extern const char kResetProfileSettingsLearnMoreURL[];
+
// Management URL for the supervised users.
extern const char kSupervisedUserManagementURL[];