diff options
author | mad@chromium.org <mad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-01 05:59:23 +0000 |
---|---|---|
committer | mad@chromium.org <mad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-01 05:59:23 +0000 |
commit | 9b46b6c0059f6968bee08c87020548a7e0a7d720 (patch) | |
tree | 01a3cc1e43fe9c42c4df25a18ebf68fd940222e8 /chrome | |
parent | 02f97168c182dc3297f76995cc0460b3cc8ab9e1 (diff) | |
download | chromium_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.h | 1 | ||||
-rw-r--r-- | chrome/app/theme/theme_resources.grd | 1 | ||||
-rw-r--r-- | chrome/browser/profile_resetter/profile_reset_callback.h | 17 | ||||
-rw-r--r-- | chrome/browser/profile_resetter/profile_reset_global_error.cc | 73 | ||||
-rw-r--r-- | chrome/browser/profile_resetter/profile_reset_global_error.h | 46 | ||||
-rw-r--r-- | chrome/browser/ui/show_profile_reset_bubble.h | 17 | ||||
-rw-r--r-- | chrome/browser/ui/show_profile_reset_bubble_stub.cc | 15 | ||||
-rw-r--r-- | chrome/browser/ui/views/profile_reset_bubble_view.cc | 449 | ||||
-rw-r--r-- | chrome/browser/ui/views/profile_reset_bubble_view.h | 136 | ||||
-rw-r--r-- | chrome/browser/ui/webui/options/reset_profile_settings_handler.cc | 11 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 3 | ||||
-rw-r--r-- | chrome/chrome_browser_ui.gypi | 9 | ||||
-rw-r--r-- | chrome/common/url_constants.cc | 3 | ||||
-rw-r--r-- | chrome/common/url_constants.h | 3 |
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[]; |