1 // Copyright 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.
5 #include "chrome/browser/ui/browser_commands.h"
7 #include "base/command_line.h"
8 #include "base/metrics/histogram.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/app/chrome_command_ids.h"
12 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/browsing_data/browsing_data_helper.h"
15 #include "chrome/browser/browsing_data/browsing_data_remover.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/chrome_page_zoom.h"
18 #include "chrome/browser/devtools/devtools_window.h"
19 #include "chrome/browser/dom_distiller/tab_utils.h"
20 #include "chrome/browser/extensions/api/commands/command_service.h"
21 #include "chrome/browser/extensions/tab_helper.h"
22 #include "chrome/browser/favicon/favicon_tab_helper.h"
23 #include "chrome/browser/lifetime/application_lifetime.h"
24 #include "chrome/browser/platform_util.h"
25 #include "chrome/browser/prefs/incognito_mode_prefs.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/rlz/rlz.h"
28 #include "chrome/browser/search/search.h"
29 #include "chrome/browser/sessions/session_service_factory.h"
30 #include "chrome/browser/sessions/tab_restore_service.h"
31 #include "chrome/browser/sessions/tab_restore_service_delegate.h"
32 #include "chrome/browser/sessions/tab_restore_service_factory.h"
33 #include "chrome/browser/signin/signin_header_helper.h"
34 #include "chrome/browser/translate/chrome_translate_client.h"
35 #include "chrome/browser/ui/accelerator_utils.h"
36 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
37 #include "chrome/browser/ui/browser.h"
38 #include "chrome/browser/ui/browser_command_controller.h"
39 #include "chrome/browser/ui/browser_dialogs.h"
40 #include "chrome/browser/ui/browser_instant_controller.h"
41 #include "chrome/browser/ui/browser_tab_restore_service_delegate.h"
42 #include "chrome/browser/ui/browser_tabstrip.h"
43 #include "chrome/browser/ui/browser_window.h"
44 #include "chrome/browser/ui/chrome_pages.h"
45 #include "chrome/browser/ui/find_bar/find_bar.h"
46 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
47 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
48 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
49 #include "chrome/browser/ui/location_bar/location_bar.h"
50 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
51 #include "chrome/browser/ui/search/search_tab_helper.h"
52 #include "chrome/browser/ui/status_bubble.h"
53 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
54 #include "chrome/browser/ui/tabs/tab_strip_model.h"
55 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
56 #include "chrome/browser/ui/zoom/zoom_controller.h"
57 #include "chrome/browser/upgrade_detector.h"
58 #include "chrome/browser/web_applications/web_app.h"
59 #include "chrome/common/chrome_switches.h"
60 #include "chrome/common/chrome_version_info.h"
61 #include "chrome/common/content_restriction.h"
62 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
63 #include "chrome/common/pref_names.h"
64 #include "components/bookmarks/browser/bookmark_model.h"
65 #include "components/bookmarks/browser/bookmark_utils.h"
66 #include "components/google/core/browser/google_util.h"
67 #include "components/translate/core/browser/language_state.h"
68 #include "components/web_modal/web_contents_modal_dialog_manager.h"
69 #include "content/public/browser/devtools_agent_host.h"
70 #include "content/public/browser/navigation_controller.h"
71 #include "content/public/browser/navigation_entry.h"
72 #include "content/public/browser/notification_service.h"
73 #include "content/public/browser/page_navigator.h"
74 #include "content/public/browser/render_view_host.h"
75 #include "content/public/browser/render_widget_host_view.h"
76 #include "content/public/browser/user_metrics.h"
77 #include "content/public/browser/web_contents.h"
78 #include "content/public/common/renderer_preferences.h"
79 #include "content/public/common/url_constants.h"
80 #include "content/public/common/url_utils.h"
81 #include "content/public/common/user_agent.h"
82 #include "extensions/browser/extension_registry.h"
83 #include "extensions/browser/extension_system.h"
84 #include "extensions/common/extension.h"
85 #include "extensions/common/extension_set.h"
86 #include "net/base/escape.h"
87 #include "ui/events/keycodes/keyboard_codes.h"
90 #include "chrome/browser/ui/metro_pin_tab_helper_win.h"
93 #if defined(ENABLE_PRINTING)
94 #if defined(ENABLE_FULL_PRINTING)
95 #include "chrome/browser/printing/print_preview_dialog_controller.h"
96 #include "chrome/browser/printing/print_view_manager.h"
98 #include "chrome/browser/printing/print_view_manager_basic.h"
99 #endif // defined(ENABLE_FULL_PRINTING)
100 #endif // defined(ENABLE_PRINTING)
103 const char kOsOverrideForTabletSite[] = "Linux; Android 4.0.3";
106 using base::UserMetricsAction;
107 using content::NavigationController;
108 using content::NavigationEntry;
109 using content::OpenURLParams;
110 using content::Referrer;
111 using content::SSLStatus;
112 using content::WebContents;
113 using web_modal::WebContentsModalDialogManager;
118 bool CanBookmarkCurrentPageInternal(const Browser* browser,
119 bool check_remove_bookmark_ui) {
120 BookmarkModel* model =
121 BookmarkModelFactory::GetForProfile(browser->profile());
122 return browser_defaults::bookmarks_enabled &&
123 browser->profile()->GetPrefs()->GetBoolean(
124 prefs::kEditBookmarksEnabled) &&
125 model && model->loaded() && browser->is_type_tabbed() &&
126 (!check_remove_bookmark_ui ||
127 !chrome::ShouldRemoveBookmarkThisPageUI(browser->profile()));
130 bool GetBookmarkOverrideCommand(
132 const extensions::Extension** extension,
133 extensions::Command* command,
134 extensions::CommandService::ExtensionCommandType* command_type) {
137 DCHECK(command_type);
139 ui::Accelerator bookmark_page_accelerator =
140 chrome::GetPrimaryChromeAcceleratorForCommandId(IDC_BOOKMARK_PAGE);
141 if (bookmark_page_accelerator.key_code() == ui::VKEY_UNKNOWN)
144 extensions::CommandService* command_service =
145 extensions::CommandService::Get(profile);
146 const extensions::ExtensionSet& extension_set =
147 extensions::ExtensionRegistry::Get(profile)->enabled_extensions();
148 for (extensions::ExtensionSet::const_iterator i = extension_set.begin();
149 i != extension_set.end();
151 extensions::Command prospective_command;
152 extensions::CommandService::ExtensionCommandType prospective_command_type;
153 if (command_service->GetBoundExtensionCommand((*i)->id(),
154 bookmark_page_accelerator,
155 &prospective_command,
156 &prospective_command_type)) {
157 *extension = i->get();
158 *command = prospective_command;
159 *command_type = prospective_command_type;
167 void BookmarkCurrentPageInternal(Browser* browser) {
168 content::RecordAction(UserMetricsAction("Star"));
170 BookmarkModel* model =
171 BookmarkModelFactory::GetForProfile(browser->profile());
172 if (!model || !model->loaded())
173 return; // Ignore requests until bookmarks are loaded.
176 base::string16 title;
177 WebContents* web_contents =
178 browser->tab_strip_model()->GetActiveWebContents();
179 GetURLAndTitleToBookmark(web_contents, &url, &title);
180 bool is_bookmarked_by_any = model->IsBookmarked(url);
181 if (!is_bookmarked_by_any &&
182 web_contents->GetBrowserContext()->IsOffTheRecord()) {
183 // If we're incognito the favicon may not have been saved. Save it now
184 // so that bookmarks have an icon for the page.
185 FaviconTabHelper::FromWebContents(web_contents)->SaveFavicon();
187 bool was_bookmarked_by_user = bookmarks::IsBookmarkedByUser(model, url);
188 bookmarks::AddIfNotBookmarked(model, url, title);
189 bool is_bookmarked_by_user = bookmarks::IsBookmarkedByUser(model, url);
190 // Make sure the model actually added a bookmark before showing the star. A
191 // bookmark isn't created if the url is invalid.
192 if (browser->window()->IsActive() && is_bookmarked_by_user) {
193 // Only show the bubble if the window is active, otherwise we may get into
194 // weird situations where the bubble is deleted as soon as it is shown.
195 browser->window()->ShowBookmarkBubble(url, was_bookmarked_by_user);
199 // Based on |disposition|, creates a new tab as necessary, and returns the
200 // appropriate tab to navigate. If that tab is the current tab, reverts the
201 // location bar contents, since all browser-UI-triggered navigations should
202 // revert any omnibox edits in the current tab.
203 WebContents* GetTabAndRevertIfNecessary(Browser* browser,
204 WindowOpenDisposition disposition) {
205 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
206 switch (disposition) {
207 case NEW_FOREGROUND_TAB:
208 case NEW_BACKGROUND_TAB: {
209 WebContents* new_tab = current_tab->Clone();
210 browser->tab_strip_model()->AddWebContents(
211 new_tab, -1, content::PAGE_TRANSITION_LINK,
212 (disposition == NEW_FOREGROUND_TAB) ?
213 TabStripModel::ADD_ACTIVE : TabStripModel::ADD_NONE);
217 WebContents* new_tab = current_tab->Clone();
218 Browser* new_browser = new Browser(Browser::CreateParams(
219 browser->profile(), browser->host_desktop_type()));
220 new_browser->tab_strip_model()->AddWebContents(
221 new_tab, -1, content::PAGE_TRANSITION_LINK,
222 TabStripModel::ADD_ACTIVE);
223 new_browser->window()->Show();
227 browser->window()->GetLocationBar()->Revert();
232 void ReloadInternal(Browser* browser,
233 WindowOpenDisposition disposition,
235 // As this is caused by a user action, give the focus to the page.
237 // Also notify RenderViewHostDelegate of the user gesture; this is
238 // normally done in Browser::Navigate, but a reload bypasses Navigate.
239 WebContents* new_tab = GetTabAndRevertIfNecessary(browser, disposition);
240 new_tab->UserGestureDone();
241 if (!new_tab->FocusLocationBarByDefault())
244 new_tab->GetController().ReloadIgnoringCache(true);
246 new_tab->GetController().Reload(true);
249 bool IsShowingWebContentsModalDialog(const Browser* browser) {
250 WebContents* web_contents =
251 browser->tab_strip_model()->GetActiveWebContents();
255 WebContentsModalDialogManager* web_contents_modal_dialog_manager =
256 WebContentsModalDialogManager::FromWebContents(web_contents);
257 return web_contents_modal_dialog_manager->IsDialogActive();
260 bool PrintPreviewShowing(const Browser* browser) {
261 #if defined(ENABLE_FULL_PRINTING)
262 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
263 printing::PrintPreviewDialogController* controller =
264 printing::PrintPreviewDialogController::GetInstance();
265 return controller && (controller->GetPrintPreviewForContents(contents) ||
266 controller->is_creating_print_preview_dialog());
274 bool IsCommandEnabled(Browser* browser, int command) {
275 return browser->command_controller()->command_updater()->IsCommandEnabled(
279 bool SupportsCommand(Browser* browser, int command) {
280 return browser->command_controller()->command_updater()->SupportsCommand(
284 bool ExecuteCommand(Browser* browser, int command) {
285 return browser->command_controller()->command_updater()->ExecuteCommand(
289 bool ExecuteCommandWithDisposition(Browser* browser,
291 WindowOpenDisposition disposition) {
292 return browser->command_controller()->command_updater()->
293 ExecuteCommandWithDisposition(command, disposition);
296 void UpdateCommandEnabled(Browser* browser, int command, bool enabled) {
297 browser->command_controller()->command_updater()->UpdateCommandEnabled(
301 void AddCommandObserver(Browser* browser,
303 CommandObserver* observer) {
304 browser->command_controller()->command_updater()->AddCommandObserver(
308 void RemoveCommandObserver(Browser* browser,
310 CommandObserver* observer) {
311 browser->command_controller()->command_updater()->RemoveCommandObserver(
315 int GetContentRestrictions(const Browser* browser) {
316 int content_restrictions = 0;
317 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
319 CoreTabHelper* core_tab_helper =
320 CoreTabHelper::FromWebContents(current_tab);
321 content_restrictions = core_tab_helper->content_restrictions();
322 NavigationEntry* last_committed_entry =
323 current_tab->GetController().GetLastCommittedEntry();
324 if (!content::IsSavableURL(
325 last_committed_entry ? last_committed_entry->GetURL() : GURL()) ||
326 current_tab->ShowingInterstitialPage())
327 content_restrictions |= CONTENT_RESTRICTION_SAVE;
328 if (current_tab->ShowingInterstitialPage())
329 content_restrictions |= CONTENT_RESTRICTION_PRINT;
331 return content_restrictions;
334 void NewEmptyWindow(Profile* profile, HostDesktopType desktop_type) {
335 bool incognito = profile->IsOffTheRecord();
336 PrefService* prefs = profile->GetPrefs();
338 if (IncognitoModePrefs::GetAvailability(prefs) ==
339 IncognitoModePrefs::DISABLED) {
342 } else if (profile->IsGuestSession() ||
343 (browser_defaults::kAlwaysOpenIncognitoWindow &&
344 IncognitoModePrefs::ShouldLaunchIncognito(
345 *CommandLine::ForCurrentProcess(), prefs))) {
350 content::RecordAction(UserMetricsAction("NewIncognitoWindow"));
351 OpenEmptyWindow(profile->GetOffTheRecordProfile(), desktop_type);
353 content::RecordAction(UserMetricsAction("NewWindow"));
354 SessionService* session_service =
355 SessionServiceFactory::GetForProfileForSessionRestore(
356 profile->GetOriginalProfile());
357 if (!session_service ||
358 !session_service->RestoreIfNecessary(std::vector<GURL>())) {
359 OpenEmptyWindow(profile->GetOriginalProfile(), desktop_type);
364 Browser* OpenEmptyWindow(Profile* profile, HostDesktopType desktop_type) {
365 Browser* browser = new Browser(
366 Browser::CreateParams(Browser::TYPE_TABBED, profile, desktop_type));
367 AddTabAt(browser, GURL(), -1, true);
368 browser->window()->Show();
372 void OpenWindowWithRestoredTabs(Profile* profile,
373 HostDesktopType host_desktop_type) {
374 TabRestoreService* service = TabRestoreServiceFactory::GetForProfile(profile);
376 service->RestoreMostRecentEntry(NULL, host_desktop_type);
379 void OpenURLOffTheRecord(Profile* profile,
381 chrome::HostDesktopType desktop_type) {
382 ScopedTabbedBrowserDisplayer displayer(profile->GetOffTheRecordProfile(),
384 AddSelectedTabWithURL(displayer.browser(), url,
385 content::PAGE_TRANSITION_LINK);
388 bool CanGoBack(const Browser* browser) {
389 return browser->tab_strip_model()->GetActiveWebContents()->
390 GetController().CanGoBack();
393 void GoBack(Browser* browser, WindowOpenDisposition disposition) {
394 content::RecordAction(UserMetricsAction("Back"));
396 if (CanGoBack(browser)) {
397 WebContents* current_tab =
398 browser->tab_strip_model()->GetActiveWebContents();
399 WebContents* new_tab = GetTabAndRevertIfNecessary(browser, disposition);
400 // If we are on an interstitial page and clone the tab, it won't be copied
401 // to the new tab, so we don't need to go back.
402 if ((new_tab == current_tab) || !current_tab->ShowingInterstitialPage())
403 new_tab->GetController().GoBack();
407 bool CanGoForward(const Browser* browser) {
408 return browser->tab_strip_model()->GetActiveWebContents()->
409 GetController().CanGoForward();
412 void GoForward(Browser* browser, WindowOpenDisposition disposition) {
413 content::RecordAction(UserMetricsAction("Forward"));
414 if (CanGoForward(browser)) {
415 GetTabAndRevertIfNecessary(browser, disposition)->
416 GetController().GoForward();
420 bool NavigateToIndexWithDisposition(Browser* browser,
422 WindowOpenDisposition disposition) {
423 NavigationController* controller =
424 &GetTabAndRevertIfNecessary(browser, disposition)->GetController();
425 if (index < 0 || index >= controller->GetEntryCount())
427 controller->GoToIndex(index);
431 void Reload(Browser* browser, WindowOpenDisposition disposition) {
432 content::RecordAction(UserMetricsAction("Reload"));
433 ReloadInternal(browser, disposition, false);
436 void ReloadIgnoringCache(Browser* browser, WindowOpenDisposition disposition) {
437 content::RecordAction(UserMetricsAction("ReloadIgnoringCache"));
438 ReloadInternal(browser, disposition, true);
441 bool CanReload(const Browser* browser) {
442 return !browser->is_devtools();
445 void Home(Browser* browser, WindowOpenDisposition disposition) {
446 content::RecordAction(UserMetricsAction("Home"));
448 std::string extra_headers;
449 #if defined(ENABLE_RLZ) && !defined(OS_IOS)
450 // If the home page is a Google home page, add the RLZ header to the request.
451 PrefService* pref_service = browser->profile()->GetPrefs();
453 if (google_util::IsGoogleHomePageUrl(
454 GURL(pref_service->GetString(prefs::kHomePage)))) {
455 extra_headers = RLZTracker::GetAccessPointHttpHeader(
456 RLZTracker::ChromeHomePage());
459 #endif // defined(ENABLE_RLZ) && !defined(OS_IOS)
461 GURL url = browser->profile()->GetHomePage();
463 // Streamlined hosted apps should return to their launch page when the home
464 // button is pressed.
465 if (browser->is_app()) {
466 const extensions::Extension* extension =
467 extensions::ExtensionRegistry::Get(browser->profile())
469 web_app::GetExtensionIdFromApplicationName(browser->app_name()),
470 extensions::ExtensionRegistry::EVERYTHING);
474 url = extensions::AppLaunchInfo::GetLaunchWebURL(extension);
477 OpenURLParams params(
478 url, Referrer(), disposition,
479 content::PageTransitionFromInt(
480 content::PAGE_TRANSITION_AUTO_BOOKMARK |
481 content::PAGE_TRANSITION_HOME_PAGE),
483 params.extra_headers = extra_headers;
484 browser->OpenURL(params);
487 void OpenCurrentURL(Browser* browser) {
488 content::RecordAction(UserMetricsAction("LoadURL"));
489 LocationBar* location_bar = browser->window()->GetLocationBar();
493 GURL url(location_bar->GetDestinationURL());
495 content::PageTransition page_transition = location_bar->GetPageTransition();
496 content::PageTransition page_transition_without_qualifier(
497 PageTransitionStripQualifier(page_transition));
498 WindowOpenDisposition open_disposition =
499 location_bar->GetWindowOpenDisposition();
500 // A PAGE_TRANSITION_TYPED means the user has typed a URL. We do not want to
501 // open URLs with instant_controller since in some cases it disregards it
502 // and performs a search instead. For example, when using CTRL-Enter, the
503 // location_bar is aware of the URL but instant is not.
504 // Instant should also not handle PAGE_TRANSITION_RELOAD because its knowledge
505 // of the omnibox text may be stale if the user focuses in the omnibox and
506 // presses enter without typing anything.
507 if (page_transition_without_qualifier != content::PAGE_TRANSITION_TYPED &&
508 page_transition_without_qualifier != content::PAGE_TRANSITION_RELOAD &&
509 browser->instant_controller() &&
510 browser->instant_controller()->OpenInstant(open_disposition, url))
513 NavigateParams params(browser, url, page_transition);
514 params.disposition = open_disposition;
515 // Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least
516 // inherit the opener. In some cases the tabstrip will determine the group
517 // should be inherited, in which case the group is inherited instead of the
519 params.tabstrip_add_types =
520 TabStripModel::ADD_FORCE_INDEX | TabStripModel::ADD_INHERIT_OPENER;
523 DCHECK(extensions::ExtensionSystem::Get(
524 browser->profile())->extension_service());
525 const extensions::Extension* extension =
526 extensions::ExtensionRegistry::Get(browser->profile())
527 ->enabled_extensions().GetAppByURL(url);
529 CoreAppLauncherHandler::RecordAppLaunchType(
530 extension_misc::APP_LAUNCH_OMNIBOX_LOCATION,
531 extension->GetType());
535 void Stop(Browser* browser) {
536 content::RecordAction(UserMetricsAction("Stop"));
537 browser->tab_strip_model()->GetActiveWebContents()->Stop();
540 void NewWindow(Browser* browser) {
541 NewEmptyWindow(browser->profile()->GetOriginalProfile(),
542 browser->host_desktop_type());
545 void NewIncognitoWindow(Browser* browser) {
546 NewEmptyWindow(browser->profile()->GetOffTheRecordProfile(),
547 browser->host_desktop_type());
550 void CloseWindow(Browser* browser) {
551 content::RecordAction(UserMetricsAction("CloseWindow"));
552 browser->window()->Close();
555 void NewTab(Browser* browser) {
556 content::RecordAction(UserMetricsAction("NewTab"));
557 // TODO(asvitkine): This is invoked programmatically from several places.
558 // Audit the code and change it so that the histogram only gets collected for
559 // user-initiated commands.
560 UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", TabStripModel::NEW_TAB_COMMAND,
561 TabStripModel::NEW_TAB_ENUM_COUNT);
563 if (browser->is_type_tabbed()) {
564 AddTabAt(browser, GURL(), -1, true);
565 browser->tab_strip_model()->GetActiveWebContents()->RestoreFocus();
567 ScopedTabbedBrowserDisplayer displayer(browser->profile(),
568 browser->host_desktop_type());
569 Browser* b = displayer.browser();
570 AddTabAt(b, GURL(), -1, true);
572 // The call to AddBlankTabAt above did not set the focus to the tab as its
573 // window was not active, so we have to do it explicitly.
574 // See http://crbug.com/6380.
575 b->tab_strip_model()->GetActiveWebContents()->RestoreFocus();
579 void CloseTab(Browser* browser) {
580 content::RecordAction(UserMetricsAction("CloseTab_Accelerator"));
581 browser->tab_strip_model()->CloseSelectedTabs();
584 bool CanZoomIn(content::WebContents* contents) {
585 ZoomController* zoom_controller = ZoomController::FromWebContents(contents);
586 return zoom_controller->GetZoomPercent() !=
587 contents->GetMaximumZoomPercent() + 1;
590 bool CanZoomOut(content::WebContents* contents) {
591 ZoomController* zoom_controller = ZoomController::FromWebContents(contents);
592 return zoom_controller->GetZoomPercent() !=
593 contents->GetMinimumZoomPercent();
596 bool ActualSize(content::WebContents* contents) {
597 ZoomController* zoom_controller = ZoomController::FromWebContents(contents);
598 return zoom_controller->GetZoomPercent() != 100.0f;
601 TabStripModelDelegate::RestoreTabType GetRestoreTabType(
602 const Browser* browser) {
603 TabRestoreService* service =
604 TabRestoreServiceFactory::GetForProfile(browser->profile());
605 if (!service || service->entries().empty())
606 return TabStripModelDelegate::RESTORE_NONE;
607 if (service->entries().front()->type == TabRestoreService::WINDOW)
608 return TabStripModelDelegate::RESTORE_WINDOW;
609 return TabStripModelDelegate::RESTORE_TAB;
612 void SelectNextTab(Browser* browser) {
613 content::RecordAction(UserMetricsAction("SelectNextTab"));
614 browser->tab_strip_model()->SelectNextTab();
617 void SelectPreviousTab(Browser* browser) {
618 content::RecordAction(UserMetricsAction("SelectPrevTab"));
619 browser->tab_strip_model()->SelectPreviousTab();
622 void MoveTabNext(Browser* browser) {
623 content::RecordAction(UserMetricsAction("MoveTabNext"));
624 browser->tab_strip_model()->MoveTabNext();
627 void MoveTabPrevious(Browser* browser) {
628 content::RecordAction(UserMetricsAction("MoveTabPrevious"));
629 browser->tab_strip_model()->MoveTabPrevious();
632 void SelectNumberedTab(Browser* browser, int index) {
633 if (index < browser->tab_strip_model()->count()) {
634 content::RecordAction(UserMetricsAction("SelectNumberedTab"));
635 browser->tab_strip_model()->ActivateTabAt(index, true);
639 void SelectLastTab(Browser* browser) {
640 content::RecordAction(UserMetricsAction("SelectLastTab"));
641 browser->tab_strip_model()->SelectLastTab();
644 void DuplicateTab(Browser* browser) {
645 content::RecordAction(UserMetricsAction("Duplicate"));
646 DuplicateTabAt(browser, browser->tab_strip_model()->active_index());
649 bool CanDuplicateTab(const Browser* browser) {
650 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
651 return contents && contents->GetController().GetLastCommittedEntry();
654 WebContents* DuplicateTabAt(Browser* browser, int index) {
655 WebContents* contents = browser->tab_strip_model()->GetWebContentsAt(index);
657 WebContents* contents_dupe = contents->Clone();
660 if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) {
661 // If this is a tabbed browser, just create a duplicate tab inside the same
662 // window next to the tab being duplicated.
663 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents);
664 pinned = browser->tab_strip_model()->IsTabPinned(index);
665 int add_types = TabStripModel::ADD_ACTIVE |
666 TabStripModel::ADD_INHERIT_GROUP |
667 (pinned ? TabStripModel::ADD_PINNED : 0);
668 browser->tab_strip_model()->InsertWebContentsAt(
669 index + 1, contents_dupe, add_types);
671 Browser* new_browser = NULL;
672 if (browser->is_app() && !browser->is_type_popup()) {
673 new_browser = new Browser(
674 Browser::CreateParams::CreateForApp(browser->app_name(),
675 browser->is_trusted_source(),
678 browser->host_desktop_type()));
680 new_browser = new Browser(
681 Browser::CreateParams(browser->type(), browser->profile(),
682 browser->host_desktop_type()));
684 // Preserve the size of the original window. The new window has already
685 // been given an offset by the OS, so we shouldn't copy the old bounds.
686 BrowserWindow* new_window = new_browser->window();
687 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
688 browser->window()->GetRestoredBounds().size()));
690 // We need to show the browser now. Otherwise ContainerWin assumes the
691 // WebContents is invisible and won't size it.
692 new_browser->window()->Show();
694 // The page transition below is only for the purpose of inserting the tab.
695 new_browser->tab_strip_model()->AddWebContents(
697 content::PAGE_TRANSITION_LINK,
698 TabStripModel::ADD_ACTIVE);
701 SessionService* session_service =
702 SessionServiceFactory::GetForProfileIfExisting(browser->profile());
704 session_service->TabRestored(contents_dupe, pinned);
705 return contents_dupe;
708 bool CanDuplicateTabAt(Browser* browser, int index) {
709 content::NavigationController& nc =
710 browser->tab_strip_model()->GetWebContentsAt(index)->GetController();
711 return nc.GetWebContents() && nc.GetLastCommittedEntry();
714 void ConvertPopupToTabbedBrowser(Browser* browser) {
715 content::RecordAction(UserMetricsAction("ShowAsTab"));
716 TabStripModel* tab_strip = browser->tab_strip_model();
717 WebContents* contents =
718 tab_strip->DetachWebContentsAt(tab_strip->active_index());
719 Browser* b = new Browser(Browser::CreateParams(browser->profile(),
720 browser->host_desktop_type()));
721 b->tab_strip_model()->AppendWebContents(contents, true);
726 content::RecordAction(UserMetricsAction("Exit"));
727 chrome::AttemptUserExit();
730 void BookmarkCurrentPage(Browser* browser) {
731 DCHECK(!chrome::ShouldRemoveBookmarkThisPageUI(browser->profile()));
733 const extensions::Extension* extension = NULL;
734 extensions::Command command;
735 extensions::CommandService::ExtensionCommandType command_type;
736 if (GetBookmarkOverrideCommand(browser->profile(),
740 switch (command_type) {
741 case extensions::CommandService::NAMED:
742 browser->window()->ExecuteExtensionCommand(extension, command);
745 case extensions::CommandService::BROWSER_ACTION:
746 // BookmarkCurrentPage is called through a user gesture, so it is safe
747 // to call ShowBrowserActionPopup.
748 browser->window()->ShowBrowserActionPopup(extension);
751 case extensions::CommandService::PAGE_ACTION:
752 browser->window()->ShowPageActionPopup(extension);
757 BookmarkCurrentPageInternal(browser);
760 bool CanBookmarkCurrentPage(const Browser* browser) {
761 return CanBookmarkCurrentPageInternal(browser, true);
764 void BookmarkAllTabs(Browser* browser) {
765 chrome::ShowBookmarkAllTabsDialog(browser);
768 bool CanBookmarkAllTabs(const Browser* browser) {
769 return browser->tab_strip_model()->count() > 1 &&
770 !chrome::ShouldRemoveBookmarkOpenPagesUI(browser->profile()) &&
771 CanBookmarkCurrentPageInternal(browser, false);
774 void Translate(Browser* browser) {
775 if (!browser->window()->IsActive())
778 WebContents* web_contents =
779 browser->tab_strip_model()->GetActiveWebContents();
780 ChromeTranslateClient* chrome_translate_client =
781 ChromeTranslateClient::FromWebContents(web_contents);
783 translate::TranslateStep step = translate::TRANSLATE_STEP_BEFORE_TRANSLATE;
784 if (chrome_translate_client) {
785 if (chrome_translate_client->GetLanguageState().translation_pending())
786 step = translate::TRANSLATE_STEP_TRANSLATING;
787 else if (chrome_translate_client->GetLanguageState().IsPageTranslated())
788 step = translate::TRANSLATE_STEP_AFTER_TRANSLATE;
790 browser->window()->ShowTranslateBubble(
791 web_contents, step, translate::TranslateErrors::NONE, true);
794 void ManagePasswordsForPage(Browser* browser) {
795 // TODO(mkwst): Implement this feature on Mac: http://crbug.com/261628
796 #if !defined(OS_MACOSX)
797 if (!browser->window()->IsActive())
800 WebContents* web_contents =
801 browser->tab_strip_model()->GetActiveWebContents();
802 chrome::ShowManagePasswordsBubble(web_contents);
806 void TogglePagePinnedToStartScreen(Browser* browser) {
808 MetroPinTabHelper::FromWebContents(
809 browser->tab_strip_model()->GetActiveWebContents())->
810 TogglePinnedToStartScreen();
814 void SavePage(Browser* browser) {
815 content::RecordAction(UserMetricsAction("SavePage"));
816 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
817 if (current_tab && current_tab->GetContentsMimeType() == "application/pdf")
818 content::RecordAction(UserMetricsAction("PDF.SavePage"));
819 current_tab->OnSavePage();
822 bool CanSavePage(const Browser* browser) {
823 // LocalState can be NULL in tests.
824 if (g_browser_process->local_state() &&
825 !g_browser_process->local_state()->GetBoolean(
826 prefs::kAllowFileSelectionDialogs)) {
829 return !browser->is_devtools() &&
830 !(GetContentRestrictions(browser) & CONTENT_RESTRICTION_SAVE);
833 void ShowFindBar(Browser* browser) {
834 browser->GetFindBarController()->Show();
837 void ShowWebsiteSettings(Browser* browser,
838 content::WebContents* web_contents,
840 const SSLStatus& ssl) {
841 browser->window()->ShowWebsiteSettings(
842 Profile::FromBrowserContext(web_contents->GetBrowserContext()),
843 web_contents, url, ssl);
847 void Print(Browser* browser) {
848 #if defined(ENABLE_PRINTING)
849 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
850 #if defined(ENABLE_FULL_PRINTING)
851 printing::PrintViewManager* print_view_manager =
852 printing::PrintViewManager::FromWebContents(contents);
853 if (browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintPreviewDisabled))
854 print_view_manager->PrintNow();
856 print_view_manager->PrintPreviewNow(false);
858 printing::PrintViewManagerBasic* print_view_manager =
859 printing::PrintViewManagerBasic::FromWebContents(contents);
860 print_view_manager->PrintNow();
861 #endif // defined(ENABLE_FULL_PRINTING)
862 #endif // defined(ENABLE_PRINTING)
865 bool CanPrint(const Browser* browser) {
866 // Do not print when printing is disabled via pref or policy.
867 // Do not print when a constrained window is showing. It's confusing.
868 return browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) &&
869 !(IsShowingWebContentsModalDialog(browser) ||
870 GetContentRestrictions(browser) & CONTENT_RESTRICTION_PRINT);
873 void AdvancedPrint(Browser* browser) {
874 #if defined(ENABLE_FULL_PRINTING)
875 printing::PrintViewManager* print_view_manager =
876 printing::PrintViewManager::FromWebContents(
877 browser->tab_strip_model()->GetActiveWebContents());
878 print_view_manager->AdvancedPrintNow();
882 bool CanAdvancedPrint(const Browser* browser) {
883 // If printing is not disabled via pref or policy, it is always possible to
884 // advanced print when the print preview is visible. The exception to this
885 // is under Win8 ash, since showing the advanced print dialog will open it
886 // modally on the Desktop and hang the browser. We can remove this check
887 // once we integrate with the system print charm.
889 if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH)
893 return browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) &&
894 (PrintPreviewShowing(browser) || CanPrint(browser));
897 void PrintToDestination(Browser* browser) {
898 #if defined(ENABLE_FULL_PRINTING)
899 printing::PrintViewManager* print_view_manager =
900 printing::PrintViewManager::FromWebContents(
901 browser->tab_strip_model()->GetActiveWebContents());
902 print_view_manager->PrintToDestination();
906 void EmailPageLocation(Browser* browser) {
907 content::RecordAction(UserMetricsAction("EmailPageLocation"));
908 WebContents* wc = browser->tab_strip_model()->GetActiveWebContents();
911 std::string title = net::EscapeQueryParamValue(
912 base::UTF16ToUTF8(wc->GetTitle()), false);
913 std::string page_url = net::EscapeQueryParamValue(wc->GetURL().spec(), false);
914 std::string mailto = std::string("mailto:?subject=Fwd:%20") +
915 title + "&body=%0A%0A" + page_url;
916 platform_util::OpenExternal(browser->profile(), GURL(mailto));
919 bool CanEmailPageLocation(const Browser* browser) {
920 return browser->toolbar_model()->ShouldDisplayURL() &&
921 browser->tab_strip_model()->GetActiveWebContents()->GetURL().is_valid();
924 void Cut(Browser* browser) {
925 content::RecordAction(UserMetricsAction("Cut"));
926 browser->window()->Cut();
929 void Copy(Browser* browser) {
930 content::RecordAction(UserMetricsAction("Copy"));
931 browser->window()->Copy();
934 void Paste(Browser* browser) {
935 content::RecordAction(UserMetricsAction("Paste"));
936 browser->window()->Paste();
939 void Find(Browser* browser) {
940 content::RecordAction(UserMetricsAction("Find"));
941 FindInPage(browser, false, false);
944 void FindNext(Browser* browser) {
945 content::RecordAction(UserMetricsAction("FindNext"));
946 FindInPage(browser, true, true);
949 void FindPrevious(Browser* browser) {
950 content::RecordAction(UserMetricsAction("FindPrevious"));
951 FindInPage(browser, true, false);
954 void FindInPage(Browser* browser, bool find_next, bool forward_direction) {
955 ShowFindBar(browser);
957 base::string16 find_text;
958 FindTabHelper* find_helper = FindTabHelper::FromWebContents(
959 browser->tab_strip_model()->GetActiveWebContents());
960 #if defined(OS_MACOSX)
961 // We always want to search for the current contents of the find bar on
962 // OS X. For regular profile it's always the current find pboard. For
963 // Incognito window it's the newest value of the find pboard content and
965 FindBar* find_bar = browser->GetFindBarController()->find_bar();
966 find_text = find_bar->GetFindText();
968 find_helper->StartFinding(find_text, forward_direction, false);
972 void Zoom(Browser* browser, content::PageZoom zoom) {
973 chrome_page_zoom::Zoom(browser->tab_strip_model()->GetActiveWebContents(),
977 void FocusToolbar(Browser* browser) {
978 content::RecordAction(UserMetricsAction("FocusToolbar"));
979 browser->window()->FocusToolbar();
982 void FocusLocationBar(Browser* browser) {
983 content::RecordAction(UserMetricsAction("FocusLocation"));
984 browser->window()->SetFocusToLocationBar(true);
987 void FocusSearch(Browser* browser) {
988 // TODO(beng): replace this with FocusLocationBar
989 content::RecordAction(UserMetricsAction("FocusSearch"));
990 browser->window()->GetLocationBar()->FocusSearch();
993 void FocusAppMenu(Browser* browser) {
994 content::RecordAction(UserMetricsAction("FocusAppMenu"));
995 browser->window()->FocusAppMenu();
998 void FocusBookmarksToolbar(Browser* browser) {
999 content::RecordAction(UserMetricsAction("FocusBookmarksToolbar"));
1000 browser->window()->FocusBookmarksToolbar();
1003 void FocusInfobars(Browser* browser) {
1004 content::RecordAction(UserMetricsAction("FocusInfobars"));
1005 browser->window()->FocusInfobars();
1008 void FocusNextPane(Browser* browser) {
1009 content::RecordAction(UserMetricsAction("FocusNextPane"));
1010 browser->window()->RotatePaneFocus(true);
1013 void FocusPreviousPane(Browser* browser) {
1014 content::RecordAction(UserMetricsAction("FocusPreviousPane"));
1015 browser->window()->RotatePaneFocus(false);
1018 void ToggleDevToolsWindow(Browser* browser, DevToolsToggleAction action) {
1019 if (action.type() == DevToolsToggleAction::kShowConsole)
1020 content::RecordAction(UserMetricsAction("DevTools_ToggleConsole"));
1022 content::RecordAction(UserMetricsAction("DevTools_ToggleWindow"));
1023 DevToolsWindow::ToggleDevToolsWindow(browser, action);
1026 bool CanOpenTaskManager() {
1027 #if defined(ENABLE_TASK_MANAGER)
1034 void OpenTaskManager(Browser* browser) {
1035 #if defined(ENABLE_TASK_MANAGER)
1036 content::RecordAction(UserMetricsAction("TaskManager"));
1037 chrome::ShowTaskManager(browser);
1043 void OpenFeedbackDialog(Browser* browser) {
1044 content::RecordAction(UserMetricsAction("Feedback"));
1045 chrome::ShowFeedbackPage(browser, std::string(), std::string());
1048 void ToggleBookmarkBar(Browser* browser) {
1049 content::RecordAction(UserMetricsAction("ShowBookmarksBar"));
1050 ToggleBookmarkBarWhenVisible(browser->profile());
1053 void ShowAppMenu(Browser* browser) {
1054 // We record the user metric for this event in WrenchMenu::RunMenu.
1055 browser->window()->ShowAppMenu();
1058 void ShowAvatarMenu(Browser* browser) {
1059 browser->window()->ShowAvatarBubbleFromAvatarButton(
1060 BrowserWindow::AVATAR_BUBBLE_MODE_DEFAULT,
1061 signin::ManageAccountsParams());
1064 void OpenUpdateChromeDialog(Browser* browser) {
1065 if (UpgradeDetector::GetInstance()->is_outdated_install()) {
1066 content::NotificationService::current()->Notify(
1067 chrome::NOTIFICATION_OUTDATED_INSTALL,
1068 content::NotificationService::AllSources(),
1069 content::NotificationService::NoDetails());
1070 } else if (UpgradeDetector::GetInstance()->is_outdated_install_no_au()) {
1071 content::NotificationService::current()->Notify(
1072 chrome::NOTIFICATION_OUTDATED_INSTALL_NO_AU,
1073 content::NotificationService::AllSources(),
1074 content::NotificationService::NoDetails());
1076 content::RecordAction(UserMetricsAction("UpdateChrome"));
1077 browser->window()->ShowUpdateChromeDialog();
1081 void ToggleSpeechInput(Browser* browser) {
1082 SearchTabHelper* search_tab_helper =
1083 SearchTabHelper::FromWebContents(
1084 browser->tab_strip_model()->GetActiveWebContents());
1085 // |search_tab_helper| can be null in unit tests.
1086 if (search_tab_helper)
1087 search_tab_helper->ToggleVoiceSearch();
1090 void DistillCurrentPage(Browser* browser) {
1091 DistillCurrentPageAndView(browser->tab_strip_model()->GetActiveWebContents());
1094 bool CanRequestTabletSite(WebContents* current_tab) {
1095 return current_tab &&
1096 current_tab->GetController().GetLastCommittedEntry() != NULL;
1099 bool IsRequestingTabletSite(Browser* browser) {
1100 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
1103 content::NavigationEntry* entry =
1104 current_tab->GetController().GetLastCommittedEntry();
1107 return entry->GetIsOverridingUserAgent();
1110 void ToggleRequestTabletSite(Browser* browser) {
1111 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
1114 NavigationController& controller = current_tab->GetController();
1115 NavigationEntry* entry = controller.GetLastCommittedEntry();
1118 if (entry->GetIsOverridingUserAgent()) {
1119 entry->SetIsOverridingUserAgent(false);
1121 entry->SetIsOverridingUserAgent(true);
1122 chrome::VersionInfo version_info;
1123 std::string product;
1124 if (version_info.is_valid())
1125 product = version_info.ProductNameAndVersionForUserAgent();
1126 current_tab->SetUserAgentOverride(content::BuildUserAgentFromOSAndProduct(
1127 kOsOverrideForTabletSite, product));
1129 controller.ReloadOriginalRequestURL(true);
1132 void ToggleFullscreenMode(Browser* browser) {
1134 browser->fullscreen_controller()->ToggleBrowserFullscreenMode();
1137 void ClearCache(Browser* browser) {
1138 BrowsingDataRemover* remover =
1139 BrowsingDataRemover::CreateForUnboundedRange(browser->profile());
1140 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
1141 BrowsingDataHelper::UNPROTECTED_WEB);
1142 // BrowsingDataRemover takes care of deleting itself when done.
1145 bool IsDebuggerAttachedToCurrentTab(Browser* browser) {
1146 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
1148 content::DevToolsAgentHost::IsDebuggerAttached(contents) : false;
1151 void ViewSource(Browser* browser, WebContents* contents) {
1154 // Use the last committed entry, since the pending entry hasn't loaded yet and
1155 // won't be copied into the cloned tab.
1156 NavigationEntry* entry = contents->GetController().GetLastCommittedEntry();
1160 ViewSource(browser, contents, entry->GetURL(), entry->GetPageState());
1163 void ViewSource(Browser* browser,
1164 WebContents* contents,
1166 const content::PageState& page_state) {
1167 content::RecordAction(UserMetricsAction("ViewSource"));
1170 WebContents* view_source_contents = contents->Clone();
1171 DCHECK(view_source_contents->GetController().CanPruneAllButLastCommitted());
1172 view_source_contents->GetController().PruneAllButLastCommitted();
1173 NavigationEntry* last_committed_entry =
1174 view_source_contents->GetController().GetLastCommittedEntry();
1175 if (!last_committed_entry)
1178 GURL view_source_url =
1179 GURL(content::kViewSourceScheme + std::string(":") + url.spec());
1180 last_committed_entry->SetVirtualURL(view_source_url);
1182 // Do not restore scroller position.
1183 last_committed_entry->SetPageState(page_state.RemoveScrollOffset());
1185 // Do not restore title, derive it from the url.
1186 last_committed_entry->SetTitle(base::string16());
1188 // Now show view-source entry.
1189 if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) {
1190 // If this is a tabbed browser, just create a duplicate tab inside the same
1191 // window next to the tab being duplicated.
1192 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents);
1193 int add_types = TabStripModel::ADD_ACTIVE |
1194 TabStripModel::ADD_INHERIT_GROUP;
1195 browser->tab_strip_model()->InsertWebContentsAt(
1197 view_source_contents,
1200 Browser* b = new Browser(
1201 Browser::CreateParams(Browser::TYPE_TABBED, browser->profile(),
1202 browser->host_desktop_type()));
1204 // Preserve the size of the original window. The new window has already
1205 // been given an offset by the OS, so we shouldn't copy the old bounds.
1206 BrowserWindow* new_window = b->window();
1207 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
1208 browser->window()->GetRestoredBounds().size()));
1210 // We need to show the browser now. Otherwise ContainerWin assumes the
1211 // WebContents is invisible and won't size it.
1212 b->window()->Show();
1214 // The page transition below is only for the purpose of inserting the tab.
1215 b->tab_strip_model()->AddWebContents(view_source_contents, -1,
1216 content::PAGE_TRANSITION_LINK,
1217 TabStripModel::ADD_ACTIVE);
1220 SessionService* session_service =
1221 SessionServiceFactory::GetForProfileIfExisting(browser->profile());
1222 if (session_service)
1223 session_service->TabRestored(view_source_contents, false);
1226 void ViewSelectedSource(Browser* browser) {
1227 ViewSource(browser, browser->tab_strip_model()->GetActiveWebContents());
1230 bool CanViewSource(const Browser* browser) {
1231 return !browser->is_devtools() &&
1232 browser->tab_strip_model()->GetActiveWebContents()->GetController().
1236 void CreateApplicationShortcuts(Browser* browser) {
1237 content::RecordAction(UserMetricsAction("CreateShortcut"));
1238 extensions::TabHelper::FromWebContents(
1239 browser->tab_strip_model()->GetActiveWebContents())->
1240 CreateApplicationShortcuts();
1243 void CreateBookmarkAppFromCurrentWebContents(Browser* browser) {
1244 content::RecordAction(UserMetricsAction("CreateHostedApp"));
1245 extensions::TabHelper::FromWebContents(
1246 browser->tab_strip_model()->GetActiveWebContents())->
1247 CreateHostedAppFromWebContents();
1250 bool CanCreateApplicationShortcuts(const Browser* browser) {
1251 return extensions::TabHelper::FromWebContents(
1252 browser->tab_strip_model()->GetActiveWebContents())->
1253 CanCreateApplicationShortcuts();
1256 bool CanCreateBookmarkApp(const Browser* browser) {
1257 return extensions::TabHelper::FromWebContents(
1258 browser->tab_strip_model()->GetActiveWebContents())
1259 ->CanCreateBookmarkApp();
1262 void ConvertTabToAppWindow(Browser* browser,
1263 content::WebContents* contents) {
1264 const GURL& url = contents->GetController().GetLastCommittedEntry()->GetURL();
1265 std::string app_name = web_app::GenerateApplicationNameFromURL(url);
1267 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents);
1269 browser->tab_strip_model()->DetachWebContentsAt(index);
1271 Browser* app_browser = new Browser(
1272 Browser::CreateParams::CreateForApp(app_name,
1273 true /* trusted_source */,
1276 browser->host_desktop_type()));
1277 app_browser->tab_strip_model()->AppendWebContents(contents, true);
1279 contents->GetMutableRendererPrefs()->can_accept_load_drops = false;
1280 contents->GetRenderViewHost()->SyncRendererPrefs();
1281 app_browser->window()->Show();
1284 } // namespace chrome