From 1fc025209fbaeb2eb91cfeac8dbced8bc493f3b2 Mon Sep 17 00:00:00 2001
From: "ben@chromium.org"
 <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Tue, 20 Jan 2009 23:03:14 +0000
Subject: Rework the command updater to not be dependent on views::Button
 (needed for porting).

TEST=make sure back/forward buttons still enable/disable correctly depending on the length of the back/forward navigation list.
Review URL: http://codereview.chromium.org/18343

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8332 0039d316-1c4b-4281-b951-d872f2087c98
---
 chrome/browser/autocomplete/autocomplete_edit.cc   |  10 +-
 chrome/browser/autocomplete/autocomplete_edit.h    |   6 +-
 chrome/browser/automation/automation_provider.cc   |  20 +-
 chrome/browser/automation/automation_provider.h    |   1 +
 chrome/browser/browser.cc                          | 292 ++++++++++-----------
 chrome/browser/browser.h                           |  22 +-
 chrome/browser/browser.vcproj                      |   4 +-
 chrome/browser/command_updater.cc                  |  61 +++++
 chrome/browser/command_updater.h                   |  97 +++++++
 chrome/browser/command_updater_unittest.cc         |  99 +++++++
 chrome/browser/controller.cc                       | 118 ---------
 chrome/browser/controller.h                        | 173 ------------
 chrome/browser/controller_unittest.cc              | 103 --------
 .../browser/encoding_menu_controller_delegate.cc   |  24 +-
 chrome/browser/encoding_menu_controller_delegate.h |   9 +-
 chrome/browser/login_prompt.cc                     |   1 -
 chrome/browser/views/browser_views.vcproj          |   8 -
 chrome/browser/views/delay_view.cc                 |  89 -------
 chrome/browser/views/delay_view.h                  |  49 ----
 chrome/browser/views/frame/browser_view.cc         |  21 +-
 chrome/browser/views/go_button.cc                  |   9 +-
 chrome/browser/views/go_button.h                   |   8 +-
 chrome/browser/views/location_bar_view.cc          |  13 +-
 chrome/browser/views/location_bar_view.h           |   8 +-
 chrome/browser/views/toolbar_view.cc               |  54 +++-
 chrome/browser/views/toolbar_view.h                |  17 +-
 chrome/test/unit/unittests.vcproj                  |   2 +-
 chrome/views/controller.h                          |  11 +-
 chrome/views/message_box_view.cc                   |   1 -
 29 files changed, 538 insertions(+), 792 deletions(-)
 create mode 100644 chrome/browser/command_updater.cc
 create mode 100644 chrome/browser/command_updater.h
 create mode 100644 chrome/browser/command_updater_unittest.cc
 delete mode 100644 chrome/browser/controller.cc
 delete mode 100644 chrome/browser/controller.h
 delete mode 100644 chrome/browser/controller_unittest.cc
 delete mode 100644 chrome/browser/views/delay_view.cc
 delete mode 100644 chrome/browser/views/delay_view.h

diff --git a/chrome/browser/autocomplete/autocomplete_edit.cc b/chrome/browser/autocomplete/autocomplete_edit.cc
index 4c4da0e..4928b16 100644
--- a/chrome/browser/autocomplete/autocomplete_edit.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit.cc
@@ -18,7 +18,7 @@
 #include "chrome/browser/autocomplete/edit_drop_target.h"
 #include "chrome/browser/autocomplete/keyword_provider.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/controller.h"
+#include "chrome/browser/command_updater.h"
 #include "chrome/browser/drag_utils.h"
 #include "chrome/browser/metrics/user_metrics.h"
 #include "chrome/browser/net/url_fixer_upper.h"
