diff options
-rw-r--r-- | chrome/app/chrome_command_ids.h | 1 | ||||
-rw-r--r-- | chrome/browser/protector/settings_change_global_error.cc | 182 | ||||
-rw-r--r-- | chrome/browser/protector/settings_change_global_error.h | 90 | ||||
-rw-r--r-- | chrome/browser/ui/views/global_error_bubble_view.cc | 32 | ||||
-rw-r--r-- | chrome/browser/ui/views/global_error_bubble_view.h | 9 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 |
6 files changed, 308 insertions, 8 deletions
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h index 228347a..b49bf84 100644 --- a/chrome/app/chrome_command_ids.h +++ b/chrome/app/chrome_command_ids.h @@ -172,6 +172,7 @@ #define IDC_SHOW_SYNC_SETUP 40030 #define IDC_EXTENSION_ERRORS 40031 #define IDC_SHOW_SYNC_ERROR 40032 +#define IDC_SHOW_SETTINGS_CHANGES 40033 // Spell-check // Insert any additional suggestions before _LAST; these have to be consecutive. diff --git a/chrome/browser/protector/settings_change_global_error.cc b/chrome/browser/protector/settings_change_global_error.cc new file mode 100644 index 0000000..cbeb056 --- /dev/null +++ b/chrome/browser/protector/settings_change_global_error.cc @@ -0,0 +1,182 @@ +// Copyright (c) 2011 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/protector/settings_change_global_error.h" + +#include "base/bind.h" +#include "base/task.h" +#include "chrome/app/chrome_command_ids.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/global_error_service.h" +#include "chrome/browser/ui/global_error_service_factory.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace { + +// Timeout before the global error is removed (wrench menu item disappears). +const int kMenuItemDisplayPeriodMs = 10*60*1000; // 10 min +// IDs of menu item labels. +const int kMenuItemLabelIDs[] = { + IDS_SEARCH_ENGINE_CHANGE_WRENCH_MENU_ITEM, + IDS_HOMEPAGE_CHANGE_WRENCH_MENU_ITEM +}; +// IDs of bubble title messages. +const int kBubbleTitleIDs[] = { + IDS_SEARCH_ENGINE_CHANGE_BUBBLE_TITLE, + IDS_HOMEPAGE_CHANGE_BUBBLE_TITLE +}; +// IDs of bubble text messages. +const int kBubbleMessageIDs[] = { + IDS_SEARCH_ENGINE_CHANGE_BUBBLE_TEXT, + IDS_HOMEPAGE_CHANGE_BUBBLE_TEXT +}; +// IDs of bubble text messages when the old setting is unknown. +const int kBubbleMessageOldUnknownIDs[] = { + IDS_SEARCH_ENGINE_CHANGE_UNKNOWN_BUBBLE_TEXT, + IDS_HOMEPAGE_CHANGE_UNKNOWN_BUBBLE_TEXT +}; +// IDs of "Keep Setting" button titles. +const int kBubbleKeepSettingIDs[] = { + IDS_SEARCH_ENGINE_CHANGE_RESTORE, + IDS_HOMEPAGE_CHANGE_RESTORE +}; +// IDs of "Change Setting" button titles. +const int kBubbleChangeSettingIDs[] = { + IDS_SEARCH_ENGINE_CHANGE_APPLY, + IDS_HOMEPAGE_CHANGE_APPLY +}; + +} // namespace + +SettingsChangeGlobalError::SettingsChangeGlobalError( + const ChangesVector& changes, + const base::Closure& make_changes_cb, + const base::Closure& restore_changes_cb) + : changes_(changes), + make_changes_cb_(make_changes_cb), + restore_changes_cb_(restore_changes_cb), + profile_(NULL), + closed_by_button_(false), + ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { + DCHECK(changes.size() > 0); +} + +SettingsChangeGlobalError::~SettingsChangeGlobalError() { +} + +bool SettingsChangeGlobalError::HasBadge() { + return true; +} + +bool SettingsChangeGlobalError::HasMenuItem() { + return true; +} + +int SettingsChangeGlobalError::MenuItemCommandID() { + return IDC_SHOW_SETTINGS_CHANGES; +} + +// TODO(ivankr): Currently the menu item/bubble only displays a warning about +// the first change. We want to fix this so that a single menu item/bubble +// can display warning about multiple changes. + +string16 SettingsChangeGlobalError::MenuItemLabel() { + return l10n_util::GetStringUTF16(kMenuItemLabelIDs[changes_.front().type]); +} + +void SettingsChangeGlobalError::ExecuteMenuItem(Browser* browser) { + weak_factory_.InvalidateWeakPtrs(); // Cancel previously posted tasks. + ShowBubbleView(browser); +} + +bool SettingsChangeGlobalError::HasBubbleView() { + return true; +} + +string16 SettingsChangeGlobalError::GetBubbleViewTitle() { + return l10n_util::GetStringUTF16(kBubbleTitleIDs[changes_.front().type]); +} + +string16 SettingsChangeGlobalError::GetBubbleViewMessage() { + const Change& change = changes_.front(); + return change.old_setting.empty() ? + l10n_util::GetStringFUTF16(kBubbleMessageOldUnknownIDs[change.type], + change.new_setting) : + l10n_util::GetStringFUTF16(kBubbleMessageIDs[change.type], + change.old_setting, change.new_setting); +} + +string16 SettingsChangeGlobalError::GetBubbleViewAcceptButtonLabel() { + const Change& change = changes_.front(); + return change.old_setting.empty() ? + l10n_util::GetStringUTF16(IDS_SETTINGS_CHANGE_OPEN_SETTINGS) : + l10n_util::GetStringFUTF16(kBubbleKeepSettingIDs[change.type], + change.old_setting); +} + +string16 SettingsChangeGlobalError::GetBubbleViewCancelButtonLabel() { + const Change& change = changes_.front(); + return l10n_util::GetStringFUTF16(kBubbleChangeSettingIDs[change.type], + change.new_setting); +} + +void SettingsChangeGlobalError::BubbleViewAcceptButtonPressed() { + VLOG(1) << "Restore changes"; + restore_changes_cb_.Run(); + closed_by_button_ = true; +} + +void SettingsChangeGlobalError::BubbleViewCancelButtonPressed() { + VLOG(1) << "Make changes"; + make_changes_cb_.Run(); + closed_by_button_ = true; +} + +void SettingsChangeGlobalError::RemoveFromProfile() { + if (profile_) + GlobalErrorServiceFactory::GetForProfile(profile_)->RemoveGlobalError(this); + BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this); +} + +void SettingsChangeGlobalError::BubbleViewDidClose() { + if (!closed_by_button_) { + BrowserThread::PostDelayedTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&SettingsChangeGlobalError::RemoveFromProfile, + weak_factory_.GetWeakPtr()), + kMenuItemDisplayPeriodMs); + } else { + RemoveFromProfile(); + } +} + +void SettingsChangeGlobalError::ShowForDefaultProfile() { + if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { + AddToDefaultProfile(); + } else { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&SettingsChangeGlobalError::AddToDefaultProfile, + base::Unretained(this))); + } +} + +void SettingsChangeGlobalError::AddToDefaultProfile() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + profile_ = ProfileManager::GetDefaultProfile(); + GlobalErrorServiceFactory::GetForProfile(profile_)->AddGlobalError(this); + Show(); +} + +void SettingsChangeGlobalError::Show() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(profile_); + Browser* browser = BrowserList::GetLastActiveWithProfile(profile_); + if (browser) + ShowBubbleView(browser); +} diff --git a/chrome/browser/protector/settings_change_global_error.h b/chrome/browser/protector/settings_change_global_error.h new file mode 100644 index 0000000..2c17075 --- /dev/null +++ b/chrome/browser/protector/settings_change_global_error.h @@ -0,0 +1,90 @@ +// Copyright (c) 2011 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_PROTECTOR_SETTINGS_CHANGE_GLOBAL_ERROR_H_ +#define CHROME_BROWSER_PROTECTOR_SETTINGS_CHANGE_GLOBAL_ERROR_H_ +#pragma once + +#include <vector> + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/string16.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/ui/global_error.h" + +class Profile; + +// Global error about unwanted settings changes. +class SettingsChangeGlobalError : public GlobalError { + public: + enum ChangeType { + kSearchEngineChanged = 0, // Default search engine has been changed. + kHomePageChanged, // Home page has been changed. + }; + + struct Change { + ChangeType type; // Which setting has been changed. + string16 old_setting; // Old setting value or "" if unknown. + string16 new_setting; // New setting value. + }; + + typedef std::vector<Change> ChangesVector; + + // Creates new global error about settings changes |changes|. + // If user decides to apply changes, |make_changes_cb| is called. + // If user decides to keep previous settings, |restore_changes_cb| is called. + SettingsChangeGlobalError(const ChangesVector& changes, + const base::Closure& make_changes_cb, + const base::Closure& restore_changes_cb); + virtual ~SettingsChangeGlobalError(); + + // Displays a global error bubble for the default browser profile. + // Can be called from any thread. + void ShowForDefaultProfile(); + + // GlobalError implementation. + virtual bool HasBadge() OVERRIDE; + 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 string16 GetBubbleViewMessage() OVERRIDE; + virtual string16 GetBubbleViewAcceptButtonLabel() OVERRIDE; + virtual string16 GetBubbleViewCancelButtonLabel() OVERRIDE; + virtual void BubbleViewDidClose() OVERRIDE; + virtual void BubbleViewAcceptButtonPressed() OVERRIDE; + virtual void BubbleViewCancelButtonPressed() OVERRIDE; + + private: + ChangesVector changes_; + + base::Closure make_changes_cb_; + base::Closure restore_changes_cb_; + + // Profile that we have been added to. + Profile* profile_; + + // True if user has dismissed the bubble by clicking on one of the buttons. + bool closed_by_button_; + + base::WeakPtrFactory<SettingsChangeGlobalError> weak_factory_; + + // Helper called on the UI thread to add this global error to the default + // profile (stored in |profile_|). + void AddToDefaultProfile(); + + // Displays global error bubble. Must be called on the UI thread. + void Show(); + + // Removes global error from its profile and deletes |this| later. + void RemoveFromProfile(); + + DISALLOW_COPY_AND_ASSIGN(SettingsChangeGlobalError); +}; + +#endif // CHROME_BROWSER_PROTECTOR_SETTINGS_CHANGE_GLOBAL_ERROR_H_ diff --git a/chrome/browser/ui/views/global_error_bubble_view.cc b/chrome/browser/ui/views/global_error_bubble_view.cc index 234181f..00d15db7 100644 --- a/chrome/browser/ui/views/global_error_bubble_view.cc +++ b/chrome/browser/ui/views/global_error_bubble_view.cc @@ -49,20 +49,22 @@ GlobalErrorBubbleView::GlobalErrorBubbleView(Browser* browser, title_label->SetFont(title_label->font().DeriveFont(1)); string16 message_string(error_->GetBubbleViewMessage()); - scoped_ptr<views::Label> message_label(new views::Label(message_string)); - message_label->SetMultiLine(true); - message_label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + message_label_ = new views::Label(message_string); + message_label_->SetMultiLine(true); + message_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); string16 accept_string(error_->GetBubbleViewAcceptButtonLabel()); scoped_ptr<views::TextButton> accept_button( new views::NativeTextButton(this, UTF16ToWideHack(accept_string))); accept_button->SetIsDefault(true); + accept_button->set_tag(TAG_ACCEPT_BUTTON); string16 cancel_string(error_->GetBubbleViewCancelButtonLabel()); scoped_ptr<views::TextButton> cancel_button; if (!cancel_string.empty()) { cancel_button.reset( new views::NativeTextButton(this, UTF16ToWideHack(cancel_string))); + cancel_button->set_tag(TAG_CANCEL_BUTTON); } views::GridLayout* layout = new views::GridLayout(this); @@ -96,7 +98,7 @@ GlobalErrorBubbleView::GlobalErrorBubbleView(Browser* browser, layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing); layout->StartRow(1, 1); - layout->AddView(message_label.release()); + layout->AddView(message_label_); layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing); layout->StartRow(0, 2); @@ -113,18 +115,30 @@ GlobalErrorBubbleView::~GlobalErrorBubbleView() { gfx::Size GlobalErrorBubbleView::GetPreferredSize() { views::GridLayout* layout = static_cast<views::GridLayout*>(GetLayoutManager()); - int height = layout->GetPreferredHeightForWidth(this, kBubbleViewWidth); - return gfx::Size(kBubbleViewWidth, height); + // Buttons row may require bigger width than |kBubbleViewWidth|. To support + // this case, we first set the message label to fit our preferred width. + // Then, get the desired width from GridLayout (it may be bigger than + // |kBubbleViewWidth| if button text is long enough). This width is used as + // the final width for our view, so message label's preferred width is reset + // back to 0. + message_label_->SizeToFit(kBubbleViewWidth); + int width = std::max(layout->GetPreferredSize(this).width(), + kBubbleViewWidth); + message_label_->SizeToFit(0); + int height = layout->GetPreferredHeightForWidth(this, width); + return gfx::Size(width, height); } void GlobalErrorBubbleView::ButtonPressed(views::Button* sender, const views::Event& event) { + DCHECK(bubble_); if (sender->tag() == TAG_ACCEPT_BUTTON) error_->BubbleViewAcceptButtonPressed(); else if (sender->tag() == TAG_CANCEL_BUTTON) error_->BubbleViewCancelButtonPressed(); else NOTREACHED(); + bubble_->Close(); } void GlobalErrorBubbleView::BubbleClosing(Bubble* bubble, @@ -155,6 +169,8 @@ void GlobalError::ShowBubbleView(Browser* browser, GlobalError* error) { GlobalErrorBubbleView* bubble_view = new GlobalErrorBubbleView(browser, error); // Bubble::Show() takes ownership of the view. - Bubble::Show(browser_view->GetWidget(), bounds, - views::BubbleBorder::TOP_RIGHT, bubble_view, bubble_view); + Bubble* bubble = Bubble::Show( + browser_view->GetWidget(), bounds, + views::BubbleBorder::TOP_RIGHT, bubble_view, bubble_view); + bubble_view->set_bubble(bubble); } diff --git a/chrome/browser/ui/views/global_error_bubble_view.h b/chrome/browser/ui/views/global_error_bubble_view.h index 2b17b9e..6c0079e 100644 --- a/chrome/browser/ui/views/global_error_bubble_view.h +++ b/chrome/browser/ui/views/global_error_bubble_view.h @@ -12,6 +12,10 @@ class Browser; class GlobalError; +namespace views { +class Label; +} + class GlobalErrorBubbleView : public views::View, public views::ButtonListener, public BubbleDelegate { @@ -31,10 +35,15 @@ class GlobalErrorBubbleView : public views::View, virtual bool CloseOnEscape() OVERRIDE; virtual bool FadeInOnShow() OVERRIDE; + void set_bubble(Bubble* bubble) { bubble_ = bubble; } + private: Browser* browser_; GlobalError* error_; + views::Label* message_label_; + Bubble* bubble_; + DISALLOW_COPY_AND_ASSIGN(GlobalErrorBubbleView); }; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 5025851..e2a51db 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1949,6 +1949,8 @@ 'browser/profiles/profile_keyed_service_factory.h', 'browser/profiles/profile_manager.cc', 'browser/profiles/profile_manager.h', + 'browser/protector/settings_change_global_error.cc', + 'browser/protector/settings_change_global_error.h', 'browser/remove_rows_table_model.h', 'browser/remoting/firewall_traversal_observer.cc', 'browser/remoting/firewall_traversal_observer.h', |