summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/chrome_command_ids.h1
-rw-r--r--chrome/browser/protector/settings_change_global_error.cc182
-rw-r--r--chrome/browser/protector/settings_change_global_error.h90
-rw-r--r--chrome/browser/ui/views/global_error_bubble_view.cc32
-rw-r--r--chrome/browser/ui/views/global_error_bubble_view.h9
-rw-r--r--chrome/chrome_browser.gypi2
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',