@@ -659,7 +659,7 @@ AutocompleteEditView::AutocompleteEditView(
     views::View* parent_view,
     HWND hwnd,
     Profile* profile,
-    CommandController* command_controller,
+    CommandUpdater* command_updater,
     bool popup_window_mode)
     : model_(new AutocompleteEditModel(this, controller, profile)),
       popup_model_(new AutocompletePopupModel(font, this, model_.get(),
@@ -667,7 +667,7 @@ AutocompleteEditView::AutocompleteEditView(
       controller_(controller),
       parent_view_(parent_view),
       toolbar_model_(toolbar_model),
-      command_controller_(command_controller),
+      command_updater_(command_updater),
       popup_window_mode_(popup_window_mode),
       tracking_click_(false),
       tracking_double_click_(false),
@@ -1184,7 +1184,7 @@ bool AutocompleteEditView::IsCommandEnabled(int id) const {
     case IDS_PASTE_AND_GO: return CanPasteAndGo(GetClipboardText());
     case IDS_SELECT_ALL:   return !!CanSelectAll();
     case IDS_EDIT_SEARCH_ENGINES:
-      return command_controller_->IsCommandEnabled(IDC_EDIT_SEARCH_ENGINES);
+      return command_updater_->IsCommandEnabled(IDC_EDIT_SEARCH_ENGINES);
     default:               NOTREACHED(); return false;
   }
 }
@@ -1232,7 +1232,7 @@ void AutocompleteEditView::ExecuteCommand(int id) {
       break;
 
     case IDS_EDIT_SEARCH_ENGINES:
-      command_controller_->ExecuteCommand(IDC_EDIT_SEARCH_ENGINES);
+      command_updater_->ExecuteCommand(IDC_EDIT_SEARCH_ENGINES);
       break;
 
     default:
diff --git a/chrome/browser/autocomplete/autocomplete_edit.h b/chrome/browser/autocomplete/autocomplete_edit.h
index dc7d0a5..8bbae11 100644
--- a/chrome/browser/autocomplete/autocomplete_edit.h
+++ b/chrome/browser/autocomplete/autocomplete_edit.h
@@ -21,7 +21,7 @@
 #include "webkit/glue/window_open_disposition.h"
 
 class AutocompletePopupModel;
-class CommandController;
+class CommandUpdater;
 class Profile;
 class TabContents;
 namespace views {
@@ -466,7 +466,7 @@ class AutocompleteEditView
                        views::View* parent_view,
                        HWND hwnd,
                        Profile* profile,
-                       CommandController* command_controller,
+                       CommandUpdater* command_updater,
                        bool popup_window_mode);
   ~AutocompleteEditView();
 
@@ -810,7 +810,7 @@ class AutocompleteEditView
 
   // The object that handles additional command functionality exposed on the
   // edit, such as invoking the keyword editor.
-  CommandController* command_controller_;
+  CommandUpdater* command_updater_;
 
   // When true, the location bar view is read only and also is has a slightly
   // different presentation (font size / color). This is used for popups.
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
index 36cec74..4d82ab1 100644
--- a/chrome/browser/automation/automation_provider.cc
+++ b/chrome/browser/automation/automation_provider.cc
@@ -922,7 +922,7 @@ void AutomationProvider::GoBack(const IPC::Message& message, int handle) {
   if (tab_tracker_->ContainsHandle(handle)) {
     NavigationController* tab = tab_tracker_->GetResource(handle);
     Browser* browser = FindAndActivateTab(tab);
-    if (browser && browser->IsCommandEnabled(IDC_BACK)) {
+    if (browser && browser->command_updater()->IsCommandEnabled(IDC_BACK)) {
       AddNavigationStatusListener(tab,
           new AutomationMsg_GoBackResponse(
               message.routing_id(), AUTOMATION_MSG_NAVIGATION_SUCCESS),
@@ -940,7 +940,7 @@ void AutomationProvider::GoForward(const IPC::Message& message, int handle) {
   if (tab_tracker_->ContainsHandle(handle)) {
     NavigationController* tab = tab_tracker_->GetResource(handle);
     Browser* browser = FindAndActivateTab(tab);
-    if (browser && browser->IsCommandEnabled(IDC_FORWARD)) {
+    if (browser && browser->command_updater()->IsCommandEnabled(IDC_FORWARD)) {
       AddNavigationStatusListener(tab,
           new AutomationMsg_GoForwardResponse(
               message.routing_id(), AUTOMATION_MSG_NAVIGATION_SUCCESS),
@@ -958,7 +958,7 @@ void AutomationProvider::Reload(const IPC::Message& message, int handle) {
   if (tab_tracker_->ContainsHandle(handle)) {
     NavigationController* tab = tab_tracker_->GetResource(handle);
     Browser* browser = FindAndActivateTab(tab);
-    if (browser && browser->IsCommandEnabled(IDC_RELOAD)) {
+    if (browser && browser->command_updater()->IsCommandEnabled(IDC_RELOAD)) {
       AddNavigationStatusListener(tab,
           new AutomationMsg_ReloadResponse(
               message.routing_id(), AUTOMATION_MSG_NAVIGATION_SUCCESS),
@@ -1182,8 +1182,8 @@ void AutomationProvider::ExecuteBrowserCommand(const IPC::Message& message,
   bool success = false;
   if (browser_tracker_->ContainsHandle(handle)) {
     Browser* browser = browser_tracker_->GetResource(handle);
-    if (browser->SupportsCommand(command) &&
-        browser->IsCommandEnabled(command)) {
+    if (browser->command_updater()->SupportsCommand(command) &&
+        browser->command_updater()->IsCommandEnabled(command)) {
       browser->ExecuteCommand(command);
       success = true;
     }
@@ -1651,7 +1651,7 @@ void AutomationProvider::GetTabProcessID(
 void AutomationProvider::ApplyAccelerator(int handle, int id) {
   if (browser_tracker_->ContainsHandle(handle)) {
     Browser* browser = browser_tracker_->GetResource(handle);
-    browser->controller()->ExecuteCommand(id);
+    browser->ExecuteCommand(id);
   }
 }
 
@@ -2211,7 +2211,7 @@ void AutomationProvider::IsPageMenuCommandEnabled(const IPC::Message& message,
   if (browser_tracker_->ContainsHandle(browser_handle)) {
     Browser* browser = browser_tracker_->GetResource(browser_handle);
     bool menu_item_enabled =
-        browser->controller()->IsCommandEnabled(message_num);
+        browser->command_updater()->IsCommandEnabled(message_num);
     Send(new AutomationMsg_IsPageMenuCommandEnabledResponse(
              message.routing_id(), menu_item_enabled));
   } else {
@@ -2246,7 +2246,7 @@ void AutomationProvider::SavePage(const IPC::Message& message,
   NavigationController* nav = tab_tracker_->GetResource(tab_handle);
   Browser* browser = FindAndActivateTab(nav);
   DCHECK(browser);
-  if (!browser->IsCommandEnabled(IDC_SAVE_PAGE)) {
+  if (!browser->command_updater()->IsCommandEnabled(IDC_SAVE_PAGE)) {
     Send(new AutomationMsg_SavePageResponse(message.routing_id(), false));
     return;
   }
@@ -2547,7 +2547,7 @@ void AutomationProvider::GetPageCurrentEncoding(const IPC::Message& message,
     Browser* browser = FindAndActivateTab(nav);
     DCHECK(browser);
 
-    if (browser->IsCommandEnabled(IDC_ENCODING_MENU)) {
+    if (browser->command_updater()->IsCommandEnabled(IDC_ENCODING_MENU)) {
       TabContents* tab_contents = nav->active_contents();
       DCHECK(tab_contents->type() == TAB_CONTENTS_WEB);
       current_encoding = tab_contents->AsWebContents()->encoding();
@@ -2567,7 +2567,7 @@ void AutomationProvider::OverrideEncoding(const IPC::Message& message,
     Browser* browser = FindAndActivateTab(nav);
     DCHECK(browser);
 
-    if (browser->IsCommandEnabled(IDC_ENCODING_MENU)) {
+    if (browser->command_updater()->IsCommandEnabled(IDC_ENCODING_MENU)) {
       TabContents* tab_contents = nav->active_contents();
       DCHECK(tab_contents->type() == TAB_CONTENTS_WEB);
       int selected_encoding_id =
diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h
index 5467b79..0022369 100644
--- a/chrome/browser/automation/automation_provider.h
+++ b/chrome/browser/automation/automation_provider.h
@@ -25,6 +25,7 @@
 #include "chrome/common/ipc_channel_proxy.h"
 #include "chrome/common/ipc_message.h"
 #include "chrome/common/notification_service.h"
+#include "chrome/views/event.h"
 
 class LoginHandler;
 class NavigationControllerRestoredObserver;
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc
index 64d3ef5..54f3789 100644
--- a/chrome/browser/browser.cc
+++ b/chrome/browser/browser.cc
@@ -149,7 +149,7 @@ Browser::Browser(Type type, Profile* profile)
       profile_(profile),
       window_(NULL),
       tabstrip_model_(this, profile),
-      controller_(this),
+      command_updater_(this),
       toolbar_model_(this),
       chrome_updater_factory_(this),
       is_attempting_to_close_browser_(false),
@@ -292,27 +292,6 @@ void Browser::OpenWebApplication(Profile* profile, WebApp* app) {
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// Browser, Command API:
-
-bool Browser::SupportsCommand(int id) const {
-  return controller_.SupportsCommand(id);
-}
-
-bool Browser::IsCommandEnabled(int id) const {
-  // No commands are enabled if there is not yet any selected tab.
-  // TODO(pkasting): It seems like we should not need this, because either
-  // most/all commands should not have been enabled yet anyway or the ones that
-  // are enabled should be global, or safe themselves against having no selected
-  // tab.  However, Ben says he tried removing this before and got lots of
-  // crashes, e.g. from Windows sending WM_COMMANDs at random times during
-  // window construction.  This probably could use closer examination someday.
-  if (!GetSelectedTabContents())
-    return false;
-
-  return controller_.IsCommandEnabled(id);
-}
-
-///////////////////////////////////////////////////////////////////////////////
 // Browser, State Storage and Retrieval for UI:
 
 std::wstring Browser::GetWindowPlacementKey() const {
@@ -1078,10 +1057,20 @@ Browser* Browser::GetBrowserForController(
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// Browser, CommandHandler implementation:
+// Browser, CommandUpdater::CommandUpdaterDelegate implementation:
 
 void Browser::ExecuteCommand(int id) {
-  DCHECK(IsCommandEnabled(id)) << "Invalid or disabled command";
+  // No commands are enabled if there is not yet any selected tab.
+  // TODO(pkasting): It seems like we should not need this, because either
+  // most/all commands should not have been enabled yet anyway or the ones that
+  // are enabled should be global, or safe themselves against having no selected
+  // tab.  However, Ben says he tried removing this before and got lots of
+  // crashes, e.g. from Windows sending WM_COMMANDs at random times during
+  // window construction.  This probably could use closer examination someday.
+  if (!GetSelectedTabContents())
+    return;
+
+  DCHECK(command_updater_.IsCommandEnabled(id)) << "Invalid/disabled command";
 
   // The order of commands in this switch statement must match the function
   // declaration order in browser.h!
@@ -1764,7 +1753,7 @@ void Browser::UpdateTargetURL(TabContents* source, const GURL& url) {
 }
 
 void Browser::ContentsZoomChange(bool zoom_in) {
-  controller_.ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS);
+  ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS);
 }
 
 bool Browser::IsApplication() const {
@@ -1890,128 +1879,132 @@ void Browser::InitCommandState() {
   // initialized here, otherwise they will be forever disabled.
 
   // Navigation commands
-  controller_.UpdateCommandEnabled(IDC_RELOAD, true);
+  command_updater_.UpdateCommandEnabled(IDC_RELOAD, true);
 
   // Window management commands
-  controller_.UpdateCommandEnabled(IDC_NEW_WINDOW, true);
-  controller_.UpdateCommandEnabled(IDC_NEW_INCOGNITO_WINDOW, true);
+  command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW, true);
+  command_updater_.UpdateCommandEnabled(IDC_NEW_INCOGNITO_WINDOW, true);
   // TODO(pkasting): Perhaps the code that populates this submenu should do
   // this?
-  controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_0, true);
-  controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_1, true);
-  controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_2, true);
-  controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_3, true);
-  controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_4, true);
-  controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_5, true);
-  controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_6, true);
-  controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_7, true);
-  controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_8, true);
-  controller_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true);
-  controller_.UpdateCommandEnabled(IDC_NEW_TAB, true);
-  controller_.UpdateCommandEnabled(IDC_CLOSE_TAB, true);
-  controller_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true);
-  controller_.UpdateCommandEnabled(IDC_EXIT, true);
+  command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_0, true);
+  command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_1, true);
+  command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_2, true);
+  command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_3, true);
+  command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_4, true);
+  command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_5, true);
+  command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_6, true);
+  command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_7, true);
+  command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_8, true);
+  command_updater_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true);
+  command_updater_.UpdateCommandEnabled(IDC_NEW_TAB, true);
+  command_updater_.UpdateCommandEnabled(IDC_CLOSE_TAB, true);
+  command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true);
+  command_updater_.UpdateCommandEnabled(IDC_EXIT, true);
 
   // Page-related commands
-  controller_.UpdateCommandEnabled(IDC_CLOSE_POPUPS, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_AUTO_DETECT, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_UTF8, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_UTF16LE, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88591, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1252, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_GBK, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_GB18030, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_BIG5HKSCS, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_BIG5, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_THAI, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_KOREAN, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_SHIFTJIS, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_ISO2022JP, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_EUCJP, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885915, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_MACINTOSH, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88592, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1250, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88595, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1251, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_KOI8R, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_KOI8U, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88597, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1253, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88594, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885913, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1257, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88593, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885910, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885914, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885916, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1254, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88596, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1256, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88598, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1255, true);
-  controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1258, true);
+  command_updater_.UpdateCommandEnabled(IDC_CLOSE_POPUPS, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_AUTO_DETECT, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF8, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF16LE, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88591, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1252, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_GBK, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_GB18030, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5HKSCS, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_THAI, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOREAN, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_SHIFTJIS, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO2022JP, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_EUCJP, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885915, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_MACINTOSH, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88592, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1250, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88595, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1251, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8R, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8U, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88597, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1253, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88594, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885913, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1257, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88593, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885910, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885914, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885916, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1254, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88596, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1256, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1255, true);
+  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1258, true);
 
   // Clipboard commands
-  controller_.UpdateCommandEnabled(IDC_CUT, true);
-  controller_.UpdateCommandEnabled(IDC_COPY, true);
-  controller_.UpdateCommandEnabled(IDC_COPY_URL, true);
-  controller_.UpdateCommandEnabled(IDC_PASTE, true);
+  command_updater_.UpdateCommandEnabled(IDC_CUT, true);
+  command_updater_.UpdateCommandEnabled(IDC_COPY, true);
+  command_updater_.UpdateCommandEnabled(IDC_COPY_URL, true);
+  command_updater_.UpdateCommandEnabled(IDC_PASTE, true);
 
   // Show various bits of UI
-  controller_.UpdateCommandEnabled(IDC_OPEN_FILE, true);
-  controller_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false);
-  controller_.UpdateCommandEnabled(IDC_TASK_MANAGER, true);
-  controller_.UpdateCommandEnabled(IDC_SELECT_PROFILE, true);
-  controller_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true);
-  controller_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER, true);
-  controller_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
-  controller_.UpdateCommandEnabled(IDC_HELP_PAGE, true);
+  command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, true);
+  command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false);
+  command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, true);
+  command_updater_.UpdateCommandEnabled(IDC_SELECT_PROFILE, true);
+  command_updater_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true);
+  command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER, true);
+  command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
+  command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE, true);
 
   // Initialize other commands based on the window type.
   {
     bool normal_window = type() == TYPE_NORMAL;
 
     // Navigation commands
-    controller_.UpdateCommandEnabled(IDC_HOME, normal_window);
-    controller_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_HOME, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, normal_window);
 
     // Window management commands
-    controller_.UpdateCommandEnabled(IDC_PROFILE_MENU, normal_window);
-    controller_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window);
-    controller_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB, normal_window);
-    controller_.UpdateCommandEnabled(IDC_SELECT_TAB_0, normal_window);
-    controller_.UpdateCommandEnabled(IDC_SELECT_TAB_1, normal_window);
-    controller_.UpdateCommandEnabled(IDC_SELECT_TAB_2, normal_window);
-    controller_.UpdateCommandEnabled(IDC_SELECT_TAB_3, normal_window);
-    controller_.UpdateCommandEnabled(IDC_SELECT_TAB_4, normal_window);
-    controller_.UpdateCommandEnabled(IDC_SELECT_TAB_5, normal_window);
-    controller_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window);
-    controller_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window);
-    controller_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window);
-    controller_.UpdateCommandEnabled(IDC_RESTORE_TAB,
+    command_updater_.UpdateCommandEnabled(IDC_PROFILE_MENU, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB,
+                                          normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_0, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_1, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_2, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_3, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_4, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_5, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB,
         normal_window && !profile_->IsOffTheRecord());
-    controller_.UpdateCommandEnabled(IDC_SHOW_AS_TAB, (type() == TYPE_POPUP));
+    command_updater_.UpdateCommandEnabled(IDC_SHOW_AS_TAB,
+                                          (type() == TYPE_POPUP));
 
     // Focus various bits of UI
-    controller_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, normal_window);
-    controller_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, normal_window);
-    controller_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, normal_window);
 
     // Show various bits of UI
