1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/browser_command_controller.h"
6
7#include "base/command_line.h"
8#include "base/prefs/pref_service.h"
9#include "chrome/app/chrome_command_ids.h"
10#include "chrome/browser/browser_process.h"
11#include "chrome/browser/chrome_notification_types.h"
12#include "chrome/browser/defaults.h"
13#include "chrome/browser/extensions/extension_service.h"
14#include "chrome/browser/extensions/extension_util.h"
15#include "chrome/browser/lifetime/application_lifetime.h"
16#include "chrome/browser/prefs/incognito_mode_prefs.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/browser/profiles/profile_manager.h"
19#include "chrome/browser/sessions/tab_restore_service.h"
20#include "chrome/browser/sessions/tab_restore_service_factory.h"
21#include "chrome/browser/shell_integration.h"
22#include "chrome/browser/signin/signin_promo.h"
23#include "chrome/browser/sync/profile_sync_service.h"
24#include "chrome/browser/sync/profile_sync_service_factory.h"
25#include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
26#include "chrome/browser/ui/browser.h"
27#include "chrome/browser/ui/browser_commands.h"
28#include "chrome/browser/ui/browser_window.h"
29#include "chrome/browser/ui/chrome_pages.h"
30#include "chrome/browser/ui/tabs/tab_strip_model.h"
31#include "chrome/browser/ui/tabs/tab_strip_model_utils.h"
32#include "chrome/browser/ui/webui/inspect_ui.h"
33#include "chrome/common/chrome_switches.h"
34#include "chrome/common/content_restriction.h"
35#include "chrome/common/pref_names.h"
36#include "chrome/common/profiling.h"
37#include "content/public/browser/native_web_keyboard_event.h"
38#include "content/public/browser/navigation_controller.h"
39#include "content/public/browser/navigation_entry.h"
40#include "content/public/browser/user_metrics.h"
41#include "content/public/browser/web_contents.h"
42#include "content/public/browser/web_contents_observer.h"
43#include "content/public/common/url_constants.h"
44#include "extensions/browser/extension_system.h"
45#include "ui/events/keycodes/keyboard_codes.h"
46
47#if defined(OS_MACOSX)
48#include "chrome/browser/ui/browser_commands_mac.h"
49#endif
50
51#if defined(OS_WIN)
52#include "base/win/metro.h"
53#include "base/win/windows_version.h"
54#include "chrome/browser/ui/apps/apps_metro_handler_win.h"
55#include "content/public/browser/gpu_data_manager.h"
56#endif
57
58#if defined(USE_ASH)
59#include "ash/accelerators/accelerator_commands.h"
60#include "chrome/browser/ui/ash/ash_util.h"
61#endif
62
63#if defined(OS_CHROMEOS)
64#include "ash/multi_profile_uma.h"
65#include "ash/session/session_state_delegate.h"
66#include "ash/shell.h"
67#include "chrome/browser/ui/ash/multi_user/multi_user_context_menu.h"
68#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
69#include "chrome/browser/ui/browser_commands_chromeos.h"
70#endif
71
72#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
73#include "ui/events/linux/text_edit_key_bindings_delegate_auralinux.h"
74#endif
75
76using content::NavigationEntry;
77using content::NavigationController;
78using content::WebContents;
79
80namespace {
81
82enum WindowState {
83  // Not in fullscreen mode.
84  WINDOW_STATE_NOT_FULLSCREEN,
85
86  // Fullscreen mode, occupying the whole screen.
87  WINDOW_STATE_FULLSCREEN,
88
89  // Fullscreen mode for metro snap, occupying the full height and 20% of
90  // the screen width.
91  WINDOW_STATE_METRO_SNAP,
92};
93
94// Returns |true| if entry has an internal chrome:// URL, |false| otherwise.
95bool HasInternalURL(const NavigationEntry* entry) {
96  if (!entry)
97    return false;
98
99  // Check the |virtual_url()| first. This catches regular chrome:// URLs
100  // including URLs that were rewritten (such as chrome://bookmarks).
101  if (entry->GetVirtualURL().SchemeIs(content::kChromeUIScheme))
102    return true;
103
104  // If the |virtual_url()| isn't a chrome:// URL, check if it's actually
105  // view-source: of a chrome:// URL.
106  if (entry->GetVirtualURL().SchemeIs(content::kViewSourceScheme))
107    return entry->GetURL().SchemeIs(content::kChromeUIScheme);
108
109  return false;
110}
111
112#if defined(OS_WIN)
113// Windows 8 specific helper class to manage DefaultBrowserWorker. It does the
114// following asynchronous actions in order:
115// 1- Check that chrome is the default browser
116// 2- If we are the default, restart chrome in metro and exit
117// 3- If not the default browser show the 'select default browser' system dialog
118// 4- When dialog dismisses check again who got made the default
119// 5- If we are the default then restart chrome in metro and exit
120// 6- If we are not the default exit.
121//
122// Note: this class deletes itself.
123class SwitchToMetroUIHandler
124    : public ShellIntegration::DefaultWebClientObserver {
125 public:
126  SwitchToMetroUIHandler()
127      : default_browser_worker_(
128            new ShellIntegration::DefaultBrowserWorker(this)),
129        first_check_(true) {
130    default_browser_worker_->StartCheckIsDefault();
131  }
132
133  virtual ~SwitchToMetroUIHandler() {
134    default_browser_worker_->ObserverDestroyed();
135  }
136
137 private:
138  virtual void SetDefaultWebClientUIState(
139      ShellIntegration::DefaultWebClientUIState state) OVERRIDE {
140    switch (state) {
141      case ShellIntegration::STATE_PROCESSING:
142        return;
143      case ShellIntegration::STATE_UNKNOWN :
144        break;
145      case ShellIntegration::STATE_IS_DEFAULT:
146        chrome::AttemptRestartToMetroMode();
147        break;
148      case ShellIntegration::STATE_NOT_DEFAULT:
149        if (first_check_) {
150          default_browser_worker_->StartSetAsDefault();
151          return;
152        }
153        break;
154      default:
155        NOTREACHED();
156    }
157    delete this;
158  }
159
160  virtual void OnSetAsDefaultConcluded(bool success)  OVERRIDE {
161    if (!success) {
162      delete this;
163      return;
164    }
165    first_check_ = false;
166    default_browser_worker_->StartCheckIsDefault();
167  }
168
169  virtual bool IsInteractiveSetDefaultPermitted() OVERRIDE {
170    return true;
171  }
172
173  scoped_refptr<ShellIntegration::DefaultBrowserWorker> default_browser_worker_;
174  bool first_check_;
175
176  DISALLOW_COPY_AND_ASSIGN(SwitchToMetroUIHandler);
177};
178#endif  // defined(OS_WIN)
179
180}  // namespace
181
182namespace chrome {
183
184///////////////////////////////////////////////////////////////////////////////
185// BrowserCommandController, public:
186
187BrowserCommandController::BrowserCommandController(Browser* browser)
188    : browser_(browser),
189      command_updater_(this),
190      block_command_execution_(false),
191      last_blocked_command_id_(-1),
192      last_blocked_command_disposition_(CURRENT_TAB) {
193  browser_->tab_strip_model()->AddObserver(this);
194  PrefService* local_state = g_browser_process->local_state();
195  if (local_state) {
196    local_pref_registrar_.Init(local_state);
197    local_pref_registrar_.Add(
198        prefs::kAllowFileSelectionDialogs,
199        base::Bind(
200            &BrowserCommandController::UpdateCommandsForFileSelectionDialogs,
201            base::Unretained(this)));
202  }
203
204  profile_pref_registrar_.Init(profile()->GetPrefs());
205  profile_pref_registrar_.Add(
206      prefs::kDevToolsDisabled,
207      base::Bind(&BrowserCommandController::UpdateCommandsForDevTools,
208                 base::Unretained(this)));
209  profile_pref_registrar_.Add(
210      bookmarks::prefs::kEditBookmarksEnabled,
211      base::Bind(&BrowserCommandController::UpdateCommandsForBookmarkEditing,
212                 base::Unretained(this)));
213  profile_pref_registrar_.Add(
214      bookmarks::prefs::kShowBookmarkBar,
215      base::Bind(&BrowserCommandController::UpdateCommandsForBookmarkBar,
216                 base::Unretained(this)));
217  profile_pref_registrar_.Add(
218      prefs::kIncognitoModeAvailability,
219      base::Bind(
220          &BrowserCommandController::UpdateCommandsForIncognitoAvailability,
221          base::Unretained(this)));
222  profile_pref_registrar_.Add(
223      prefs::kPrintingEnabled,
224      base::Bind(&BrowserCommandController::UpdatePrintingState,
225                 base::Unretained(this)));
226#if !defined(OS_MACOSX)
227  profile_pref_registrar_.Add(
228      prefs::kFullscreenAllowed,
229      base::Bind(&BrowserCommandController::UpdateCommandsForFullscreenMode,
230                 base::Unretained(this)));
231#endif
232  pref_signin_allowed_.Init(
233      prefs::kSigninAllowed,
234      profile()->GetOriginalProfile()->GetPrefs(),
235      base::Bind(&BrowserCommandController::OnSigninAllowedPrefChange,
236                 base::Unretained(this)));
237
238  InitCommandState();
239
240  TabRestoreService* tab_restore_service =
241      TabRestoreServiceFactory::GetForProfile(profile());
242  if (tab_restore_service) {
243    tab_restore_service->AddObserver(this);
244    TabRestoreServiceChanged(tab_restore_service);
245  }
246}
247
248BrowserCommandController::~BrowserCommandController() {
249  // TabRestoreService may have been shutdown by the time we get here. Don't
250  // trigger creating it.
251  TabRestoreService* tab_restore_service =
252      TabRestoreServiceFactory::GetForProfileIfExisting(profile());
253  if (tab_restore_service)
254    tab_restore_service->RemoveObserver(this);
255  profile_pref_registrar_.RemoveAll();
256  local_pref_registrar_.RemoveAll();
257  browser_->tab_strip_model()->RemoveObserver(this);
258}
259
260bool BrowserCommandController::IsReservedCommandOrKey(
261    int command_id,
262    const content::NativeWebKeyboardEvent& event) {
263  // In Apps mode, no keys are reserved.
264  if (browser_->is_app())
265    return false;
266
267#if defined(OS_CHROMEOS)
268  // On Chrome OS, the top row of keys are mapped to browser actions like
269  // back/forward or refresh. We don't want web pages to be able to change the
270  // behavior of these keys.  Ash handles F4 and up; this leaves us needing to
271  // reserve browser back/forward and refresh here.
272  ui::KeyboardCode key_code =
273    static_cast<ui::KeyboardCode>(event.windowsKeyCode);
274  if ((key_code == ui::VKEY_BROWSER_BACK && command_id == IDC_BACK) ||
275      (key_code == ui::VKEY_BROWSER_FORWARD && command_id == IDC_FORWARD) ||
276      (key_code == ui::VKEY_BROWSER_REFRESH && command_id == IDC_RELOAD)) {
277    return true;
278  }
279#endif
280
281  if (window()->IsFullscreen() && command_id == IDC_FULLSCREEN)
282    return true;
283
284#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
285  // If this key was registered by the user as a content editing hotkey, then
286  // it is not reserved.
287  ui::TextEditKeyBindingsDelegateAuraLinux* delegate =
288      ui::GetTextEditKeyBindingsDelegate();
289  if (delegate && event.os_event && delegate->MatchEvent(*event.os_event, NULL))
290    return false;
291#endif
292
293  return command_id == IDC_CLOSE_TAB ||
294         command_id == IDC_CLOSE_WINDOW ||
295         command_id == IDC_NEW_INCOGNITO_WINDOW ||
296         command_id == IDC_NEW_TAB ||
297         command_id == IDC_NEW_WINDOW ||
298         command_id == IDC_RESTORE_TAB ||
299         command_id == IDC_SELECT_NEXT_TAB ||
300         command_id == IDC_SELECT_PREVIOUS_TAB ||
301         command_id == IDC_EXIT;
302}
303
304void BrowserCommandController::SetBlockCommandExecution(bool block) {
305  block_command_execution_ = block;
306  if (block) {
307    last_blocked_command_id_ = -1;
308    last_blocked_command_disposition_ = CURRENT_TAB;
309  }
310}
311
312int BrowserCommandController::GetLastBlockedCommand(
313    WindowOpenDisposition* disposition) {
314  if (disposition)
315    *disposition = last_blocked_command_disposition_;
316  return last_blocked_command_id_;
317}
318
319void BrowserCommandController::TabStateChanged() {
320  UpdateCommandsForTabState();
321}
322
323void BrowserCommandController::ZoomStateChanged() {
324  UpdateCommandsForZoomState();
325}
326
327void BrowserCommandController::ContentRestrictionsChanged() {
328  UpdateCommandsForContentRestrictionState();
329}
330
331void BrowserCommandController::FullscreenStateChanged() {
332  UpdateCommandsForFullscreenMode();
333}
334
335void BrowserCommandController::PrintingStateChanged() {
336  UpdatePrintingState();
337}
338
339void BrowserCommandController::LoadingStateChanged(bool is_loading,
340                                                   bool force) {
341  UpdateReloadStopState(is_loading, force);
342}
343
344////////////////////////////////////////////////////////////////////////////////
345// BrowserCommandController, CommandUpdaterDelegate implementation:
346
347void BrowserCommandController::ExecuteCommandWithDisposition(
348    int id,
349    WindowOpenDisposition disposition) {
350  // No commands are enabled if there is not yet any selected tab.
351  // TODO(pkasting): It seems like we should not need this, because either
352  // most/all commands should not have been enabled yet anyway or the ones that
353  // are enabled should be global, or safe themselves against having no selected
354  // tab.  However, Ben says he tried removing this before and got lots of
355  // crashes, e.g. from Windows sending WM_COMMANDs at random times during
356  // window construction.  This probably could use closer examination someday.
357  if (browser_->tab_strip_model()->active_index() == TabStripModel::kNoTab)
358    return;
359
360  DCHECK(command_updater_.IsCommandEnabled(id)) << "Invalid/disabled command "
361                                                << id;
362
363  // If command execution is blocked then just record the command and return.
364  if (block_command_execution_) {
365    // We actually only allow no more than one blocked command, otherwise some
366    // commands maybe lost.
367    DCHECK_EQ(last_blocked_command_id_, -1);
368    last_blocked_command_id_ = id;
369    last_blocked_command_disposition_ = disposition;
370    return;
371  }
372
373  // The order of commands in this switch statement must match the function
374  // declaration order in browser.h!
375  switch (id) {
376    // Navigation commands
377    case IDC_BACK:
378      GoBack(browser_, disposition);
379      break;
380    case IDC_FORWARD:
381      GoForward(browser_, disposition);
382      break;
383    case IDC_RELOAD:
384      Reload(browser_, disposition);
385      break;
386    case IDC_RELOAD_CLEARING_CACHE:
387      ClearCache(browser_);
388      // FALL THROUGH
389    case IDC_RELOAD_IGNORING_CACHE:
390      ReloadIgnoringCache(browser_, disposition);
391      break;
392    case IDC_HOME:
393      Home(browser_, disposition);
394      break;
395    case IDC_OPEN_CURRENT_URL:
396      OpenCurrentURL(browser_);
397      break;
398    case IDC_STOP:
399      Stop(browser_);
400      break;
401
402     // Window management commands
403    case IDC_NEW_WINDOW:
404      NewWindow(browser_);
405      break;
406    case IDC_NEW_INCOGNITO_WINDOW:
407      NewIncognitoWindow(browser_);
408      break;
409    case IDC_CLOSE_WINDOW:
410      content::RecordAction(base::UserMetricsAction("CloseWindowByKey"));
411      CloseWindow(browser_);
412      break;
413    case IDC_NEW_TAB:
414      NewTab(browser_);
415      break;
416    case IDC_CLOSE_TAB:
417      content::RecordAction(base::UserMetricsAction("CloseTabByKey"));
418      CloseTab(browser_);
419      break;
420    case IDC_SELECT_NEXT_TAB:
421      content::RecordAction(base::UserMetricsAction("Accel_SelectNextTab"));
422      SelectNextTab(browser_);
423      break;
424    case IDC_SELECT_PREVIOUS_TAB:
425      content::RecordAction(
426          base::UserMetricsAction("Accel_SelectPreviousTab"));
427      SelectPreviousTab(browser_);
428      break;
429    case IDC_MOVE_TAB_NEXT:
430      MoveTabNext(browser_);
431      break;
432    case IDC_MOVE_TAB_PREVIOUS:
433      MoveTabPrevious(browser_);
434      break;
435    case IDC_SELECT_TAB_0:
436    case IDC_SELECT_TAB_1:
437    case IDC_SELECT_TAB_2:
438    case IDC_SELECT_TAB_3:
439    case IDC_SELECT_TAB_4:
440    case IDC_SELECT_TAB_5:
441    case IDC_SELECT_TAB_6:
442    case IDC_SELECT_TAB_7:
443      SelectNumberedTab(browser_, id - IDC_SELECT_TAB_0);
444      break;
445    case IDC_SELECT_LAST_TAB:
446      SelectLastTab(browser_);
447      break;
448    case IDC_DUPLICATE_TAB:
449      DuplicateTab(browser_);
450      break;
451    case IDC_RESTORE_TAB:
452      RestoreTab(browser_);
453      break;
454    case IDC_SHOW_AS_TAB:
455      ConvertPopupToTabbedBrowser(browser_);
456      break;
457    case IDC_FULLSCREEN:
458#if defined(OS_MACOSX)
459      chrome::ToggleFullscreenWithChromeOrFallback(browser_);
460#else
461      chrome::ToggleFullscreenMode(browser_);
462#endif
463      break;
464
465#if defined(OS_CHROMEOS)
466    case IDC_VISIT_DESKTOP_OF_LRU_USER_2:
467    case IDC_VISIT_DESKTOP_OF_LRU_USER_3:
468      ExecuteVisitDesktopCommand(id, browser_->window()->GetNativeWindow());
469      break;
470#endif
471
472#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
473    case IDC_USE_SYSTEM_TITLE_BAR: {
474      PrefService* prefs = browser_->profile()->GetPrefs();
475      prefs->SetBoolean(prefs::kUseCustomChromeFrame,
476                        !prefs->GetBoolean(prefs::kUseCustomChromeFrame));
477      break;
478    }
479#endif
480
481#if defined(OS_WIN)
482    // Windows 8 specific commands.
483    case IDC_METRO_SNAP_ENABLE:
484      browser_->SetMetroSnapMode(true);
485      break;
486    case IDC_METRO_SNAP_DISABLE:
487      browser_->SetMetroSnapMode(false);
488      break;
489    case IDC_WIN_DESKTOP_RESTART:
490      if (!VerifyASHSwitchForApps(window()->GetNativeWindow(), id))
491        break;
492
493      chrome::AttemptRestartToDesktopMode();
494      if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
495        content::RecordAction(base::UserMetricsAction("Win8DesktopRestart"));
496      } else {
497        content::RecordAction(base::UserMetricsAction("Win7DesktopRestart"));
498      }
499      break;
500    case IDC_WIN8_METRO_RESTART:
501    case IDC_WIN_CHROMEOS_RESTART:
502      if (!VerifyASHSwitchForApps(window()->GetNativeWindow(), id))
503        break;
504      if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
505        // SwitchToMetroUIHandler deletes itself.
506        new SwitchToMetroUIHandler;
507        content::RecordAction(base::UserMetricsAction("Win8MetroRestart"));
508      } else {
509        content::RecordAction(base::UserMetricsAction("Win7ASHRestart"));
510        chrome::AttemptRestartToMetroMode();
511      }
512      break;
513#endif
514
515#if defined(OS_MACOSX)
516    case IDC_PRESENTATION_MODE:
517      chrome::ToggleFullscreenMode(browser_);
518      break;
519#endif
520    case IDC_EXIT:
521      Exit();
522      break;
523
524    // Page-related commands
525    case IDC_SAVE_PAGE:
526      SavePage(browser_);
527      break;
528    case IDC_BOOKMARK_PAGE:
529      BookmarkCurrentPage(browser_);
530      break;
531    case IDC_PIN_TO_START_SCREEN:
532      TogglePagePinnedToStartScreen(browser_);
533      break;
534    case IDC_BOOKMARK_ALL_TABS:
535      BookmarkAllTabs(browser_);
536      break;
537    case IDC_VIEW_SOURCE:
538      ViewSelectedSource(browser_);
539      break;
540    case IDC_EMAIL_PAGE_LOCATION:
541      EmailPageLocation(browser_);
542      break;
543    case IDC_PRINT:
544      Print(browser_);
545      break;
546#if !defined(DISABLE_BASIC_PRINTING)
547    case IDC_BASIC_PRINT:
548      content::RecordAction(base::UserMetricsAction("Accel_Advanced_Print"));
549      BasicPrint(browser_);
550      break;
551#endif  // !DISABLE_BASIC_PRINTING
552    case IDC_TRANSLATE_PAGE:
553      Translate(browser_);
554      break;
555    case IDC_MANAGE_PASSWORDS_FOR_PAGE:
556      ManagePasswordsForPage(browser_);
557      break;
558
559    // Page encoding commands
560    case IDC_ENCODING_AUTO_DETECT:
561      browser_->ToggleEncodingAutoDetect();
562      break;
563    case IDC_ENCODING_UTF8:
564    case IDC_ENCODING_UTF16LE:
565    case IDC_ENCODING_ISO88591:
566    case IDC_ENCODING_WINDOWS1252:
567    case IDC_ENCODING_GBK:
568    case IDC_ENCODING_GB18030:
569    case IDC_ENCODING_BIG5HKSCS:
570    case IDC_ENCODING_BIG5:
571    case IDC_ENCODING_KOREAN:
572    case IDC_ENCODING_SHIFTJIS:
573    case IDC_ENCODING_ISO2022JP:
574    case IDC_ENCODING_EUCJP:
575    case IDC_ENCODING_THAI:
576    case IDC_ENCODING_ISO885915:
577    case IDC_ENCODING_MACINTOSH:
578    case IDC_ENCODING_ISO88592:
579    case IDC_ENCODING_WINDOWS1250:
580    case IDC_ENCODING_ISO88595:
581    case IDC_ENCODING_WINDOWS1251:
582    case IDC_ENCODING_KOI8R:
583    case IDC_ENCODING_KOI8U:
584    case IDC_ENCODING_ISO88597:
585    case IDC_ENCODING_WINDOWS1253:
586    case IDC_ENCODING_ISO88594:
587    case IDC_ENCODING_ISO885913:
588    case IDC_ENCODING_WINDOWS1257:
589    case IDC_ENCODING_ISO88593:
590    case IDC_ENCODING_ISO885910:
591    case IDC_ENCODING_ISO885914:
592    case IDC_ENCODING_ISO885916:
593    case IDC_ENCODING_WINDOWS1254:
594    case IDC_ENCODING_ISO88596:
595    case IDC_ENCODING_WINDOWS1256:
596    case IDC_ENCODING_ISO88598:
597    case IDC_ENCODING_ISO88598I:
598    case IDC_ENCODING_WINDOWS1255:
599    case IDC_ENCODING_WINDOWS1258:
600      browser_->OverrideEncoding(id);
601      break;
602
603    // Clipboard commands
604    case IDC_CUT:
605      Cut(browser_);
606      break;
607    case IDC_COPY:
608      Copy(browser_);
609      break;
610    case IDC_PASTE:
611      Paste(browser_);
612      break;
613
614    // Find-in-page
615    case IDC_FIND:
616      Find(browser_);
617      break;
618    case IDC_FIND_NEXT:
619      FindNext(browser_);
620      break;
621    case IDC_FIND_PREVIOUS:
622      FindPrevious(browser_);
623      break;
624
625    // Zoom
626    case IDC_ZOOM_PLUS:
627      Zoom(browser_, content::PAGE_ZOOM_IN);
628      break;
629    case IDC_ZOOM_NORMAL:
630      Zoom(browser_, content::PAGE_ZOOM_RESET);
631      break;
632    case IDC_ZOOM_MINUS:
633      Zoom(browser_, content::PAGE_ZOOM_OUT);
634      break;
635
636    // Focus various bits of UI
637    case IDC_FOCUS_TOOLBAR:
638      content::RecordAction(base::UserMetricsAction("Accel_Focus_Toolbar"));
639      FocusToolbar(browser_);
640      break;
641    case IDC_FOCUS_LOCATION:
642      content::RecordAction(base::UserMetricsAction("Accel_Focus_Location"));
643      FocusLocationBar(browser_);
644      break;
645    case IDC_FOCUS_SEARCH:
646      content::RecordAction(base::UserMetricsAction("Accel_Focus_Search"));
647      FocusSearch(browser_);
648      break;
649    case IDC_FOCUS_MENU_BAR:
650      FocusAppMenu(browser_);
651      break;
652    case IDC_FOCUS_BOOKMARKS:
653      content::RecordAction(
654          base::UserMetricsAction("Accel_Focus_Bookmarks"));
655      FocusBookmarksToolbar(browser_);
656      break;
657    case IDC_FOCUS_INFOBARS:
658      FocusInfobars(browser_);
659      break;
660    case IDC_FOCUS_NEXT_PANE:
661      FocusNextPane(browser_);
662      break;
663    case IDC_FOCUS_PREVIOUS_PANE:
664      FocusPreviousPane(browser_);
665      break;
666
667    // Show various bits of UI
668    case IDC_OPEN_FILE:
669      browser_->OpenFile();
670      break;
671    case IDC_CREATE_SHORTCUTS:
672      CreateApplicationShortcuts(browser_);
673      break;
674    case IDC_CREATE_HOSTED_APP:
675      CreateBookmarkAppFromCurrentWebContents(browser_);
676      break;
677    case IDC_DEV_TOOLS:
678      ToggleDevToolsWindow(browser_, DevToolsToggleAction::Show());
679      break;
680    case IDC_DEV_TOOLS_CONSOLE:
681      ToggleDevToolsWindow(browser_, DevToolsToggleAction::ShowConsole());
682      break;
683    case IDC_DEV_TOOLS_DEVICES:
684      InspectUI::InspectDevices(browser_);
685      break;
686    case IDC_DEV_TOOLS_INSPECT:
687      ToggleDevToolsWindow(browser_, DevToolsToggleAction::Inspect());
688      break;
689    case IDC_DEV_TOOLS_TOGGLE:
690      ToggleDevToolsWindow(browser_, DevToolsToggleAction::Toggle());
691      break;
692    case IDC_TASK_MANAGER:
693      OpenTaskManager(browser_);
694      break;
695#if defined(OS_CHROMEOS)
696    case IDC_TAKE_SCREENSHOT:
697      TakeScreenshot();
698      break;
699#endif
700#if defined(GOOGLE_CHROME_BUILD)
701    case IDC_FEEDBACK:
702      OpenFeedbackDialog(browser_);
703      break;
704#endif
705    case IDC_SHOW_BOOKMARK_BAR:
706      ToggleBookmarkBar(browser_);
707      break;
708    case IDC_PROFILING_ENABLED:
709      Profiling::Toggle();
710      break;
711
712    case IDC_SHOW_BOOKMARK_MANAGER:
713      ShowBookmarkManager(browser_);
714      break;
715    case IDC_SHOW_APP_MENU:
716      content::RecordAction(base::UserMetricsAction("Accel_Show_App_Menu"));
717      ShowAppMenu(browser_);
718      break;
719    case IDC_SHOW_AVATAR_MENU:
720      ShowAvatarMenu(browser_);
721      break;
722    case IDC_SHOW_HISTORY:
723      ShowHistory(browser_);
724      break;
725    case IDC_SHOW_DOWNLOADS:
726      ShowDownloads(browser_);
727      break;
728    case IDC_MANAGE_EXTENSIONS:
729      ShowExtensions(browser_, std::string());
730      break;
731    case IDC_OPTIONS:
732      ShowSettings(browser_);
733      break;
734    case IDC_EDIT_SEARCH_ENGINES:
735      ShowSearchEngineSettings(browser_);
736      break;
737    case IDC_VIEW_PASSWORDS:
738      ShowPasswordManager(browser_);
739      break;
740    case IDC_CLEAR_BROWSING_DATA:
741      ShowClearBrowsingDataDialog(browser_);
742      break;
743    case IDC_IMPORT_SETTINGS:
744      ShowImportDialog(browser_);
745      break;
746    case IDC_TOGGLE_REQUEST_TABLET_SITE:
747      ToggleRequestTabletSite(browser_);
748      break;
749    case IDC_ABOUT:
750      ShowAboutChrome(browser_);
751      break;
752    case IDC_UPGRADE_DIALOG:
753      OpenUpdateChromeDialog(browser_);
754      break;
755    case IDC_VIEW_INCOMPATIBILITIES:
756      ShowConflicts(browser_);
757      break;
758    case IDC_HELP_PAGE_VIA_KEYBOARD:
759      ShowHelp(browser_, HELP_SOURCE_KEYBOARD);
760      break;
761    case IDC_HELP_PAGE_VIA_MENU:
762      ShowHelp(browser_, HELP_SOURCE_MENU);
763      break;
764    case IDC_SHOW_SIGNIN:
765      ShowBrowserSignin(browser_, signin::SOURCE_MENU);
766      break;
767    case IDC_TOGGLE_SPEECH_INPUT:
768      ToggleSpeechInput(browser_);
769      break;
770    case IDC_DISTILL_PAGE:
771      DistillCurrentPage(browser_);
772      break;
773
774    default:
775      LOG(WARNING) << "Received Unimplemented Command: " << id;
776      break;
777  }
778}
779
780////////////////////////////////////////////////////////////////////////////////
781// BrowserCommandController, SigninPrefObserver implementation:
782
783void BrowserCommandController::OnSigninAllowedPrefChange() {
784  // For unit tests, we don't have a window.
785  if (!window())
786    return;
787  UpdateShowSyncState(IsShowingMainUI());
788}
789
790// BrowserCommandController, TabStripModelObserver implementation:
791
792void BrowserCommandController::TabInsertedAt(WebContents* contents,
793                                             int index,
794                                             bool foreground) {
795  AddInterstitialObservers(contents);
796}
797
798void BrowserCommandController::TabDetachedAt(WebContents* contents, int index) {
799  RemoveInterstitialObservers(contents);
800}
801
802void BrowserCommandController::TabReplacedAt(TabStripModel* tab_strip_model,
803                                             WebContents* old_contents,
804                                             WebContents* new_contents,
805                                             int index) {
806  RemoveInterstitialObservers(old_contents);
807  AddInterstitialObservers(new_contents);
808}
809
810void BrowserCommandController::TabBlockedStateChanged(
811    content::WebContents* contents,
812    int index) {
813  PrintingStateChanged();
814  FullscreenStateChanged();
815  UpdateCommandsForFind();
816}
817
818////////////////////////////////////////////////////////////////////////////////
819// BrowserCommandController, TabRestoreServiceObserver implementation:
820
821void BrowserCommandController::TabRestoreServiceChanged(
822    TabRestoreService* service) {
823  UpdateTabRestoreCommandState();
824}
825
826void BrowserCommandController::TabRestoreServiceDestroyed(
827    TabRestoreService* service) {
828  service->RemoveObserver(this);
829}
830
831void BrowserCommandController::TabRestoreServiceLoaded(
832    TabRestoreService* service) {
833  UpdateTabRestoreCommandState();
834}
835
836////////////////////////////////////////////////////////////////////////////////
837// BrowserCommandController, private:
838
839class BrowserCommandController::InterstitialObserver
840    : public content::WebContentsObserver {
841 public:
842  InterstitialObserver(BrowserCommandController* controller,
843                       content::WebContents* web_contents)
844      : WebContentsObserver(web_contents),
845        controller_(controller) {
846  }
847
848  virtual void DidAttachInterstitialPage() OVERRIDE {
849    controller_->UpdateCommandsForTabState();
850  }
851
852  virtual void DidDetachInterstitialPage() OVERRIDE {
853    controller_->UpdateCommandsForTabState();
854  }
855
856 private:
857  BrowserCommandController* controller_;
858
859  DISALLOW_COPY_AND_ASSIGN(InterstitialObserver);
860};
861
862bool BrowserCommandController::IsShowingMainUI() {
863  bool should_hide_ui = window() && window()->ShouldHideUIForFullscreen();
864  return browser_->is_type_tabbed() && !should_hide_ui;
865}
866
867void BrowserCommandController::InitCommandState() {
868  // All browser commands whose state isn't set automagically some other way
869  // (like Back & Forward with initial page load) must have their state
870  // initialized here, otherwise they will be forever disabled.
871
872  // Navigation commands
873  command_updater_.UpdateCommandEnabled(IDC_RELOAD, true);
874  command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE, true);
875  command_updater_.UpdateCommandEnabled(IDC_RELOAD_CLEARING_CACHE, true);
876
877  // Window management commands
878  command_updater_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true);
879  command_updater_.UpdateCommandEnabled(IDC_NEW_TAB, true);
880  command_updater_.UpdateCommandEnabled(IDC_CLOSE_TAB, true);
881  command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true);
882  UpdateTabRestoreCommandState();
883#if defined(OS_WIN) && defined(USE_ASH)
884  if (browser_->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
885    command_updater_.UpdateCommandEnabled(IDC_EXIT, true);
886#else
887  command_updater_.UpdateCommandEnabled(IDC_EXIT, true);
888#endif
889  command_updater_.UpdateCommandEnabled(IDC_DEBUG_FRAME_TOGGLE, true);
890#if defined(USE_ASH)
891  command_updater_.UpdateCommandEnabled(IDC_MINIMIZE_WINDOW, true);
892#endif
893#if defined(OS_CHROMEOS)
894  command_updater_.UpdateCommandEnabled(IDC_VISIT_DESKTOP_OF_LRU_USER_2, true);
895  command_updater_.UpdateCommandEnabled(IDC_VISIT_DESKTOP_OF_LRU_USER_3, true);
896#endif
897#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
898  command_updater_.UpdateCommandEnabled(IDC_USE_SYSTEM_TITLE_BAR, true);
899#endif
900
901  // Page-related commands
902  command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION, true);
903  command_updater_.UpdateCommandEnabled(IDC_MANAGE_PASSWORDS_FOR_PAGE, true);
904  command_updater_.UpdateCommandEnabled(IDC_ENCODING_AUTO_DETECT, true);
905  command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF8, true);
906  command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF16LE, true);
907  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88591, true);
908  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1252, true);
909  command_updater_.UpdateCommandEnabled(IDC_ENCODING_GBK, true);
910  command_updater_.UpdateCommandEnabled(IDC_ENCODING_GB18030, true);
911  command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5HKSCS, true);
912  command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5, true);
913  command_updater_.UpdateCommandEnabled(IDC_ENCODING_THAI, true);
914  command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOREAN, true);
915  command_updater_.UpdateCommandEnabled(IDC_ENCODING_SHIFTJIS, true);
916  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO2022JP, true);
917  command_updater_.UpdateCommandEnabled(IDC_ENCODING_EUCJP, true);
918  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885915, true);
919  command_updater_.UpdateCommandEnabled(IDC_ENCODING_MACINTOSH, true);
920  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88592, true);
921  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1250, true);
922  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88595, true);
923  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1251, true);
924  command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8R, true);
925  command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8U, true);
926  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88597, true);
927  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1253, true);
928  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88594, true);
929  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885913, true);
930  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1257, true);
931  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88593, true);
932  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885910, true);
933  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885914, true);
934  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885916, true);
935  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1254, true);
936  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88596, true);
937  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1256, true);
938  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598, true);
939  command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598I, true);
940  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1255, true);
941  command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1258, true);
942
943  // Zoom
944  command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, true);
945  command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true);
946  command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, false);
947  command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true);
948
949  // Show various bits of UI
950  const bool guest_session = profile()->IsGuestSession();
951  const bool normal_window = browser_->is_type_tabbed();
952  UpdateOpenFileState(&command_updater_);
953  command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false);
954  UpdateCommandsForDevTools();
955  command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, CanOpenTaskManager());
956  command_updater_.UpdateCommandEnabled(IDC_SHOW_HISTORY, !guest_session);
957  command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
958  command_updater_.UpdateCommandEnabled(IDC_HELP_MENU, true);
959  command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE_VIA_KEYBOARD, true);
960  command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE_VIA_MENU, true);
961  command_updater_.UpdateCommandEnabled(IDC_BOOKMARKS_MENU, !guest_session);
962  command_updater_.UpdateCommandEnabled(IDC_RECENT_TABS_MENU,
963                                        !guest_session &&
964                                        !profile()->IsOffTheRecord());
965  command_updater_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA, normal_window);
966#if defined(OS_CHROMEOS)
967  command_updater_.UpdateCommandEnabled(IDC_TAKE_SCREENSHOT, true);
968#else
969  // Chrome OS uses the system tray menu to handle multi-profiles.
970  if (normal_window && (guest_session || !profile()->IsOffTheRecord()))
971    command_updater_.UpdateCommandEnabled(IDC_SHOW_AVATAR_MENU, true);
972#endif
973
974  UpdateShowSyncState(true);
975
976  // Navigation commands
977  command_updater_.UpdateCommandEnabled(
978      IDC_HOME,
979      normal_window || (extensions::util::IsStreamlinedHostedAppsEnabled() &&
980                        browser_->is_app()));
981
982  // Window management commands
983  command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window);
984  command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB,
985                                        normal_window);
986  command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_NEXT, normal_window);
987  command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_PREVIOUS, normal_window);
988  command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_0, normal_window);
989  command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_1, normal_window);
990  command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_2, normal_window);
991  command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_3, normal_window);
992  command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_4, normal_window);
993  command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_5, normal_window);
994  command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window);
995  command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window);
996  command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window);
997#if defined(OS_WIN)
998  bool metro = browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH;
999  command_updater_.UpdateCommandEnabled(IDC_METRO_SNAP_ENABLE, metro);
1000  command_updater_.UpdateCommandEnabled(IDC_METRO_SNAP_DISABLE, metro);
1001  int restart_mode = metro ? IDC_WIN_DESKTOP_RESTART :
1002      (base::win::GetVersion() >= base::win::VERSION_WIN8 ?
1003          IDC_WIN8_METRO_RESTART : IDC_WIN_CHROMEOS_RESTART);
1004  command_updater_.UpdateCommandEnabled(restart_mode, normal_window);
1005#endif
1006
1007  // These are always enabled; the menu determines their menu item visibility.
1008  command_updater_.UpdateCommandEnabled(IDC_UPGRADE_DIALOG, true);
1009  command_updater_.UpdateCommandEnabled(IDC_VIEW_INCOMPATIBILITIES, true);
1010
1011  // Toggle speech input
1012  command_updater_.UpdateCommandEnabled(IDC_TOGGLE_SPEECH_INPUT, true);
1013
1014  // Distill current page.
1015  command_updater_.UpdateCommandEnabled(
1016      IDC_DISTILL_PAGE,
1017      CommandLine::ForCurrentProcess()->HasSwitch(
1018          switches::kEnableDomDistiller));
1019
1020  // Initialize other commands whose state changes based on various conditions.
1021  UpdateCommandsForFullscreenMode();
1022  UpdateCommandsForContentRestrictionState();
1023  UpdateCommandsForBookmarkEditing();
1024  UpdateCommandsForIncognitoAvailability();
1025}
1026
1027// static
1028void BrowserCommandController::UpdateSharedCommandsForIncognitoAvailability(
1029    CommandUpdater* command_updater,
1030    Profile* profile) {
1031  const bool guest_session = profile->IsGuestSession();
1032  // TODO(mlerman): Make GetAvailability account for profile->IsGuestSession().
1033  IncognitoModePrefs::Availability incognito_availability =
1034      IncognitoModePrefs::GetAvailability(profile->GetPrefs());
1035  command_updater->UpdateCommandEnabled(
1036      IDC_NEW_WINDOW,
1037      incognito_availability != IncognitoModePrefs::FORCED);
1038  command_updater->UpdateCommandEnabled(
1039      IDC_NEW_INCOGNITO_WINDOW,
1040      incognito_availability != IncognitoModePrefs::DISABLED && !guest_session);
1041
1042  const bool forced_incognito =
1043      incognito_availability == IncognitoModePrefs::FORCED ||
1044      guest_session;  // Guest always runs in Incognito mode.
1045  command_updater->UpdateCommandEnabled(
1046      IDC_SHOW_BOOKMARK_MANAGER,
1047      browser_defaults::bookmarks_enabled && !forced_incognito);
1048  ExtensionService* extension_service =
1049      extensions::ExtensionSystem::Get(profile)->extension_service();
1050  const bool enable_extensions =
1051      extension_service && extension_service->extensions_enabled();
1052
1053  // Bookmark manager and settings page/subpages are forced to open in normal
1054  // mode. For this reason we disable these commands when incognito is forced.
1055  command_updater->UpdateCommandEnabled(IDC_MANAGE_EXTENSIONS,
1056                                        enable_extensions && !forced_incognito);
1057
1058  command_updater->UpdateCommandEnabled(IDC_IMPORT_SETTINGS, !forced_incognito);
1059  command_updater->UpdateCommandEnabled(IDC_OPTIONS,
1060                                        !forced_incognito || guest_session);
1061  command_updater->UpdateCommandEnabled(IDC_SHOW_SIGNIN, !forced_incognito);
1062}
1063
1064void BrowserCommandController::UpdateCommandsForIncognitoAvailability() {
1065  UpdateSharedCommandsForIncognitoAvailability(&command_updater_, profile());
1066
1067  if (!IsShowingMainUI()) {
1068    command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, false);
1069    command_updater_.UpdateCommandEnabled(IDC_OPTIONS, false);
1070  }
1071}
1072
1073void BrowserCommandController::UpdateCommandsForTabState() {
1074  WebContents* current_web_contents =
1075      browser_->tab_strip_model()->GetActiveWebContents();
1076  if (!current_web_contents)  // May be NULL during tab restore.
1077    return;
1078
1079  // Navigation commands
1080  command_updater_.UpdateCommandEnabled(IDC_BACK, CanGoBack(browser_));
1081  command_updater_.UpdateCommandEnabled(IDC_FORWARD, CanGoForward(browser_));
1082  command_updater_.UpdateCommandEnabled(IDC_RELOAD, CanReload(browser_));
1083  command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE,
1084                                        CanReload(browser_));
1085  command_updater_.UpdateCommandEnabled(IDC_RELOAD_CLEARING_CACHE,
1086                                        CanReload(browser_));
1087
1088  // Window management commands
1089  command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB,
1090      !browser_->is_app() && CanDuplicateTab(browser_));
1091
1092  // Page-related commands
1093  window()->SetStarredState(
1094      BookmarkTabHelper::FromWebContents(current_web_contents)->is_starred());
1095  window()->ZoomChangedForActiveTab(false);
1096  command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE,
1097                                        CanViewSource(browser_));
1098  command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION,
1099                                        CanEmailPageLocation(browser_));
1100  if (browser_->is_devtools())
1101    command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, false);
1102
1103  // Changing the encoding is not possible on Chrome-internal webpages.
1104  NavigationController& nc = current_web_contents->GetController();
1105  bool is_chrome_internal = HasInternalURL(nc.GetLastCommittedEntry()) ||
1106      current_web_contents->ShowingInterstitialPage();
1107  command_updater_.UpdateCommandEnabled(IDC_ENCODING_MENU,
1108      !is_chrome_internal && current_web_contents->IsSavable());
1109
1110  // Show various bits of UI
1111  // TODO(pinkerton): Disable app-mode in the model until we implement it
1112  // on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148
1113#if !defined(OS_MACOSX)
1114  command_updater_.UpdateCommandEnabled(
1115      IDC_CREATE_SHORTCUTS,
1116      CanCreateApplicationShortcuts(browser_));
1117  command_updater_.UpdateCommandEnabled(IDC_CREATE_HOSTED_APP,
1118                                        CanCreateBookmarkApp(browser_));
1119#endif
1120
1121  command_updater_.UpdateCommandEnabled(
1122      IDC_TOGGLE_REQUEST_TABLET_SITE,
1123      CanRequestTabletSite(current_web_contents));
1124
1125  UpdateCommandsForContentRestrictionState();
1126  UpdateCommandsForBookmarkEditing();
1127  UpdateCommandsForFind();
1128  // Update the zoom commands when an active tab is selected.
1129  UpdateCommandsForZoomState();
1130}
1131
1132void BrowserCommandController::UpdateCommandsForZoomState() {
1133  WebContents* contents =
1134      browser_->tab_strip_model()->GetActiveWebContents();
1135  if (!contents)
1136    return;
1137  command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, CanZoomIn(contents));
1138  command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, ActualSize(contents));
1139  command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, CanZoomOut(contents));
1140}
1141
1142void BrowserCommandController::UpdateCommandsForContentRestrictionState() {
1143  int restrictions = GetContentRestrictions(browser_);
1144
1145  command_updater_.UpdateCommandEnabled(
1146      IDC_COPY, !(restrictions & CONTENT_RESTRICTION_COPY));
1147  command_updater_.UpdateCommandEnabled(
1148      IDC_CUT, !(restrictions & CONTENT_RESTRICTION_CUT));
1149  command_updater_.UpdateCommandEnabled(
1150      IDC_PASTE, !(restrictions & CONTENT_RESTRICTION_PASTE));
1151  UpdateSaveAsState();
1152  UpdatePrintingState();
1153}
1154
1155void BrowserCommandController::UpdateCommandsForDevTools() {
1156  bool dev_tools_enabled =
1157      !profile()->GetPrefs()->GetBoolean(prefs::kDevToolsDisabled);
1158  command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS,
1159                                        dev_tools_enabled);
1160  command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_CONSOLE,
1161                                        dev_tools_enabled);
1162  command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_DEVICES,
1163                                        dev_tools_enabled);
1164  command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_INSPECT,
1165                                        dev_tools_enabled);
1166  command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_TOGGLE,
1167                                        dev_tools_enabled);
1168}
1169
1170void BrowserCommandController::UpdateCommandsForBookmarkEditing() {
1171  command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_PAGE,
1172                                        CanBookmarkCurrentPage(browser_));
1173  command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_ALL_TABS,
1174                                        CanBookmarkAllTabs(browser_));
1175  command_updater_.UpdateCommandEnabled(IDC_PIN_TO_START_SCREEN,
1176                                        true);
1177}
1178
1179void BrowserCommandController::UpdateCommandsForBookmarkBar() {
1180  command_updater_.UpdateCommandEnabled(
1181      IDC_SHOW_BOOKMARK_BAR,
1182      browser_defaults::bookmarks_enabled && !profile()->IsGuestSession() &&
1183          !profile()->GetPrefs()->IsManagedPreference(
1184              bookmarks::prefs::kShowBookmarkBar) &&
1185          IsShowingMainUI());
1186}
1187
1188void BrowserCommandController::UpdateCommandsForFileSelectionDialogs() {
1189  UpdateSaveAsState();
1190  UpdateOpenFileState(&command_updater_);
1191}
1192
1193void BrowserCommandController::UpdateCommandsForFullscreenMode() {
1194  WindowState window_state = WINDOW_STATE_NOT_FULLSCREEN;
1195  if (window() && window()->IsFullscreen()) {
1196    window_state = WINDOW_STATE_FULLSCREEN;
1197#if defined(OS_WIN)
1198    if (window()->IsInMetroSnapMode())
1199      window_state = WINDOW_STATE_METRO_SNAP;
1200#endif
1201  }
1202  bool show_main_ui = IsShowingMainUI();
1203  bool main_not_fullscreen =
1204      show_main_ui && window_state == WINDOW_STATE_NOT_FULLSCREEN;
1205
1206  // Navigation commands
1207  command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, show_main_ui);
1208
1209  // Window management commands
1210  command_updater_.UpdateCommandEnabled(
1211      IDC_SHOW_AS_TAB,
1212      !browser_->is_type_tabbed() &&
1213          window_state == WINDOW_STATE_NOT_FULLSCREEN);
1214
1215  // Focus various bits of UI
1216  command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, show_main_ui);
1217  command_updater_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, show_main_ui);
1218  command_updater_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, show_main_ui);
1219  command_updater_.UpdateCommandEnabled(
1220      IDC_FOCUS_MENU_BAR, main_not_fullscreen);
1221  command_updater_.UpdateCommandEnabled(
1222      IDC_FOCUS_NEXT_PANE, main_not_fullscreen);
1223  command_updater_.UpdateCommandEnabled(
1224      IDC_FOCUS_PREVIOUS_PANE, main_not_fullscreen);
1225  command_updater_.UpdateCommandEnabled(
1226      IDC_FOCUS_BOOKMARKS, main_not_fullscreen);
1227  command_updater_.UpdateCommandEnabled(
1228      IDC_FOCUS_INFOBARS, main_not_fullscreen);
1229
1230  // Show various bits of UI
1231  command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, show_main_ui);
1232#if defined(GOOGLE_CHROME_BUILD)
1233  command_updater_.UpdateCommandEnabled(IDC_FEEDBACK, show_main_ui);
1234#endif
1235  UpdateShowSyncState(show_main_ui);
1236
1237  // Settings page/subpages are forced to open in normal mode. We disable these
1238  // commands for guest sessions and when incognito is forced.
1239  const bool options_enabled = show_main_ui &&
1240      IncognitoModePrefs::GetAvailability(
1241          profile()->GetPrefs()) != IncognitoModePrefs::FORCED;
1242  const bool guest_session = profile()->IsGuestSession();
1243  command_updater_.UpdateCommandEnabled(IDC_OPTIONS, options_enabled);
1244  command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS,
1245                                        options_enabled && !guest_session);
1246
1247  command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui);
1248  command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui);
1249  command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui);
1250  command_updater_.UpdateCommandEnabled(IDC_SHOW_APP_MENU, show_main_ui);
1251#if defined (ENABLE_PROFILING) && !defined(NO_TCMALLOC)
1252  command_updater_.UpdateCommandEnabled(IDC_PROFILING_ENABLED, show_main_ui);
1253#endif
1254
1255  // Disable explicit fullscreen toggling when in metro snap mode.
1256  bool fullscreen_enabled = window_state != WINDOW_STATE_METRO_SNAP;
1257#if !defined(OS_MACOSX)
1258  if (window_state == WINDOW_STATE_NOT_FULLSCREEN &&
1259      !profile()->GetPrefs()->GetBoolean(prefs::kFullscreenAllowed)) {
1260    // Disable toggling into fullscreen mode if disallowed by pref.
1261    fullscreen_enabled = false;
1262  }
1263#endif
1264
1265  command_updater_.UpdateCommandEnabled(IDC_FULLSCREEN, fullscreen_enabled);
1266  command_updater_.UpdateCommandEnabled(IDC_PRESENTATION_MODE,
1267                                        fullscreen_enabled);
1268
1269  UpdateCommandsForBookmarkBar();
1270}
1271
1272void BrowserCommandController::UpdatePrintingState() {
1273  bool print_enabled = CanPrint(browser_);
1274  command_updater_.UpdateCommandEnabled(IDC_PRINT, print_enabled);
1275#if !defined(DISABLE_BASIC_PRINTING)
1276  command_updater_.UpdateCommandEnabled(IDC_BASIC_PRINT,
1277                                        CanBasicPrint(browser_));
1278#endif  // !DISABLE_BASIC_PRINTING
1279}
1280
1281void BrowserCommandController::UpdateSaveAsState() {
1282  command_updater_.UpdateCommandEnabled(IDC_SAVE_PAGE, CanSavePage(browser_));
1283}
1284
1285void BrowserCommandController::UpdateShowSyncState(bool show_main_ui) {
1286  command_updater_.UpdateCommandEnabled(
1287      IDC_SHOW_SYNC_SETUP, show_main_ui && pref_signin_allowed_.GetValue());
1288}
1289
1290// static
1291void BrowserCommandController::UpdateOpenFileState(
1292    CommandUpdater* command_updater) {
1293  bool enabled = true;
1294  PrefService* local_state = g_browser_process->local_state();
1295  if (local_state)
1296    enabled = local_state->GetBoolean(prefs::kAllowFileSelectionDialogs);
1297
1298  command_updater->UpdateCommandEnabled(IDC_OPEN_FILE, enabled);
1299}
1300
1301void BrowserCommandController::UpdateReloadStopState(bool is_loading,
1302                                                     bool force) {
1303  window()->UpdateReloadStopState(is_loading, force);
1304  command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading);
1305}
1306
1307void BrowserCommandController::UpdateTabRestoreCommandState() {
1308  TabRestoreService* tab_restore_service =
1309      TabRestoreServiceFactory::GetForProfile(profile());
1310  // The command is enabled if the service hasn't loaded yet to trigger loading.
1311  // The command is updated once the load completes.
1312  command_updater_.UpdateCommandEnabled(
1313      IDC_RESTORE_TAB,
1314      tab_restore_service &&
1315      (!tab_restore_service->IsLoaded() ||
1316       GetRestoreTabType(browser_) != TabStripModelDelegate::RESTORE_NONE));
1317}
1318
1319void BrowserCommandController::UpdateCommandsForFind() {
1320  TabStripModel* model = browser_->tab_strip_model();
1321  bool enabled = !model->IsTabBlocked(model->active_index()) &&
1322                 !browser_->is_devtools();
1323
1324  command_updater_.UpdateCommandEnabled(IDC_FIND, enabled);
1325  command_updater_.UpdateCommandEnabled(IDC_FIND_NEXT, enabled);
1326  command_updater_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, enabled);
1327}
1328
1329void BrowserCommandController::AddInterstitialObservers(WebContents* contents) {
1330  interstitial_observers_.push_back(new InterstitialObserver(this, contents));
1331}
1332
1333void BrowserCommandController::RemoveInterstitialObservers(
1334    WebContents* contents) {
1335  for (size_t i = 0; i < interstitial_observers_.size(); i++) {
1336    if (interstitial_observers_[i]->web_contents() != contents)
1337      continue;
1338
1339    delete interstitial_observers_[i];
1340    interstitial_observers_.erase(interstitial_observers_.begin() + i);
1341    return;
1342  }
1343}
1344
1345BrowserWindow* BrowserCommandController::window() {
1346  return browser_->window();
1347}
1348
1349Profile* BrowserCommandController::profile() {
1350  return browser_->profile();
1351}
1352
1353}  // namespace chrome
1354