-    controller_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, normal_window);
-    controller_.UpdateCommandEnabled(IDC_DEBUGGER,
+    command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_DEBUGGER,
         // The debugger doesn't work in single process mode.
         normal_window && !RenderProcessHost::run_renderer_in_process());
-    controller_.UpdateCommandEnabled(IDC_NEW_PROFILE, normal_window);
-    controller_.UpdateCommandEnabled(IDC_REPORT_BUG, normal_window);
-    controller_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR, normal_window);
-    controller_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA, normal_window);
-    controller_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, normal_window);
-    controller_.UpdateCommandEnabled(IDC_OPTIONS, normal_window);
-    controller_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, normal_window);
-    controller_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, normal_window);
-    controller_.UpdateCommandEnabled(IDC_ABOUT, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_NEW_PROFILE, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_REPORT_BUG, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA,
+                                          normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_OPTIONS, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES,
+                                          normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, normal_window);
+    command_updater_.UpdateCommandEnabled(IDC_ABOUT, normal_window);
   }
 }
 
@@ -2022,12 +2015,12 @@ void Browser::UpdateCommandsForTabState() {
 
   // Navigation commands
   NavigationController* nc = current_tab->controller();
-  controller_.UpdateCommandEnabled(IDC_BACK, nc->CanGoBack());
-  controller_.UpdateCommandEnabled(IDC_FORWARD, nc->CanGoForward());
+  command_updater_.UpdateCommandEnabled(IDC_BACK, nc->CanGoBack());
+  command_updater_.UpdateCommandEnabled(IDC_FORWARD, nc->CanGoForward());
 
   // Window management commands
-  controller_.UpdateCommandEnabled(IDC_DUPLICATE_TAB,
-                                   CanDuplicateContentsAt(selected_index()));
+  command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB,
+      CanDuplicateContentsAt(selected_index()));
 
   // Initialize commands available only for web content.
   {
@@ -2036,56 +2029,51 @@ void Browser::UpdateCommandsForTabState() {
 
     // Page-related commands
     // Only allow bookmarking for tabbed browsers.
-    controller_.UpdateCommandEnabled(IDC_STAR,
+    command_updater_.UpdateCommandEnabled(IDC_STAR,
         is_web_contents && (type() == TYPE_NORMAL));
     SetStarredButtonToggled(is_web_contents && web_contents->is_starred());
     // View-source should not be enabled if already in view-source mode.
-    controller_.UpdateCommandEnabled(IDC_VIEW_SOURCE,
+    command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE,
         is_web_contents && (current_tab->type() != TAB_CONTENTS_VIEW_SOURCE) &&
         current_tab->controller()->GetActiveEntry());
-    controller_.UpdateCommandEnabled(IDC_PRINT, is_web_contents);
-    controller_.UpdateCommandEnabled(IDC_SAVE_PAGE,
+    command_updater_.UpdateCommandEnabled(IDC_PRINT, is_web_contents);
+    command_updater_.UpdateCommandEnabled(IDC_SAVE_PAGE,
         is_web_contents && SavePackage::IsSavableURL(current_tab->GetURL()));
-    controller_.UpdateCommandEnabled(IDC_ENCODING_MENU,
+    command_updater_.UpdateCommandEnabled(IDC_ENCODING_MENU,
         is_web_contents &&
         SavePackage::IsSavableContents(web_contents->contents_mime_type()) &&
         SavePackage::IsSavableURL(current_tab->GetURL()));
 
     // Find-in-page
-    controller_.UpdateCommandEnabled(IDC_FIND, is_web_contents);
-    controller_.UpdateCommandEnabled(IDC_FIND_NEXT, is_web_contents);
-    controller_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, is_web_contents);
+    command_updater_.UpdateCommandEnabled(IDC_FIND, is_web_contents);
+    command_updater_.UpdateCommandEnabled(IDC_FIND_NEXT, is_web_contents);
+    command_updater_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, is_web_contents);
 
     // Zoom
-    controller_.UpdateCommandEnabled(IDC_ZOOM_MENU, is_web_contents);
-    controller_.UpdateCommandEnabled(IDC_ZOOM_PLUS, is_web_contents);
-    controller_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, is_web_contents);
-    controller_.UpdateCommandEnabled(IDC_ZOOM_MINUS, is_web_contents);
+    command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, is_web_contents);
+    command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, is_web_contents);
+    command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, is_web_contents);
+    command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, is_web_contents);
 
     // Show various bits of UI
-    controller_.UpdateCommandEnabled(IDC_JS_CONSOLE, is_web_contents);
-    controller_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
+    command_updater_.UpdateCommandEnabled(IDC_JS_CONSOLE, is_web_contents);
+    command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
         is_web_contents && !current_tab->GetFavIcon().isNull());
   }
 }
 
 void Browser::UpdateStopGoState(bool is_loading) {
   GoButton* go_button = GetGoButton();
-  if (!go_button)
-    return;
-
-  go_button->ChangeMode(is_loading ?
-      GoButton::MODE_STOP : GoButton::MODE_GO);
-  controller_.UpdateCommandEnabled(IDC_GO, !is_loading);
-  controller_.UpdateCommandEnabled(IDC_STOP, is_loading);
+  if (go_button)
+    go_button->ChangeMode(is_loading ? GoButton::MODE_STOP : GoButton::MODE_GO);
+  command_updater_.UpdateCommandEnabled(IDC_GO, !is_loading);
+  command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading);
 }
 
 void Browser::SetStarredButtonToggled(bool starred) {
   ToolbarStarToggle* star_button = window_->GetStarButton();
-  if (!star_button)
-    return;
-
-  star_button->SetToggled(starred);
+  if (star_button)
+    star_button->SetToggled(starred);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -2189,7 +2177,7 @@ void Browser::ProcessPendingUIUpdates() {
 
       if (contents == GetSelectedTabContents()) {
         TabContents* current_tab = GetSelectedTabContents();
-        controller_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
+        command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
             current_tab->type() == TAB_CONTENTS_WEB &&
             !current_tab->GetFavIcon().isNull());
       }
diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h
index aba16c3..1faa8ab 100644
--- a/chrome/browser/browser.h
+++ b/chrome/browser/browser.h
@@ -8,7 +8,7 @@
 #include <vector>
 
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/controller.h"
+#include "chrome/browser/command_updater.h"
 #include "chrome/browser/shell_dialogs.h"
 #include "chrome/browser/browser_window.h"
 #include "chrome/browser/sessions/session_id.h"
@@ -33,7 +33,7 @@ class WebApp;
 class Browser : public TabStripModelDelegate,
                 public TabStripModelObserver,
                 public TabContentsDelegate,
-                public CommandHandler,
+                public CommandUpdater::CommandUpdaterDelegate,
                 public NotificationObserver,
                 public SelectFileDialog::Listener {
  public:
@@ -92,7 +92,7 @@ class Browser : public TabStripModelDelegate,
   BrowserWindow* window() const { return window_; }
   ToolbarModel* toolbar_model() { return &toolbar_model_; }
   const SessionID& session_id() const { return session_id_; }
-  CommandController* controller() { return &controller_; }
+  CommandUpdater* command_updater() { return &command_updater_; }
 
   // Setters /////////////////////////////////////////////////////////////////
 
@@ -113,13 +113,6 @@ class Browser : public TabStripModelDelegate,
   // Opens the a new application window for the specified WebApp.
   static void OpenWebApplication(Profile* profile, WebApp* app);
 
-  // Command API //////////////////////////////////////////////////////////////
-
-  // Please fix the incestuous nest that is */controller.h and eliminate the
-  // need for this retarded hack.
-  bool SupportsCommand(int id) const;
-  bool IsCommandEnabled(int id) const;
-
   // State Storage and Retrieval for UI ///////////////////////////////////////
 
   // Save and restore the window position.
@@ -313,10 +306,7 @@ class Browser : public TabStripModelDelegate,
 
   // Interface implementations ////////////////////////////////////////////////
 
-  // Overridden from CommandHandler:
-  virtual bool GetContextualLabel(int id, std::wstring* out) const {
-    return false;
-  }
+  // Overridden from CommandUpdater::CommandUpdaterDelegate:
   virtual void ExecuteCommand(int id);
 
   // Overridden from TabStripModelDelegate:
@@ -536,8 +526,8 @@ class Browser : public TabStripModelDelegate,
   // This Browser's TabStripModel.
   TabStripModel tabstrip_model_;
 
-  // The Controller that updates all browser commands.
-  CommandController controller_;
+  // The CommandUpdater that manages the browser window commands.
+  CommandUpdater command_updater_;
 
   // An optional application name which is used to retrieve and save window
   // positions.
diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj
index 13140b5..19cc20a 100644
--- a/chrome/browser/browser.vcproj
+++ b/chrome/browser/browser.vcproj
@@ -762,11 +762,11 @@
 				>
 			</File>
 			<File
-				RelativePath=".\controller.cc"
+				RelativePath=".\command_updater.cc"
 				>
 			</File>
 			<File
-				RelativePath=".\controller.h"
+				RelativePath=".\command_updater.h"
 				>
 			</File>
 			<File
diff --git a/chrome/browser/command_updater.cc b/chrome/browser/command_updater.cc
new file mode 100644
index 0000000..8839965
--- /dev/null
+++ b/chrome/browser/command_updater.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2006-2008 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 <algorithm>
+
+#include "chrome/browser/command_updater.h"
+
+#include "base/logging.h"
+#include "chrome/common/stl_util-inl.h"
+
+CommandUpdater::CommandUpdater(CommandUpdaterDelegate* handler)
+    : delegate_(handler) {
+}
+
+CommandUpdater::~CommandUpdater() {
+  STLDeleteContainerPairSecondPointers(commands_.begin(), commands_.end());
+}
+
+bool CommandUpdater::IsCommandEnabled(int id) const {
+  const CommandMap::const_iterator command(commands_.find(id));
+  if (command == commands_.end())
+    return false;
+  return command->second->enabled;
+}
+
+bool CommandUpdater::SupportsCommand(int id) const {
+  return commands_.find(id) != commands_.end();
+}
+
+void CommandUpdater::ExecuteCommand(int id) {
+  if (IsCommandEnabled(id))
+    delegate_->ExecuteCommand(id);
+}
+
+void CommandUpdater::UpdateCommandEnabled(int id, bool enabled) {
+  Command* command = GetCommand(id, true);
+  if (command->enabled == enabled)
+    return;  // Nothing to do.
+  command->enabled = enabled;
+  FOR_EACH_OBSERVER(CommandObserver, command->observers,
+                    EnabledStateChangedForCommand(id, enabled));
+}
+
+CommandUpdater::Command* CommandUpdater::GetCommand(int id, bool create) {
+  bool supported = SupportsCommand(id);
+  if (supported)
+    return commands_[id];
+  DCHECK(create);
+  Command* command = new Command;
+  commands_[id] = command;
+  return command;
+}
+
+void CommandUpdater::AddCommandObserver(int id, CommandObserver* observer) {
+  GetCommand(id, true)->observers.AddObserver(observer);
+}
+
+void CommandUpdater::RemoveCommandObserver(int id, CommandObserver* observer) {
+  GetCommand(id, false)->observers.RemoveObserver(observer);
+}
diff --git a/chrome/browser/command_updater.h b/chrome/browser/command_updater.h
new file mode 100644
index 0000000..ef937c6
--- /dev/null
+++ b/chrome/browser/command_updater.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2006-2008 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_COMMAND_UPDATER_H_
+#define CHROME_BROWSER_COMMAND_UPDATER_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/hash_tables.h"
+#include "base/observer_list.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// CommandUpdater class
+//
+//   This object manages the enabled state of a set of commands. Observers
+//   register to listen to changes in this state so they can update their
+//   presentation.
+//
+class CommandUpdater {
+ public:
+  // A Delegate object implements this interface so that it can execute commands
+  // when needed.
+  class CommandUpdaterDelegate {
+   public:
+    // Perform the action associated with the command with the specified ID.
+    virtual void ExecuteCommand(int id) = 0;
+  };
+
+  // Create a CommandUpdater with a CommandUpdaterDelegate to handle execution
+  // of specific commands.
+  explicit CommandUpdater(CommandUpdaterDelegate* handler);
+  virtual ~CommandUpdater();
+
+  // Returns true if the specified command ID is supported.
+  bool SupportsCommand(int id) const;
+
+  // Returns true if the specified command ID is enabled. The command ID must be
+  // supported by this updater.
+  bool IsCommandEnabled(int id) const;
+
+  // Performs the action associated with this command ID.
+  // TODO(beng): get rid of this since it's effectively just a pass-thru and the
+  // call sites would be better off using more well defined delegate interfaces.
+  void ExecuteCommand(int id);
+
+  // An Observer interface implemented by objects that want to be informed when
+  // the state of a particular command ID is modified.
+  class CommandObserver {
+   public:
+    // Notifies the observer that the enabled state has changed for the
+    // specified command id.
+    virtual void EnabledStateChangedForCommand(int id, bool enabled) = 0;
+  };
+
+  // Adds an observer to the state of a particular command. If the command does
+  // not exist, it is created, initialized to false.
+  void AddCommandObserver(int id, CommandObserver* observer);
+
+  // Removes an observer to the state of a particular command.
+  void RemoveCommandObserver(int id, CommandObserver* observer);
+
+  // Notify all observers of a particular command that the command has been
+  // enabled or disabled. If the command does not exist, it is created and
+  // initialized to |state|. This function is very lightweight if the command
+  // state has not changed.
+  void UpdateCommandEnabled(int id, bool state);
+
+ private:
+  // A piece of data about a command - whether or not it is enabled, and a list
+  // of objects that observe the enabled state of this command.
+  class Command {
+   public:
+    bool enabled;
+    ObserverList<CommandObserver> observers;
+
+    Command() : enabled(true) {}
+  };
+
+  // Get a Command node for a given command ID, creating an entry if it doesn't
+  // exist if desired.
+  Command* GetCommand(int id, bool create);
+
+  // The delegate is responsible for executing commands.
+  CommandUpdaterDelegate* delegate_;
+
+  // This is a map of command IDs to states and observer lists
+  typedef base::hash_map<int, Command*> CommandMap;
+  CommandMap commands_;
+
+  CommandUpdater();
+  DISALLOW_EVIL_CONSTRUCTORS(CommandUpdater);
+};
+
+#endif // CHROME_BROWSER_COMMAND_UPDATER_H_
diff --git a/chrome/browser/command_updater_unittest.cc b/chrome/browser/command_updater_unittest.cc
new file mode 100644
index 0000000..9100753
--- /dev/null
+++ b/chrome/browser/command_updater_unittest.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2006-2008 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 "base/logging.h"
+#include "chrome/browser/command_updater.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class TestingCommandHandlerMock
+    : public CommandUpdater::CommandUpdaterDelegate {
+ public:
+  virtual void ExecuteCommand(int id) {
+    EXPECT_EQ(1, id);
+  }
+};
+
+class CommandUpdaterTest : public testing::Test {
+};
+
+class TestingCommandObserverMock : public CommandUpdater::CommandObserver {
+ public:
+  virtual void EnabledStateChangedForCommand(int id, bool enabled) {
+    enabled_ = enabled;
+  }
+
+  bool enabled() const { return enabled_; }
+
+ private:
+  bool enabled_;
+};
+
+TEST_F(CommandUpdaterTest, TestBasicAPI) {
+  TestingCommandHandlerMock handler;
+  CommandUpdater command_updater(&handler);
+
+  // Unsupported command
+  EXPECT_FALSE(command_updater.SupportsCommand(0));
+  EXPECT_FALSE(command_updater.IsCommandEnabled(0));
+  // TestingCommandHandlerMock::ExecuteCommand should not be called, since
+  // the command is not supported.
+  command_updater.ExecuteCommand(0);
+
+  // Supported, enabled command
+  command_updater.UpdateCommandEnabled(1, true);
+  EXPECT_TRUE(command_updater.SupportsCommand(1));
+  EXPECT_TRUE(command_updater.IsCommandEnabled(1));
+  command_updater.ExecuteCommand(1);
+
+  // Supported, disabled command
+  command_updater.UpdateCommandEnabled(2, false);
+  EXPECT_TRUE(command_updater.SupportsCommand(2));
+  EXPECT_FALSE(command_updater.IsCommandEnabled(2));
+  // TestingCommandHandlerMock::ExecuteCommmand should not be called, since
+  // the command_updater is disabled
+  command_updater.ExecuteCommand(2);
+}
+
+TEST_F(CommandUpdaterTest, TestObservers) {
+  TestingCommandHandlerMock handler;
+  CommandUpdater command_updater(&handler);
+
+  // Create an observer for the command 2 and add it to the controller, then
+  // update the command.
+  TestingCommandObserverMock observer;
+  command_updater.AddCommandObserver(2, &observer);
+  command_updater.UpdateCommandEnabled(2, true);
+  EXPECT_TRUE(observer.enabled());
+  command_updater.UpdateCommandEnabled(2, false);
+  EXPECT_FALSE(observer.enabled());
+
+  // Remove the observer and update the command.
+  command_updater.RemoveCommandObserver(2, &observer);
+  command_updater.UpdateCommandEnabled(2, true);
+  EXPECT_FALSE(observer.enabled());
+}
+
+TEST_F(CommandUpdaterTest, TestRemoveObserverForUnsupportedCommand) {
+  TestingCommandHandlerMock handler;
+  CommandUpdater command_updater(&handler);
+
+  // Test removing observers for commands that are unsupported
+  TestingCommandObserverMock observer;
+  command_updater.RemoveCommandObserver(3, &observer);
+}
+
+TEST_F(CommandUpdaterTest, TestAddingNullObserver) {
+  TestingCommandHandlerMock handler;
+  CommandUpdater command_updater(&handler);
+
+  // Test adding/removing NULL observers
+  command_updater.AddCommandObserver(4, NULL);
+}
+
+TEST_F(CommandUpdaterTest, TestRemovingNullObserver) {
+  TestingCommandHandlerMock handler;
+  CommandUpdater command_updater(&handler);
+
+  command_updater.RemoveCommandObserver(4, NULL);
+}
diff --git a/chrome/browser/controller.cc b/chrome/browser/controller.cc
deleted file mode 100644
index a9a7619..0000000
--- a/chrome/browser/controller.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright (c) 2006-2008 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 <algorithm>
-
-#include "chrome/browser/controller.h"
-#include "base/logging.h"
-
-CommandController::CommandController(CommandHandler* handler) :
-    handler_(handler) {
-}
-
-CommandController::~CommandController() {
-  // The button controllers are command observers hence this list
-  // must be deleted before the commands below.
-  std::vector<ButtonController*>::iterator bc_iter;
-  for (bc_iter = managed_button_controllers_.begin();
-       bc_iter != managed_button_controllers_.end();
-       ++bc_iter)
-    delete *bc_iter;
-
-  CommandMap::iterator command;
-  for (command = commands_.begin(); command != commands_.end(); ++command) {
-    DCHECK(command->second);
-    delete command->second->observers;
-    delete command->second;
-  }
-}
-
-bool CommandController::IsCommandEnabled(int id) const {
-  const CommandMap::const_iterator command(commands_.find(id));
-  if (command == commands_.end())
-    return false;
-
-  DCHECK(command->second);
-  return command->second->enabled;
-}
-
-bool CommandController::SupportsCommand(int id) const {
-  return commands_.find(id) != commands_.end();
-}
-
-bool CommandController::GetContextualLabel(int id, std::wstring* out) const {
-  return handler_->GetContextualLabel(id, out);
-}
-
-void CommandController::ExecuteCommand(int id) {
-  if (IsCommandEnabled(id))
-    handler_->ExecuteCommand(id);
-}
-
-void CommandController::UpdateCommandEnabled(int id, bool enabled) {
-  Command* command = GetCommand(id, true);
-  if (command->enabled == enabled)
-    return;  // Nothing to do.
-  command->enabled = enabled;
-  CommandObserverList* list = command->observers;
-
-  // FIXME: If Update calls RemoveCommandObserver, the iterator will be
-  //        invalidated. Darin says he's working on a new ObserverList
-  //        class that will handle this properly. For right now, don't
-  //        do that!
-  CommandObserverList::const_iterator end = list->end();
-  CommandObserverList::iterator observer = list->begin();
-  while (observer != end)
-    (*observer++)->SetEnabled(enabled);
-}
-
-Command* CommandController::GetCommand(int id, bool create) {
-  Command* command = NULL;
-  bool supported = SupportsCommand(id);
-  if (supported) {
-    command = commands_[id];
-  } else if (create) {
-    command = new Command;
-    DCHECK(command) << "Controller::GetCommand - OOM!";
-    command->observers = new CommandObserverList;
-    DCHECK(command->observers) << "Controller::GetCommand - OOM!";
-    command->enabled = false;
-    commands_[id] = command;
-  }
-  return command;
-}
-
-void CommandController::AddCommandObserver(int id, CommandObserver* observer) {
-  Command* command = GetCommand(id, true);
-  CommandObserverList* list = command->observers;
-
-  CommandObserverList::const_iterator end = list->end();
-  CommandObserverList::iterator existing =
-      find(list->begin(), list->end(), observer);
-  if (existing != end)
-    return;
-
-  list->push_back(observer);
-}
-
-void CommandController::RemoveCommandObserver(int id,
-                                              CommandObserver* observer) {
-  Command* command = GetCommand(id, false);
-  if (!command)
-    return;
-
-  CommandObserverList* list = command->observers;
-  CommandObserverList::const_iterator end = list->end();
-  CommandObserverList::iterator existing =
-      find(list->begin(), list->end(), observer);
-
-  if (existing != end)
-    list->erase(existing);
-}
-
-void CommandController::AddManagedButton(views::Button* b, int command) {
-  ButtonController* bc = new ButtonController(b, this, command);
-  managed_button_controllers_.push_back(bc);
-}
-
diff --git a/chrome/browser/controller.h b/chrome/browser/controller.h
deleted file mode 100644
index 246c841..0000000
--- a/chrome/browser/controller.h
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright (c) 2006-2008 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_CONTROLLER_H__
-#define CHROME_BROWSER_CONTROLLER_H__
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/hash_tables.h"
-#include "chrome/views/button.h"
-#include "chrome/views/controller.h"
-
-class ButtonController;
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// CommandObserver interface
-//
-//   A component of the View portion of the MVC pattern implements the
-//   CommandObserver interface to update itself when the state of its command
-//   changes.
-//
-///////////////////////////////////////////////////////////////////////////////
-class CommandObserver {
- public:
-  // Update the View because this command's enabled state has changed.
-  virtual void SetEnabled(bool enabled) = 0;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// CommandHandler interface
-//
-//   An object implementing the CommandHandler interface is responsible for
-//   actually executing specific commands.
-//
-//   This object is also responsible for producing contextual labels if needed.
-//
-///////////////////////////////////////////////////////////////////////////////
-class CommandHandler {
- public:
-
-  // This method is called to give the command handler a chance to specify
-  // a contextual label for the provided command id. Returns true if a
-  // contextual label has been assigned or false if the default label should be
-  // used.
-  virtual bool GetContextualLabel(int id, std::wstring* out) const {
-    return false;
-  }
-
-  // Whether the specified command can be executed.
-  virtual bool IsCommandEnabled(int id) const { return true; }
-
-  // Execute a command, according to the command's state (currently binary!)
-  virtual void ExecuteCommand(int id) = 0;
-};
-
-typedef std::vector<CommandObserver*> CommandObserverList;
-
-// A piece of data about a command - whether or not it is enabled, and a list
-// of objects that observe the enabled state of this command.
-struct Command {
-  bool enabled;
-  CommandObserverList* observers;
-};
-typedef base::hash_map<int, Command*> CommandMap;
-
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// Controller class
-//
-//   This is the Controller portion of a MVC pattern. It handles dispatching
-//   commands, maintaining enabled state, and updating the UI as that state
-//   changes. The purpose of using MVC and a controller like this is to
-//   maintain a clear separation between rendering, control logic and various
-//   data sources so that code is more maintainable.
-//
-///////////////////////////////////////////////////////////////////////////////
-class CommandController : public Controller {
- public:
-  // The controller is constructed with an object implementing the
-  // CommandHandler interface, to which the Controller defers execution
-  // duties. This keeps the Controller fairly simple without requiring a
-  // lot of reworking of the command handlers. If there are significant
-  // groups of commands that require execution separated from this handler,
-  // then the Command object can be extended to provide a handler field that
-  // specifies a handler different to the default.
-  CommandController(CommandHandler* handler);
-  virtual ~CommandController();
-
-  // Add a button to the list of managed buttons. The button is synced with
-  // the provided command
-  void AddManagedButton(views::Button* button, int command);
-
-  // Controller
-  virtual bool SupportsCommand(int id) const;
-  virtual bool IsCommandEnabled(int id) const;
-  virtual bool GetContextualLabel(int id, std::wstring* out) const;
-  virtual void ExecuteCommand(int id);
-
-
-  // Adds an observer to the state of a particular command. If the command does
-  // not exist, it is created, initialized to false.
-  void AddCommandObserver(int id, CommandObserver* observer);
-
-  // Removes an observer to the state of a particular command.
-  void RemoveCommandObserver(int id, CommandObserver* observer);
-
-  // Notify all observers of a particular command that the command has been
-  // enabled or disabled. If the command does not exist, it is created and
-  // initialized to |state|. This function is very lightweight if the command
-  // state has not changed.
-  void UpdateCommandEnabled(int id, bool state);
-
- private:
-  ///////////////////////////////////////////////////////////////////////////////
-  //
-  // ButtonController
-  //
-  // An adapter class to use views buttons with our controller
-  //
-  ///////////////////////////////////////////////////////////////////////////////
-  class ButtonController : public views::BaseButton::ButtonListener,
-                           public CommandObserver {
-
-   public:
-
-    ButtonController(views::Button* b,
-                     CommandController* controller,
-                     int command)
-        : button_(b),
-          controller_(controller) {
-      controller_->AddCommandObserver(command, this);
-      button_->SetListener(this, command);
-
-      // The button's initial state should be the current command state.
-      button_->SetEnabled(controller_->IsCommandEnabled(command));
-    }
-
-    virtual void SetEnabled(bool enabled) {
-      button_->SetEnabled(enabled);
-    }
-
-    virtual void ButtonPressed(views::BaseButton* sender) {
-      controller_->ExecuteCommand(sender->GetTag());
-    }
-
-   private:
-    views::Button* button_;
-    CommandController* controller_;
-  };
-
-  // Get a Command node for a given command ID, creating an entry if it doesn't
-  // exist if desired.
-  Command* GetCommand(int id, bool create);
-
-  // This is the default handler for all command execution
-  CommandHandler* handler_;
-
-  // This is a map of command IDs to states and observer lists
-  CommandMap commands_;
-
-  // vector of ButtonController for managed buttons
-  std::vector<ButtonController*> managed_button_controllers_;
-
-  CommandController();
-  DISALLOW_EVIL_CONSTRUCTORS(CommandController);
-};
-
-#endif // CHROME_BROWSER_CONTROLLER_H__
diff --git a/chrome/browser/controller_unittest.cc b/chrome/browser/controller_unittest.cc
deleted file mode 100644
index c5e1c03..0000000
--- a/chrome/browser/controller_unittest.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 2006-2008 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/controller.h"
-#include "base/logging.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class TestingCommandHandlerMock : public CommandHandler {
- public:
-  virtual void ExecuteCommand(int id) {
-    EXPECT_EQ(1, id);
-  }
-};
-
-class CommandControllerTest : public testing::Test {
- public:
-  CommandControllerTest() : controller_(&handler_) { }
- protected:
-  CommandController controller_;
-  TestingCommandHandlerMock handler_;
-};
-
-class TestingCommandObserverMock : public CommandObserver {
- public:
-  virtual void SetEnabled(bool enabled) {
-    enabled_ = enabled;
-  }
-
-  bool enabled() {
-    return enabled_;
-  }
-
- private:
-  bool enabled_;
-};
-
-TEST_F(CommandControllerTest, TestBasicAPI) {
-  // Unsupported command
-  EXPECT_FALSE(controller_.SupportsCommand(0));
-  EXPECT_FALSE(controller_.IsCommandEnabled(0));
-  // TestingCommandHandlerMock::ExecuteCommand should not be called, since
-  // the command is not supported.
-  controller_.ExecuteCommand(0);
-
-  // Supported, enabled command
-  controller_.UpdateCommandEnabled(1, true);
-  EXPECT_TRUE(controller_.SupportsCommand(1));
-  EXPECT_TRUE(controller_.IsCommandEnabled(1));
-  controller_.ExecuteCommand(1);
-
-  // Supported, disabled command
-  controller_.UpdateCommandEnabled(2, false);
-  EXPECT_TRUE(controller_.SupportsCommand(2));
-  EXPECT_FALSE(controller_.IsCommandEnabled(2));
-  // TestingCommandHandlerMock::ExecuteCommmand should not be called, since
-  // the command is disabled
-  controller_.ExecuteCommand(2);
-}
-
-TEST_F(CommandControllerTest, TestObservers) {
-  TestingCommandHandlerMock handler;
-  CommandController controller(&handler);
-
-  // Create an observer for the command 2 and add it to the controller, then
-  // update the command.
-  TestingCommandObserverMock observer;
-  controller_.AddCommandObserver(2, &observer);
-  controller_.UpdateCommandEnabled(2, true);
-  EXPECT_TRUE(observer.enabled());
-  controller_.UpdateCommandEnabled(2, false);
-  EXPECT_FALSE(observer.enabled());
-
-  // Remove the observer and update the command.
-  controller_.RemoveCommandObserver(2, &observer);
-  controller_.UpdateCommandEnabled(2, true);
-  EXPECT_FALSE(observer.enabled());
-}
-
-TEST_F(CommandControllerTest, TestRemoveObserverForUnsupportedCommand) {
-  TestingCommandHandlerMock handler;
-  CommandController controller(&handler);
-
-  // Test removing observers for commands that are unsupported
-  TestingCommandObserverMock observer;
-  controller_.RemoveCommandObserver(3, &observer);
-}
-
-TEST_F(CommandControllerTest, TestAddingNullObserver) {
-  TestingCommandHandlerMock handler;
-  CommandController controller(&handler);
-
-  // Test adding/removing NULL observers
-  controller_.AddCommandObserver(4, NULL);
-}
-
-TEST_F(CommandControllerTest, TestRemovingNullObserver) {
-  TestingCommandHandlerMock handler;
-  CommandController controller(&handler);
-
-  controller_.RemoveCommandObserver(4, NULL);
-}
-
diff --git a/chrome/browser/encoding_menu_controller_delegate.cc b/chrome/browser/encoding_menu_controller_delegate.cc
index 20c8424..133569b 100644
--- a/chrome/browser/encoding_menu_controller_delegate.cc
+++ b/chrome/browser/encoding_menu_controller_delegate.cc
@@ -16,10 +16,8 @@
 
 #include "generated_resources.h"
 
-EncodingMenuControllerDelegate::EncodingMenuControllerDelegate(
-    Browser* browser, Controller* wrapped)
-    : BaseControllerDelegate(wrapped),
-      browser_(browser) {
+EncodingMenuControllerDelegate::EncodingMenuControllerDelegate(Browser* browser)
+    : browser_(browser) {
 }
 
 bool EncodingMenuControllerDelegate::IsItemChecked(int id) const {
@@ -81,6 +79,24 @@ bool EncodingMenuControllerDelegate::IsItemChecked(int id) const {
   }
 }
 
+bool EncodingMenuControllerDelegate::SupportsCommand(int id) const {
+  return browser_->command_updater()->SupportsCommand(id);
+}
+
+bool EncodingMenuControllerDelegate::IsCommandEnabled(int id) const {
+  return browser_->command_updater()->IsCommandEnabled(id);
+}
+
+bool EncodingMenuControllerDelegate::GetContextualLabel(
+    int id,
+    std::wstring* out) const {
+  return false;
+}
+
+void EncodingMenuControllerDelegate::ExecuteCommand(int id) {
+  browser_->ExecuteCommand(id);
+}
+
 void EncodingMenuControllerDelegate::BuildEncodingMenu(
     Profile* profile, Menu* encoding_menu) {
   // Append auto-detection item.
diff --git a/chrome/browser/encoding_menu_controller_delegate.h b/chrome/browser/encoding_menu_controller_delegate.h
index 44998e2..0671a2f 100644
--- a/chrome/browser/encoding_menu_controller_delegate.h
+++ b/chrome/browser/encoding_menu_controller_delegate.h
@@ -13,13 +13,16 @@ class Profile;
 
 // Encapsulates logic about populating the encoding menu and making
 // sure the correct items are checked.
-class EncodingMenuControllerDelegate : public Menu::BaseControllerDelegate {
+class EncodingMenuControllerDelegate : public Menu::Delegate {
  public:
-  explicit EncodingMenuControllerDelegate(
-      Browser* browser, Controller* wrapped);
+  explicit EncodingMenuControllerDelegate(Browser* browser);
 
   // Overridden from Menu::Delegate:
   virtual bool IsItemChecked(int id) const;
+  virtual bool SupportsCommand(int id) const;
+  virtual bool IsCommandEnabled(int id) const;
+  virtual bool GetContextualLabel(int id, std::wstring* out) const;
+  virtual void ExecuteCommand(int id);
 
   // Builds the encoding menu in the passed in |encoding_menu|. This
   // is used in both the simple frame menu and in the page menu in the
diff --git a/chrome/browser/login_prompt.cc b/chrome/browser/login_prompt.cc
index 978d4dc..097763c 100644
--- a/chrome/browser/login_prompt.cc
+++ b/chrome/browser/login_prompt.cc
@@ -8,7 +8,6 @@
 #include "base/lock.h"
 #include "base/message_loop.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/controller.h"
 #include "chrome/browser/password_manager/password_manager.h"
 #include "chrome/browser/renderer_host/render_process_host.h"
 #include "chrome/browser/renderer_host/resource_dispatcher_host.h"
diff --git a/chrome/browser/views/browser_views.vcproj b/chrome/browser/views/browser_views.vcproj
index b605de5..557e4a2 100644
--- a/chrome/browser/views/browser_views.vcproj
+++ b/chrome/browser/views/browser_views.vcproj
@@ -450,14 +450,6 @@
 			>
 		</File>
 		<File
-			RelativePath=".\delay_view.cc"
-			>
-		</File>
-		<File
-			RelativePath=".\delay_view.h"
-			>
-		</File>
-		<File
 			RelativePath=".\dom_view.cc"
 			>
 		</File>
diff --git a/chrome/browser/views/delay_view.cc b/chrome/browser/views/delay_view.cc
deleted file mode 100644
index 4b8e871..0000000
--- a/chrome/browser/views/delay_view.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright (c) 2006-2008 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/views/delay_view.h"
-
-#include "chrome/common/l10n_util.h"
-
-#include "generated_resources.h"
-
-// The amount of horizontal space between the throbber and the label.
-const int kThrobberLabelSpace = 7;
-
-// The amount of space between controls and the edge of the window.
-const int kWindowMargin = 5;
-
-DelayView::DelayView(const std::wstring& text, CommandController* controller,
-                     bool show_cancel)
-    : controller_(controller),
-      label_(NULL),
-      cancel_button_(NULL) {
-  DCHECK(controller);
-
-  label_ = new views::Label(text);
-  AddChildView(label_);
-
-  if (show_cancel) {
-    cancel_button_ = new views::NativeButton(l10n_util::GetString(IDS_CANCEL));
-    cancel_button_->SetID(ID_CANCEL);
-    cancel_button_->SetListener(this);
-    AddChildView(cancel_button_);
-  }
-
-  throbber_ = new views::Throbber(50, true);
-  AddChildView(throbber_);
-  throbber_->Start();
-}
-
-DelayView::~DelayView() {
-}
-
-void DelayView::ButtonPressed(views::NativeButton *sender) {
-  if (sender->GetID() == ID_CANCEL) {
-    controller_->ExecuteCommand(IDCANCEL);
-  }
-}
-
-void DelayView::Layout() {
-  if (!GetParent())
-    return;
-
-  gfx::Size available = GetParent()->size();
-
-  if (cancel_button_) {
-    gfx::Size button_size = cancel_button_->GetPreferredSize();
-    cancel_button_->SetBounds(available.width() - kWindowMargin -
-                                  button_size.width(),
-                              available.height() - kWindowMargin -
-                                  button_size.height(),
-                              button_size.width(), button_size.height());
-  }
-
-  DCHECK(label_);
-  gfx::Size label_size = label_->GetPreferredSize();
-
-  DCHECK(throbber_);
-  gfx::Size throbber_size = throbber_->GetPreferredSize();
-
-  gfx::Rect main_rect(0, 0,
-                      throbber_size.width() + kThrobberLabelSpace +
-                          label_size.width(),
-                      std::max(throbber_size.height(), label_size.height()));
-
-  main_rect.set_x((available.width() / 2) - (main_rect.width() / 2));
-  main_rect.set_y((available.height() / 2) - (main_rect.height() / 2));
-
-  label_->SetBounds(main_rect.x() + throbber_size.width() +
-                        kThrobberLabelSpace,
-                    main_rect.y() + main_rect.height() / 2 -
-                        label_size.height() / 2,
-                    label_size.width(),
-                    label_size.height());
-
-  throbber_->SetBounds(
-      main_rect.x(),
-      main_rect.y() + main_rect.height() / 2 - throbber_size.height() / 2,
-      throbber_size.width(),
-      throbber_size.height());
-}
diff --git a/chrome/browser/views/delay_view.h b/chrome/browser/views/delay_view.h
deleted file mode 100644
index 86ac7cc..0000000
--- a/chrome/browser/views/delay_view.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) 2006-2008 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.
-
-// A simple view that indicates to the user that a time-consuming operation
-// is being performed, using a throbber and some explanatory text.
-
-#ifndef CHROME_BROWSER_VIEWS_DELAY_VIEW_H__
-#define CHROME_BROWSER_VIEWS_DELAY_VIEW_H__
-
-#include "chrome/browser/controller.h"
-#include "base/basictypes.h"
-#include "chrome/views/label.h"
-#include "chrome/views/native_button.h"
-#include "chrome/views/throbber.h"
-
-class DelayView : public views::View,
-                  public views::NativeButton::Listener {
- public:
-  // |text| explains the delay
-  // |controller| receives notifications when the "cancel" button is pressed
-  // |show_cancel| determines whether the cancel button is shown
-  DelayView(const std::wstring& text,
-            CommandController* controller,
-            bool show_cancel);
-  virtual ~DelayView();
-
-  enum ViewID {
-    ID_CANCEL = 10000,
-  };
-
-  // Overridden from views::View
-  virtual void Layout();
-
-  // Implemented from views::NativeButton::Listener
-  virtual void ButtonPressed(views::NativeButton *sender);
-
- private:
-  CommandController* controller_;
-
-  views::Label* label_;
-  views::NativeButton* cancel_button_;
-  views::Throbber* throbber_;
-
-  DISALLOW_EVIL_CONSTRUCTORS(DelayView);
-};
-
-#endif  // CHROME_BROWSER_VIEWS_DELAY_VIEW_H__
-
diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc
index 9930cc1..7bf7156e 100644
--- a/chrome/browser/views/frame/browser_view.cc
+++ b/chrome/browser/views/frame/browser_view.cc
@@ -212,8 +212,8 @@ bool BrowserView::AcceleratorPressed(const views::Accelerator& accelerator) {
   DCHECK(iter != accelerator_table_->end());
 
   int command_id = iter->second;
-  if (browser_->SupportsCommand(command_id) &&
-      browser_->IsCommandEnabled(command_id)) {
+  if (browser_->command_updater()->SupportsCommand(command_id) &&
+      browser_->command_updater()->IsCommandEnabled(command_id)) {
     browser_->ExecuteCommand(command_id);
     return true;
   }
@@ -236,7 +236,8 @@ bool BrowserView::SystemCommandReceived(UINT notification_code,
                                         const gfx::Point& point) {
   bool handled = false;
 
-  if (browser_->SupportsCommand(notification_code)) {
+  if (browser_->command_updater()->SupportsCommand(notification_code) &&
+      browser_->command_updater()->IsCommandEnabled(notification_code)) {
     browser_->ExecuteCommand(notification_code);
     handled = true;
   }
@@ -285,8 +286,9 @@ void BrowserView::PrepareToRunSystemMenu(HMENU menu) {
     // |command| can be zero on submenu items (IDS_ENCODING,
     // IDS_ZOOM) and on separators.
     if (command != 0) {
-      system_menu_->EnableMenuItemByID(command,
-                                       browser_->IsCommandEnabled(command));
+      system_menu_->EnableMenuItemByID(
+          command,
+          browser_->command_updater()->IsCommandEnabled(command));
     }
   }
 }
@@ -335,7 +337,7 @@ void BrowserView::Init() {
   tabstrip_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_TABSTRIP));
   AddChildView(tabstrip_);
 
-  toolbar_ = new BrowserToolbarView(browser_->controller(), browser_.get());
+  toolbar_ = new BrowserToolbarView(browser_.get());
   AddChildView(toolbar_);
   toolbar_->SetID(VIEW_ID_TOOLBAR);
   toolbar_->Init(browser_->profile());
@@ -730,8 +732,8 @@ bool BrowserView::ExecuteWindowsCommand(int command_id) {
   if (command_id_from_app_command != -1)
     command_id = command_id_from_app_command;
 
-  if (browser_->SupportsCommand(command_id)) {
-    if (browser_->IsCommandEnabled(command_id))
+  if (browser_->command_updater()->SupportsCommand(command_id)) {
+    if (browser_->command_updater()->IsCommandEnabled(command_id))
       browser_->ExecuteCommand(command_id);
     return true;
   }
@@ -1256,8 +1258,7 @@ void BrowserView::LoadAccelerators() {
 void BrowserView::BuildMenuForTabStriplessWindow(Menu* menu,
                                                  int insertion_index) {
   encoding_menu_delegate_.reset(new EncodingMenuControllerDelegate(
-      browser_.get(),
-      browser_->controller()));
+      browser_.get()));
 
   for (int i = 0; i < arraysize(kMenuLayout); ++i) {
     if (kMenuLayout[i].separator) {
diff --git a/chrome/browser/views/go_button.cc b/chrome/browser/views/go_button.cc
index f9025fb..47f6175 100644
--- a/chrome/browser/views/go_button.cc
+++ b/chrome/browser/views/go_button.cc
@@ -5,15 +5,16 @@
 #include "chrome/browser/views/go_button.h"
 
 #include "chrome/app/chrome_dll_resource.h"
+#include "chrome/browser/command_updater.h"
 #include "chrome/browser/views/location_bar_view.h"
 #include "chrome/common/l10n_util.h"
 
 #include "generated_resources.h"
 
 GoButton::GoButton(LocationBarView* location_bar,
-                   CommandController* controller) : ToggleButton(),
+                   CommandUpdater* command_updater) : ToggleButton(),
     location_bar_(location_bar),
-    controller_(controller),
+    command_updater_(command_updater),
     intended_mode_(MODE_GO),
     visible_mode_(MODE_GO),
     button_delay_(NULL),
@@ -27,14 +28,14 @@ GoButton::~GoButton() {
 
 void GoButton::NotifyClick(int mouse_event_flags) {
   if (visible_mode_ == MODE_STOP) {
-    controller_->ExecuteCommand(IDC_STOP);
+    command_updater_->ExecuteCommand(IDC_STOP);
 
     // The user has clicked, so we can feel free to update the button,
     // even if the mouse is still hovering.
     ChangeMode(MODE_GO);
   } else if (visible_mode_ == MODE_GO && stop_timer_.empty()) {
     // If the go button is visible and not within the doubleclick timer, go.
-    controller_->ExecuteCommand(IDC_GO);
+    command_updater_->ExecuteCommand(IDC_GO);
 
     // Figure out the system double-click time.
     if (button_delay_ == NULL)
diff --git a/chrome/browser/views/go_button.h b/chrome/browser/views/go_button.h
index 1cfd107..4566184 100644
--- a/chrome/browser/views/go_button.h
+++ b/chrome/browser/views/go_button.h
@@ -6,9 +6,9 @@
 #define CHROME_BROWSER_VIEWS_GO_BUTTON_H__
 
 #include "chrome/views/button.h"
-#include "chrome/browser/controller.h"
 #include "base/task.h"
 
+class CommandUpdater;
 class LocationBarView;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -25,7 +25,9 @@ class LocationBarView;
 
 class GoButton : public views::ToggleButton {
  public:
-  GoButton(LocationBarView* location_bar, CommandController* controller);
+  // TODO(beng): get rid of the command updater param and instead have a
+  //             delegate.
+  GoButton(LocationBarView* location_bar, CommandUpdater* command_updater);
   virtual ~GoButton();
 
   typedef enum Mode { MODE_GO = 0, MODE_STOP };
@@ -49,7 +51,7 @@ class GoButton : public views::ToggleButton {
   ScopedRunnableMethodFactory<GoButton> stop_timer_;
 
   LocationBarView* location_bar_;
-  CommandController* controller_;
+  CommandUpdater* command_updater_;
   ButtonListener* listener_;
 
   // The mode we should be in
diff --git a/chrome/browser/views/location_bar_view.cc b/chrome/browser/views/location_bar_view.cc
index 8c727b7..aa6fb1d 100644
--- a/chrome/browser/views/location_bar_view.cc
+++ b/chrome/browser/views/location_bar_view.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/browser.h"
 #include "chrome/browser/browser_list.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/command_updater.h"
 #include "chrome/browser/profile.h"
 #include "chrome/browser/search_engines/template_url.h"
 #include "chrome/browser/search_engines/template_url_model.h"
@@ -77,12 +78,12 @@ static std::wstring GetKeywordDescription(Profile* profile,
 }
 
 LocationBarView::LocationBarView(Profile* profile,
-                                 CommandController* controller,
+                                 CommandUpdater* command_updater,
                                  ToolbarModel* model,
                                  Delegate* delegate,
                                  bool popup_window_mode)
     : profile_(profile),
-      controller_(controller),
+      command_updater_(command_updater),
       model_(model),
       delegate_(delegate),
       disposition_(CURRENT_TAB),
@@ -126,7 +127,7 @@ void LocationBarView::Init() {
   views::Widget* widget = GetWidget();
   location_entry_.reset(new AutocompleteEditView(font_, this, model_, this,
                                                  widget->GetHWND(),
-                                                 profile_, controller_,
+                                                 profile_, command_updater_,
                                                  popup_window_mode_));
 
   // View container for URL edit field.
@@ -319,9 +320,9 @@ void LocationBarView::OnAutocompleteAccept(
   disposition_ = disposition;
   transition_ = transition;
 
-  if (controller_) {
+  if (command_updater_) {
     if (!alternate_nav_url.is_valid()) {
-      controller_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
+      command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
       return;
     }
 
@@ -330,7 +331,7 @@ void LocationBarView::OnAutocompleteAccept(
     // The AlternateNavURLFetcher will listen for the pending navigation
     // notification that will be issued as a result of the "open URL." It
     // will automatically install itself into that navigation controller.
-    controller_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
+    command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
     if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) {
       // I'm not sure this should be reachable, but I'm not also sure enough
       // that it shouldn't to stick in a NOTREACHED().  In any case, this is
diff --git a/chrome/browser/views/location_bar_view.h b/chrome/browser/views/location_bar_view.h
index ad99fb5..eb3b4ef 100644
--- a/chrome/browser/views/location_bar_view.h
+++ b/chrome/browser/views/location_bar_view.h
@@ -9,7 +9,6 @@
 
 #include "base/gfx/rect.h"
 #include "chrome/browser/autocomplete/autocomplete_edit.h"
-#include "chrome/browser/controller.h"
 #include "chrome/browser/tab_contents/tab_contents.h"
 #include "chrome/browser/toolbar_model.h"
 #include "chrome/browser/views/info_bubble.h"
@@ -19,6 +18,7 @@
 #include "chrome/views/label.h"
 #include "chrome/views/painter.h"
 
+class CommandUpdater;
 class GURL;
 class Profile;
 
@@ -46,7 +46,7 @@ class LocationBarView : public views::View,
   };
 
   LocationBarView(Profile* profile,
-                  CommandController* controller,
+                  CommandUpdater* command_updater,
                   ToolbarModel* model_,
                   Delegate* delegate,
                   bool popup_window_mode);
@@ -339,8 +339,8 @@ class LocationBarView : public views::View,
   // The Autocomplete Edit field.
   scoped_ptr<AutocompleteEditView> location_entry_;
 
-  // The command controller for this View.
-  CommandController* controller_;
+  // The CommandUpdater for the Browser object that corresponds to this View.
+  CommandUpdater* command_updater_;
 
   // The model.
   ToolbarModel* model_;
diff --git a/chrome/browser/views/toolbar_view.cc b/chrome/browser/views/toolbar_view.cc
index 091c97e..f6ed905 100644
--- a/chrome/browser/views/toolbar_view.cc
+++ b/chrome/browser/views/toolbar_view.cc
@@ -60,10 +60,8 @@ static const int kMenuButtonOffset = 3;
 // Padding to the right of the location bar
 static const int kPaddingRight = 2;
 
-BrowserToolbarView::BrowserToolbarView(CommandController* controller,
-                                       Browser* browser)
-    : EncodingMenuControllerDelegate(browser, controller),
-      controller_(controller),
+BrowserToolbarView::BrowserToolbarView(Browser* browser)
+    : EncodingMenuControllerDelegate(browser),
       model_(browser->toolbar_model()),
       back_(NULL),
       forward_(NULL),
@@ -78,11 +76,15 @@ BrowserToolbarView::BrowserToolbarView(CommandController* controller,
       tab_(NULL),
       profiles_helper_(new GetProfilesHelper(this)),
       profiles_menu_(NULL) {
+  browser_->command_updater()->AddCommandObserver(IDC_BACK, this);
+  browser_->command_updater()->AddCommandObserver(IDC_FORWARD, this);
+  browser_->command_updater()->AddCommandObserver(IDC_RELOAD, this);
+  browser_->command_updater()->AddCommandObserver(IDC_HOME, this);
+  browser_->command_updater()->AddCommandObserver(IDC_STAR, this);
   back_menu_model_.reset(new BackForwardMenuModel(
       browser, BackForwardMenuModel::BACKWARD_MENU_DELEGATE));
   forward_menu_model_.reset(new BackForwardMenuModel(
       browser, BackForwardMenuModel::FORWARD_MENU_DELEGATE));
-
   if (browser->type() == Browser::TYPE_NORMAL)
     display_mode_ = DISPLAYMODE_NORMAL;
   else
@@ -116,6 +118,7 @@ void BrowserToolbarView::CreateLeftSideControls() {
   ResourceBundle &rb = ResourceBundle::GetSharedInstance();
 
   back_ = new views::ButtonDropDown(back_menu_model_.get());
+  back_->SetListener(this, IDC_BACK);
   back_->SetImageAlignment(views::Button::ALIGN_RIGHT,
                            views::Button::ALIGN_TOP);
   back_->SetImage(views::Button::BS_NORMAL, rb.GetBitmapNamed(IDR_BACK));
@@ -126,9 +129,9 @@ void BrowserToolbarView::CreateLeftSideControls() {
   back_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_BACK));
   back_->SetID(VIEW_ID_BACK_BUTTON);
   AddChildView(back_);
-  controller_->AddManagedButton(back_, IDC_BACK);
 
   forward_ = new views::ButtonDropDown(forward_menu_model_.get());
+  forward_->SetListener(this, IDC_FORWARD);
   forward_->SetImage(views::Button::BS_NORMAL, rb.GetBitmapNamed(IDR_FORWARD));
   forward_->SetImage(views::Button::BS_HOT, rb.GetBitmapNamed(IDR_FORWARD_H));
   forward_->SetImage(views::Button::BS_PUSHED,
@@ -139,9 +142,9 @@ void BrowserToolbarView::CreateLeftSideControls() {
   forward_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_FORWARD));
   forward_->SetID(VIEW_ID_FORWARD_BUTTON);
   AddChildView(forward_);
-  controller_->AddManagedButton(forward_, IDC_FORWARD);
 
   reload_ = new views::Button();
+  reload_->SetListener(this, IDC_RELOAD);
   reload_->SetImage(views::Button::BS_NORMAL, rb.GetBitmapNamed(IDR_RELOAD));
   reload_->SetImage(views::Button::BS_HOT, rb.GetBitmapNamed(IDR_RELOAD_H));
   reload_->SetImage(views::Button::BS_PUSHED, rb.GetBitmapNamed(IDR_RELOAD_P));
@@ -149,9 +152,9 @@ void BrowserToolbarView::CreateLeftSideControls() {
   reload_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_RELOAD));
   reload_->SetID(VIEW_ID_RELOAD_BUTTON);
   AddChildView(reload_);
-  controller_->AddManagedButton(reload_, IDC_RELOAD);
 
   home_ = new views::Button();
+  home_->SetListener(this, IDC_HOME);
   home_->SetImage(views::Button::BS_NORMAL, rb.GetBitmapNamed(IDR_HOME));
   home_->SetImage(views::Button::BS_HOT, rb.GetBitmapNamed(IDR_HOME_H));
   home_->SetImage(views::Button::BS_PUSHED, rb.GetBitmapNamed(IDR_HOME_P));
@@ -159,13 +162,13 @@ void BrowserToolbarView::CreateLeftSideControls() {
   home_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_HOME));
   home_->SetID(VIEW_ID_HOME_BUTTON);
   AddChildView(home_);
-  controller_->AddManagedButton(home_, IDC_HOME);
 }
 
 void BrowserToolbarView::CreateCenterStack(Profile *profile) {
   ResourceBundle &rb = ResourceBundle::GetSharedInstance();
 
   star_ = new ToolbarStarToggle(this);
+  star_->SetListener(this, IDC_STAR);
   star_->SetImage(views::Button::BS_NORMAL, rb.GetBitmapNamed(IDR_STAR));
   star_->SetImage(views::Button::BS_HOT, rb.GetBitmapNamed(IDR_STAR_H));
   star_->SetImage(views::Button::BS_PUSHED, rb.GetBitmapNamed(IDR_STAR_P));
@@ -182,15 +185,15 @@ void BrowserToolbarView::CreateCenterStack(Profile *profile) {
   star_->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_STAR));
   star_->SetID(VIEW_ID_STAR_BUTTON);
   AddChildView(star_);
-  controller_->AddManagedButton(star_, IDC_STAR);
 
-  location_bar_ = new LocationBarView(profile, controller_, model_, this,
+  location_bar_ = new LocationBarView(profile, browser_->command_updater(),
+                                      model_, this,
                                       display_mode_ == DISPLAYMODE_LOCATION);
   AddChildView(location_bar_);
   location_bar_->Init();
 
   // The Go button.
-  go_ = new GoButton(location_bar_, controller_);
+  go_ = new GoButton(location_bar_, browser_->command_updater());
   go_->SetImage(views::Button::BS_NORMAL, rb.GetBitmapNamed(IDR_GO));
   go_->SetImage(views::Button::BS_HOT, rb.GetBitmapNamed(IDR_GO_H));
   go_->SetImage(views::Button::BS_PUSHED, rb.GetBitmapNamed(IDR_GO_P));
@@ -750,6 +753,33 @@ TabContents* BrowserToolbarView::GetTabContents() {
   return tab_;
 }
 
+void BrowserToolbarView::EnabledStateChangedForCommand(int id, bool enabled) {
+  views::Button* button = NULL;
+  switch (id) {
+    case IDC_BACK:
+      button = back_;
+      break;
+    case IDC_FORWARD:
+      button = forward_;
+      break;
+    case IDC_RELOAD:
+      button = reload_;
+      break;
+    case IDC_HOME:
+      button = home_;
+      break;
+    case IDC_STAR:
+      button = star_;
+      break;
+  }
+  if (button)
+    button->SetEnabled(enabled);
+}
+
+void BrowserToolbarView::ButtonPressed(views::BaseButton* sender) {
+  browser_->ExecuteCommand(sender->GetTag());
+}
+
 void BrowserToolbarView::Observe(NotificationType type,
                                  const NotificationSource& source,
                                  const NotificationDetails& details) {
diff --git a/chrome/browser/views/toolbar_view.h b/chrome/browser/views/toolbar_view.h
index a927f0c..a4b6ec0 100644
--- a/chrome/browser/views/toolbar_view.h
+++ b/chrome/browser/views/toolbar_view.h
@@ -10,7 +10,7 @@
 #include "base/ref_counted.h"
 #include "base/scoped_ptr.h"
 #include "chrome/browser/back_forward_menu_model.h"
-#include "chrome/browser/controller.h"
+#include "chrome/browser/command_updater.h"
 #include "chrome/browser/encoding_menu_controller_delegate.h"
 #include "chrome/browser/user_data_manager.h"
 #include "chrome/browser/views/dom_view.h"
@@ -40,9 +40,11 @@ class BrowserToolbarView : public views::View,
                            public views::DragController,
                            public LocationBarView::Delegate,
                            public NotificationObserver,
-                           public GetProfilesHelper::Delegate {
+                           public GetProfilesHelper::Delegate,
+                           public CommandUpdater::CommandObserver,
+                           public views::BaseButton::ButtonListener {
  public:
-  BrowserToolbarView(CommandController* controller, Browser* browser);
+  explicit BrowserToolbarView(Browser* browser);
   virtual ~BrowserToolbarView();
 
   // Create the contents of the Browser Toolbar
@@ -116,6 +118,12 @@ class BrowserToolbarView : public views::View,
 
   Browser* browser() { return browser_; }
 
+  // Overridden from CommandUpdater::CommandObserver:
+  virtual void EnabledStateChangedForCommand(int id, bool enabled);
+
+  // Overridden from views::BaseButton::ButtonListener:
+  virtual void ButtonPressed(views::BaseButton* sender);
+
  private:
   // NotificationObserver
   virtual void Observe(NotificationType type,
@@ -159,9 +167,6 @@ class BrowserToolbarView : public views::View,
     return display_mode_ == DISPLAYMODE_NORMAL;
   }
 
-  // This View's Command Controller
-  CommandController* controller_;
-
   scoped_ptr<BackForwardMenuModel> back_menu_model_;
   scoped_ptr<BackForwardMenuModel> forward_menu_model_;
 
diff --git a/chrome/test/unit/unittests.vcproj b/chrome/test/unit/unittests.vcproj
index cb1f448..3df2bd7 100644
--- a/chrome/test/unit/unittests.vcproj
+++ b/chrome/test/unit/unittests.vcproj
@@ -342,7 +342,7 @@
 				>
 			</File>
 			<File
-				RelativePath="..\..\browser\controller_unittest.cc"
+				RelativePath="..\..\browser\command_updater_unittest.cc"
 				>
 			</File>
 			<File
diff --git a/chrome/views/controller.h b/chrome/views/controller.h
index 17edadf..edd9a1c 100644
--- a/chrome/views/controller.h
+++ b/chrome/views/controller.h
@@ -7,15 +7,8 @@
 
 #include <string>
 
-///////////////////////////////////////////////////////////////////////////////
-//
-// Controller class
-//
-//   This is the Controller portion of a MVC pattern. It handles dispatching
-//   commands, maintaining enabled state, and updating the UI as that state
-//   changes.
-//
-///////////////////////////////////////////////////////////////////////////////
+// TODO(beng): remove this interface and fold it into MenuDelegate.
+
 class Controller {
  public:
   virtual ~Controller() { }
diff --git a/chrome/views/message_box_view.cc b/chrome/views/message_box_view.cc
index 2129212..6851ed4 100644
--- a/chrome/views/message_box_view.cc
+++ b/chrome/views/message_box_view.cc
@@ -6,7 +6,6 @@
 
 #include "base/message_loop.h"
 #include "base/string_util.h"
-#include "chrome/browser/controller.h"
 #include "chrome/browser/views/standard_layout.h"
 #include "chrome/common/l10n_util.h"
 #include "chrome/views/checkbox.h"
-- 
cgit v1.1