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/browser/bookmarks/bookmark_model.h"
12 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
13 #include "chrome/browser/bookmarks/bookmark_utils.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/browsing_data/browsing_data_helper.h"
16 #include "chrome/browser/browsing_data/browsing_data_remover.h"
17 #include "chrome/browser/chrome_notification_types.h"
18 #include "chrome/browser/chrome_page_zoom.h"
19 #include "chrome/browser/devtools/devtools_window.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/tab_helper.h"
22 #include "chrome/browser/favicon/favicon_tab_helper.h"
23 #include "chrome/browser/google/google_util.h"
24 #include "chrome/browser/lifetime/application_lifetime.h"
25 #include "chrome/browser/platform_util.h"
26 #include "chrome/browser/prefs/incognito_mode_prefs.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/rlz/rlz.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/translate/translate_tab_helper.h"
34 #include "chrome/browser/ui/bookmarks/bookmark_prompt_controller.h"
35 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
36 #include "chrome/browser/ui/browser.h"
37 #include "chrome/browser/ui/browser_command_controller.h"
38 #include "chrome/browser/ui/browser_dialogs.h"
39 #include "chrome/browser/ui/browser_instant_controller.h"
40 #include "chrome/browser/ui/browser_tab_restore_service_delegate.h"
41 #include "chrome/browser/ui/browser_tabstrip.h"
42 #include "chrome/browser/ui/browser_window.h"
43 #include "chrome/browser/ui/chrome_pages.h"
44 #include "chrome/browser/ui/find_bar/find_bar.h"
45 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
46 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
47 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
48 #include "chrome/browser/ui/omnibox/location_bar.h"
49 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
50 #include "chrome/browser/ui/status_bubble.h"
51 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
52 #include "chrome/browser/ui/tabs/tab_strip_model.h"
53 #include "chrome/browser/ui/translate/translate_bubble_model.h"
54 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
55 #include "chrome/browser/upgrade_detector.h"
56 #include "chrome/browser/web_applications/web_app.h"
57 #include "chrome/common/chrome_switches.h"
58 #include "chrome/common/chrome_version_info.h"
59 #include "chrome/common/content_restriction.h"
60 #include "chrome/common/pref_names.h"
61 #include "components/web_modal/web_contents_modal_dialog_manager.h"
62 #include "content/public/browser/devtools_agent_host.h"
63 #include "content/public/browser/navigation_controller.h"
64 #include "content/public/browser/navigation_entry.h"
65 #include "content/public/browser/notification_service.h"
66 #include "content/public/browser/page_navigator.h"
67 #include "content/public/browser/render_view_host.h"
68 #include "content/public/browser/user_metrics.h"
69 #include "content/public/browser/web_contents.h"
70 #include "content/public/browser/web_contents_view.h"
71 #include "content/public/common/renderer_preferences.h"
72 #include "content/public/common/url_constants.h"
73 #include "content/public/common/url_utils.h"
74 #include "net/base/escape.h"
75 #include "webkit/common/user_agent/user_agent_util.h"
78 #include "chrome/browser/ui/metro_pin_tab_helper_win.h"
79 #include "win8/util/win8_util.h"
82 #if defined(ENABLE_PRINTING)
83 #if defined(ENABLE_FULL_PRINTING)
84 #include "chrome/browser/printing/print_preview_dialog_controller.h"
85 #include "chrome/browser/printing/print_view_manager.h"
87 #include "chrome/browser/printing/print_view_manager_basic.h"
88 #endif // defined(ENABLE_FULL_PRINTING)
89 #endif // defined(ENABLE_PRINTING)
92 const char kOsOverrideForTabletSite[] = "Linux; Android 4.0.3";
95 using content::NavigationController;
96 using content::NavigationEntry;
97 using content::OpenURLParams;
98 using content::Referrer;
99 using content::SSLStatus;
100 using content::UserMetricsAction;
101 using content::WebContents;
102 using web_modal::WebContentsModalDialogManager;
107 void BookmarkCurrentPageInternal(Browser* browser, bool from_star) {
108 content::RecordAction(UserMetricsAction("Star"));
110 BookmarkModel* model =
111 BookmarkModelFactory::GetForProfile(browser->profile());
112 if (!model || !model->loaded())
113 return; // Ignore requests until bookmarks are loaded.
117 WebContents* web_contents =
118 browser->tab_strip_model()->GetActiveWebContents();
119 GetURLAndTitleToBookmark(web_contents, &url, &title);
120 bool was_bookmarked = model->IsBookmarked(url);
121 if (!was_bookmarked && web_contents->GetBrowserContext()->IsOffTheRecord()) {
122 // If we're incognito the favicon may not have been saved. Save it now
123 // so that bookmarks have an icon for the page.
124 FaviconTabHelper::FromWebContents(web_contents)->SaveFavicon();
126 bookmark_utils::AddIfNotBookmarked(model, url, title);
127 if (from_star && !was_bookmarked)
128 BookmarkPromptController::AddedBookmark(browser, url);
129 // Make sure the model actually added a bookmark before showing the star. A
130 // bookmark isn't created if the url is invalid.
131 if (browser->window()->IsActive() && model->IsBookmarked(url)) {
132 // Only show the bubble if the window is active, otherwise we may get into
133 // weird situations where the bubble is deleted as soon as it is shown.
134 browser->window()->ShowBookmarkBubble(url, was_bookmarked);
138 WebContents* GetOrCloneTabForDisposition(Browser* browser,
139 WindowOpenDisposition disposition) {
140 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
141 switch (disposition) {
142 case NEW_FOREGROUND_TAB:
143 case NEW_BACKGROUND_TAB: {
144 current_tab = current_tab->Clone();
145 browser->tab_strip_model()->AddWebContents(
146 current_tab, -1, content::PAGE_TRANSITION_LINK,
147 disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_ACTIVE :
148 TabStripModel::ADD_NONE);
152 current_tab = current_tab->Clone();
153 Browser* b = new Browser(Browser::CreateParams(
154 browser->profile(), browser->host_desktop_type()));
155 b->tab_strip_model()->AddWebContents(
156 current_tab, -1, content::PAGE_TRANSITION_LINK,
157 TabStripModel::ADD_ACTIVE);
167 void ReloadInternal(Browser* browser,
168 WindowOpenDisposition disposition,
170 // As this is caused by a user action, give the focus to the page.
172 // Also notify RenderViewHostDelegate of the user gesture; this is
173 // normally done in Browser::Navigate, but a reload bypasses Navigate.
174 WebContents* web_contents = GetOrCloneTabForDisposition(browser, disposition);
175 web_contents->UserGestureDone();
176 if (!web_contents->FocusLocationBarByDefault())
177 web_contents->GetView()->Focus();
179 web_contents->GetController().ReloadIgnoringCache(true);
181 web_contents->GetController().Reload(true);
184 bool IsShowingWebContentsModalDialog(const Browser* browser) {
185 WebContents* web_contents =
186 browser->tab_strip_model()->GetActiveWebContents();
190 WebContentsModalDialogManager* web_contents_modal_dialog_manager =
191 WebContentsModalDialogManager::FromWebContents(web_contents);
192 return web_contents_modal_dialog_manager->IsDialogActive();
195 bool PrintPreviewShowing(const Browser* browser) {
196 #if defined(ENABLE_FULL_PRINTING)
197 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
198 printing::PrintPreviewDialogController* controller =
199 printing::PrintPreviewDialogController::GetInstance();
200 return controller && (controller->GetPrintPreviewForContents(contents) ||
201 controller->is_creating_print_preview_dialog());
209 bool IsCommandEnabled(Browser* browser, int command) {
210 return browser->command_controller()->command_updater()->IsCommandEnabled(
214 bool SupportsCommand(Browser* browser, int command) {
215 return browser->command_controller()->command_updater()->SupportsCommand(
219 bool ExecuteCommand(Browser* browser, int command) {
220 return browser->command_controller()->command_updater()->ExecuteCommand(
224 bool ExecuteCommandWithDisposition(Browser* browser,
226 WindowOpenDisposition disposition) {
227 return browser->command_controller()->command_updater()->
228 ExecuteCommandWithDisposition(command, disposition);
231 void UpdateCommandEnabled(Browser* browser, int command, bool enabled) {
232 browser->command_controller()->command_updater()->UpdateCommandEnabled(
236 void AddCommandObserver(Browser* browser,
238 CommandObserver* observer) {
239 browser->command_controller()->command_updater()->AddCommandObserver(
243 void RemoveCommandObserver(Browser* browser,
245 CommandObserver* observer) {
246 browser->command_controller()->command_updater()->RemoveCommandObserver(
250 int GetContentRestrictions(const Browser* browser) {
251 int content_restrictions = 0;
252 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
254 CoreTabHelper* core_tab_helper =
255 CoreTabHelper::FromWebContents(current_tab);
256 content_restrictions = core_tab_helper->content_restrictions();
257 NavigationEntry* active_entry =
258 current_tab->GetController().GetActiveEntry();
259 // See comment in UpdateCommandsForTabState about why we call url().
260 if (!content::IsSavableURL(
261 active_entry ? active_entry->GetURL() : GURL()) ||
262 current_tab->ShowingInterstitialPage())
263 content_restrictions |= CONTENT_RESTRICTION_SAVE;
264 if (current_tab->ShowingInterstitialPage())
265 content_restrictions |= CONTENT_RESTRICTION_PRINT;
267 return content_restrictions;
270 void NewEmptyWindow(Profile* profile, HostDesktopType desktop_type) {
271 bool incognito = profile->IsOffTheRecord();
272 PrefService* prefs = profile->GetPrefs();
274 if (IncognitoModePrefs::GetAvailability(prefs) ==
275 IncognitoModePrefs::DISABLED) {
279 if (browser_defaults::kAlwaysOpenIncognitoWindow &&
280 IncognitoModePrefs::ShouldLaunchIncognito(
281 *CommandLine::ForCurrentProcess(), prefs)) {
287 content::RecordAction(UserMetricsAction("NewIncognitoWindow"));
288 OpenEmptyWindow(profile->GetOffTheRecordProfile(), desktop_type);
290 content::RecordAction(UserMetricsAction("NewWindow"));
291 SessionService* session_service =
292 SessionServiceFactory::GetForProfileForSessionRestore(
293 profile->GetOriginalProfile());
294 if (!session_service ||
295 !session_service->RestoreIfNecessary(std::vector<GURL>())) {
296 OpenEmptyWindow(profile->GetOriginalProfile(), desktop_type);
301 Browser* OpenEmptyWindow(Profile* profile, HostDesktopType desktop_type) {
302 Browser* browser = new Browser(
303 Browser::CreateParams(Browser::TYPE_TABBED, profile, desktop_type));
304 AddBlankTabAt(browser, -1, true);
305 browser->window()->Show();
309 void OpenWindowWithRestoredTabs(Profile* profile,
310 HostDesktopType host_desktop_type) {
311 TabRestoreService* service = TabRestoreServiceFactory::GetForProfile(profile);
313 service->RestoreMostRecentEntry(NULL, host_desktop_type);
316 void OpenURLOffTheRecord(Profile* profile,
318 chrome::HostDesktopType desktop_type) {
319 ScopedTabbedBrowserDisplayer displayer(profile->GetOffTheRecordProfile(),
321 AddSelectedTabWithURL(displayer.browser(), url,
322 content::PAGE_TRANSITION_LINK);
325 bool CanGoBack(const Browser* browser) {
326 return browser->tab_strip_model()->GetActiveWebContents()->
327 GetController().CanGoBack();
330 void GoBack(Browser* browser, WindowOpenDisposition disposition) {
331 content::RecordAction(UserMetricsAction("Back"));
333 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
334 if (CanGoBack(browser)) {
335 WebContents* new_tab = GetOrCloneTabForDisposition(browser, disposition);
336 // If we are on an interstitial page and clone the tab, it won't be copied
337 // to the new tab, so we don't need to go back.
338 if (current_tab->ShowingInterstitialPage() && new_tab != current_tab)
340 new_tab->GetController().GoBack();
344 bool CanGoForward(const Browser* browser) {
345 return browser->tab_strip_model()->GetActiveWebContents()->
346 GetController().CanGoForward();
349 void GoForward(Browser* browser, WindowOpenDisposition disposition) {
350 content::RecordAction(UserMetricsAction("Forward"));
351 if (CanGoForward(browser)) {
352 GetOrCloneTabForDisposition(browser, disposition)->
353 GetController().GoForward();
357 bool NavigateToIndexWithDisposition(Browser* browser,
359 WindowOpenDisposition disp) {
360 NavigationController& controller =
361 GetOrCloneTabForDisposition(browser, disp)->GetController();
362 if (index < 0 || index >= controller.GetEntryCount())
364 controller.GoToIndex(index);
368 void Reload(Browser* browser, WindowOpenDisposition disposition) {
369 content::RecordAction(UserMetricsAction("Reload"));
370 ReloadInternal(browser, disposition, false);
373 void ReloadIgnoringCache(Browser* browser, WindowOpenDisposition disposition) {
374 content::RecordAction(UserMetricsAction("ReloadIgnoringCache"));
375 ReloadInternal(browser, disposition, true);
378 bool CanReload(const Browser* browser) {
379 return !browser->is_devtools();
382 void Home(Browser* browser, WindowOpenDisposition disposition) {
383 content::RecordAction(UserMetricsAction("Home"));
385 std::string extra_headers;
386 #if defined(ENABLE_RLZ)
387 // If the home page is a Google home page, add the RLZ header to the request.
388 PrefService* pref_service = browser->profile()->GetPrefs();
390 if (google_util::IsGoogleHomePageUrl(
391 GURL(pref_service->GetString(prefs::kHomePage)))) {
392 extra_headers = RLZTracker::GetAccessPointHttpHeader(
393 RLZTracker::CHROME_HOME_PAGE);
398 OpenURLParams params(
399 browser->profile()->GetHomePage(), Referrer(), disposition,
400 content::PageTransitionFromInt(
401 content::PAGE_TRANSITION_AUTO_BOOKMARK |
402 content::PAGE_TRANSITION_HOME_PAGE),
404 params.extra_headers = extra_headers;
405 browser->OpenURL(params);
408 void OpenCurrentURL(Browser* browser) {
409 content::RecordAction(UserMetricsAction("LoadURL"));
410 LocationBar* location_bar = browser->window()->GetLocationBar();
414 GURL url(location_bar->GetDestinationURL());
416 content::PageTransition page_transition = location_bar->GetPageTransition();
417 content::PageTransition page_transition_without_qualifier(
418 PageTransitionStripQualifier(page_transition));
419 WindowOpenDisposition open_disposition =
420 location_bar->GetWindowOpenDisposition();
421 // A PAGE_TRANSITION_TYPED means the user has typed a URL. We do not want to
422 // open URLs with instant_controller since in some cases it disregards it
423 // and performs a search instead. For example, when using CTRL-Enter, the
424 // location_bar is aware of the URL but instant is not.
425 // Instant should also not handle PAGE_TRANSITION_RELOAD because its knowledge
426 // of the omnibox text may be stale if the user focuses in the omnibox and
427 // presses enter without typing anything.
428 if (page_transition_without_qualifier != content::PAGE_TRANSITION_TYPED &&
429 page_transition_without_qualifier != content::PAGE_TRANSITION_RELOAD &&
430 browser->instant_controller() &&
431 browser->instant_controller()->OpenInstant(open_disposition, url))
434 NavigateParams params(browser, url, page_transition);
435 params.disposition = open_disposition;
436 // Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least
437 // inherit the opener. In some cases the tabstrip will determine the group
438 // should be inherited, in which case the group is inherited instead of the
440 params.tabstrip_add_types =
441 TabStripModel::ADD_FORCE_INDEX | TabStripModel::ADD_INHERIT_OPENER;
444 DCHECK(browser->profile()->GetExtensionService());
445 const extensions::Extension* extension =
446 browser->profile()->GetExtensionService()->GetInstalledApp(url);
448 CoreAppLauncherHandler::RecordAppLaunchType(
449 extension_misc::APP_LAUNCH_OMNIBOX_LOCATION,
450 extension->GetType());
454 void Stop(Browser* browser) {
455 content::RecordAction(UserMetricsAction("Stop"));
456 browser->tab_strip_model()->GetActiveWebContents()->Stop();
460 void NewWindow(Browser* browser) {
461 NewEmptyWindow(browser->profile()->GetOriginalProfile(),
462 browser->host_desktop_type());
465 void NewIncognitoWindow(Browser* browser) {
466 NewEmptyWindow(browser->profile()->GetOffTheRecordProfile(),
467 browser->host_desktop_type());
471 void CloseWindow(Browser* browser) {
472 content::RecordAction(UserMetricsAction("CloseWindow"));
473 browser->window()->Close();
476 void NewTab(Browser* browser) {
477 content::RecordAction(UserMetricsAction("NewTab"));
478 // TODO(asvitkine): This is invoked programmatically from several places.
479 // Audit the code and change it so that the histogram only gets collected for
480 // user-initiated commands.
481 UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", TabStripModel::NEW_TAB_COMMAND,
482 TabStripModel::NEW_TAB_ENUM_COUNT);
484 if (browser->is_type_tabbed()) {
485 AddBlankTabAt(browser, -1, true);
486 browser->tab_strip_model()->GetActiveWebContents()->GetView()->
489 ScopedTabbedBrowserDisplayer displayer(browser->profile(),
490 browser->host_desktop_type());
491 Browser* b = displayer.browser();
492 AddBlankTabAt(b, -1, true);
494 // The call to AddBlankTabAt above did not set the focus to the tab as its
495 // window was not active, so we have to do it explicitly.
496 // See http://crbug.com/6380.
497 b->tab_strip_model()->GetActiveWebContents()->GetView()->RestoreFocus();
501 void CloseTab(Browser* browser) {
502 content::RecordAction(UserMetricsAction("CloseTab_Accelerator"));
503 browser->tab_strip_model()->CloseSelectedTabs();
506 void RestoreTab(Browser* browser) {
507 content::RecordAction(UserMetricsAction("RestoreTab"));
508 TabRestoreService* service =
509 TabRestoreServiceFactory::GetForProfile(browser->profile());
511 service->RestoreMostRecentEntry(browser->tab_restore_service_delegate(),
512 browser->host_desktop_type());
515 TabStripModelDelegate::RestoreTabType GetRestoreTabType(
516 const Browser* browser) {
517 TabRestoreService* service =
518 TabRestoreServiceFactory::GetForProfile(browser->profile());
519 if (!service || service->entries().empty())
520 return TabStripModelDelegate::RESTORE_NONE;
521 if (service->entries().front()->type == TabRestoreService::WINDOW)
522 return TabStripModelDelegate::RESTORE_WINDOW;
523 return TabStripModelDelegate::RESTORE_TAB;
526 void SelectNextTab(Browser* browser) {
527 content::RecordAction(UserMetricsAction("SelectNextTab"));
528 browser->tab_strip_model()->SelectNextTab();
531 void SelectPreviousTab(Browser* browser) {
532 content::RecordAction(UserMetricsAction("SelectPrevTab"));
533 browser->tab_strip_model()->SelectPreviousTab();
536 void OpenTabpose(Browser* browser) {
537 #if defined(OS_MACOSX)
538 if (!CommandLine::ForCurrentProcess()->HasSwitch(
539 switches::kEnableExposeForTabs)) {
543 content::RecordAction(UserMetricsAction("OpenTabpose"));
544 browser->window()->OpenTabpose();
550 void MoveTabNext(Browser* browser) {
551 content::RecordAction(UserMetricsAction("MoveTabNext"));
552 browser->tab_strip_model()->MoveTabNext();
555 void MoveTabPrevious(Browser* browser) {
556 content::RecordAction(UserMetricsAction("MoveTabPrevious"));
557 browser->tab_strip_model()->MoveTabPrevious();
560 void SelectNumberedTab(Browser* browser, int index) {
561 if (index < browser->tab_strip_model()->count()) {
562 content::RecordAction(UserMetricsAction("SelectNumberedTab"));
563 browser->tab_strip_model()->ActivateTabAt(index, true);
567 void SelectLastTab(Browser* browser) {
568 content::RecordAction(UserMetricsAction("SelectLastTab"));
569 browser->tab_strip_model()->SelectLastTab();
572 void DuplicateTab(Browser* browser) {
573 content::RecordAction(UserMetricsAction("Duplicate"));
574 DuplicateTabAt(browser, browser->tab_strip_model()->active_index());
577 bool CanDuplicateTab(const Browser* browser) {
578 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
579 return contents && contents->GetController().GetLastCommittedEntry();
582 WebContents* DuplicateTabAt(Browser* browser, int index) {
583 WebContents* contents = browser->tab_strip_model()->GetWebContentsAt(index);
585 WebContents* contents_dupe = contents->Clone();
588 if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) {
589 // If this is a tabbed browser, just create a duplicate tab inside the same
590 // window next to the tab being duplicated.
591 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents);
592 pinned = browser->tab_strip_model()->IsTabPinned(index);
593 int add_types = TabStripModel::ADD_ACTIVE |
594 TabStripModel::ADD_INHERIT_GROUP |
595 (pinned ? TabStripModel::ADD_PINNED : 0);
596 browser->tab_strip_model()->InsertWebContentsAt(
597 index + 1, contents_dupe, add_types);
599 Browser* new_browser = NULL;
600 if (browser->is_app() &&
601 !browser->is_type_popup()) {
602 new_browser = new Browser(
603 Browser::CreateParams::CreateForApp(browser->type(),
607 browser->host_desktop_type()));
609 new_browser = new Browser(
610 Browser::CreateParams(browser->type(), browser->profile(),
611 browser->host_desktop_type()));
613 // Preserve the size of the original window. The new window has already
614 // been given an offset by the OS, so we shouldn't copy the old bounds.
615 BrowserWindow* new_window = new_browser->window();
616 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
617 browser->window()->GetRestoredBounds().size()));
619 // We need to show the browser now. Otherwise ContainerWin assumes the
620 // WebContents is invisible and won't size it.
621 new_browser->window()->Show();
623 // The page transition below is only for the purpose of inserting the tab.
624 new_browser->tab_strip_model()->AddWebContents(
626 content::PAGE_TRANSITION_LINK,
627 TabStripModel::ADD_ACTIVE);
630 SessionService* session_service =
631 SessionServiceFactory::GetForProfileIfExisting(browser->profile());
633 session_service->TabRestored(contents_dupe, pinned);
634 return contents_dupe;
637 bool CanDuplicateTabAt(Browser* browser, int index) {
638 content::NavigationController& nc =
639 browser->tab_strip_model()->GetWebContentsAt(index)->GetController();
640 return nc.GetWebContents() && nc.GetLastCommittedEntry();
643 void ConvertPopupToTabbedBrowser(Browser* browser) {
644 content::RecordAction(UserMetricsAction("ShowAsTab"));
645 TabStripModel* tab_strip = browser->tab_strip_model();
646 WebContents* contents =
647 tab_strip->DetachWebContentsAt(tab_strip->active_index());
648 Browser* b = new Browser(Browser::CreateParams(browser->profile(),
649 browser->host_desktop_type()));
650 b->tab_strip_model()->AppendWebContents(contents, true);
655 content::RecordAction(UserMetricsAction("Exit"));
656 chrome::AttemptUserExit();
659 void BookmarkCurrentPage(Browser* browser) {
660 BookmarkCurrentPageInternal(browser, false);
663 void BookmarkCurrentPageFromStar(Browser* browser) {
664 BookmarkCurrentPageInternal(browser, true);
667 bool CanBookmarkCurrentPage(const Browser* browser) {
668 BookmarkModel* model =
669 BookmarkModelFactory::GetForProfile(browser->profile());
670 return browser_defaults::bookmarks_enabled &&
671 browser->profile()->GetPrefs()->GetBoolean(
672 prefs::kEditBookmarksEnabled) &&
673 model && model->loaded() && browser->is_type_tabbed();
676 void BookmarkAllTabs(Browser* browser) {
677 chrome::ShowBookmarkAllTabsDialog(browser);
680 bool CanBookmarkAllTabs(const Browser* browser) {
681 return browser->tab_strip_model()->count() > 1 &&
682 CanBookmarkCurrentPage(browser);
685 void Translate(Browser* browser) {
686 if (!browser->window()->IsActive())
689 WebContents* web_contents =
690 browser->tab_strip_model()->GetActiveWebContents();
691 TranslateTabHelper* translate_tab_helper =
692 TranslateTabHelper::FromWebContents(web_contents);
694 TranslateBubbleModel::ViewState view_state =
695 TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE;
696 if (translate_tab_helper) {
697 if (translate_tab_helper->language_state().translation_pending())
698 view_state = TranslateBubbleModel::VIEW_STATE_TRANSLATING;
699 else if (translate_tab_helper->language_state().IsPageTranslated())
700 view_state = TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE;
702 browser->window()->ShowTranslateBubble(web_contents, view_state);
705 void TogglePagePinnedToStartScreen(Browser* browser) {
707 MetroPinTabHelper::FromWebContents(
708 browser->tab_strip_model()->GetActiveWebContents())->
709 TogglePinnedToStartScreen();
713 void SavePage(Browser* browser) {
714 content::RecordAction(UserMetricsAction("SavePage"));
715 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
716 if (current_tab && current_tab->GetContentsMimeType() == "application/pdf")
717 content::RecordAction(UserMetricsAction("PDF.SavePage"));
718 current_tab->OnSavePage();
721 bool CanSavePage(const Browser* browser) {
722 // LocalState can be NULL in tests.
723 if (g_browser_process->local_state() &&
724 !g_browser_process->local_state()->GetBoolean(
725 prefs::kAllowFileSelectionDialogs)) {
728 return !browser->is_devtools() &&
729 !(GetContentRestrictions(browser) & CONTENT_RESTRICTION_SAVE);
732 void ShowFindBar(Browser* browser) {
733 browser->GetFindBarController()->Show();
736 void ShowWebsiteSettings(Browser* browser,
737 content::WebContents* web_contents,
739 const SSLStatus& ssl) {
740 browser->window()->ShowWebsiteSettings(
741 Profile::FromBrowserContext(web_contents->GetBrowserContext()),
742 web_contents, url, ssl);
746 void Print(Browser* browser) {
747 #if defined(ENABLE_PRINTING)
748 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
749 #if defined(ENABLE_FULL_PRINTING)
750 printing::PrintViewManager* print_view_manager =
751 printing::PrintViewManager::FromWebContents(contents);
752 if (browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintPreviewDisabled))
753 print_view_manager->PrintNow();
755 print_view_manager->PrintPreviewNow(false);
757 printing::PrintViewManagerBasic* print_view_manager =
758 printing::PrintViewManagerBasic::FromWebContents(contents);
759 print_view_manager->PrintNow();
760 #endif // defined(ENABLE_FULL_PRINTING)
761 #endif // defined(ENABLE_PRINTING)
764 bool CanPrint(const Browser* browser) {
765 // Do not print when printing is disabled via pref or policy.
766 // Do not print when a constrained window is showing. It's confusing.
767 return browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) &&
768 !(IsShowingWebContentsModalDialog(browser) ||
769 GetContentRestrictions(browser) & CONTENT_RESTRICTION_PRINT);
772 void AdvancedPrint(Browser* browser) {
773 #if defined(ENABLE_FULL_PRINTING)
774 printing::PrintViewManager* print_view_manager =
775 printing::PrintViewManager::FromWebContents(
776 browser->tab_strip_model()->GetActiveWebContents());
777 print_view_manager->AdvancedPrintNow();
781 bool CanAdvancedPrint(const Browser* browser) {
782 // If printing is not disabled via pref or policy, it is always possible to
783 // advanced print when the print preview is visible. The exception to this
784 // is under Win8 ash, since showing the advanced print dialog will open it
785 // modally on the Desktop and hang the browser. We can remove this check
786 // once we integrate with the system print charm.
788 if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH)
792 return browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) &&
793 (PrintPreviewShowing(browser) || CanPrint(browser));
796 void PrintToDestination(Browser* browser) {
797 #if defined(ENABLE_FULL_PRINTING)
798 printing::PrintViewManager* print_view_manager =
799 printing::PrintViewManager::FromWebContents(
800 browser->tab_strip_model()->GetActiveWebContents());
801 print_view_manager->PrintToDestination();
805 void EmailPageLocation(Browser* browser) {
806 content::RecordAction(UserMetricsAction("EmailPageLocation"));
807 WebContents* wc = browser->tab_strip_model()->GetActiveWebContents();
810 std::string title = net::EscapeQueryParamValue(
811 UTF16ToUTF8(wc->GetTitle()), false);
812 std::string page_url = net::EscapeQueryParamValue(wc->GetURL().spec(), false);
813 std::string mailto = std::string("mailto:?subject=Fwd:%20") +
814 title + "&body=%0A%0A" + page_url;
815 platform_util::OpenExternal(GURL(mailto));
818 bool CanEmailPageLocation(const Browser* browser) {
819 return browser->toolbar_model()->ShouldDisplayURL() &&
820 browser->tab_strip_model()->GetActiveWebContents()->GetURL().is_valid();
823 void Cut(Browser* browser) {
824 content::RecordAction(UserMetricsAction("Cut"));
825 browser->window()->Cut();
828 void Copy(Browser* browser) {
829 content::RecordAction(UserMetricsAction("Copy"));
830 browser->window()->Copy();
833 void Paste(Browser* browser) {
834 content::RecordAction(UserMetricsAction("Paste"));
835 browser->window()->Paste();
838 void Find(Browser* browser) {
839 content::RecordAction(UserMetricsAction("Find"));
840 FindInPage(browser, false, false);
843 void FindNext(Browser* browser) {
844 content::RecordAction(UserMetricsAction("FindNext"));
845 FindInPage(browser, true, true);
848 void FindPrevious(Browser* browser) {
849 content::RecordAction(UserMetricsAction("FindPrevious"));
850 FindInPage(browser, true, false);
853 void FindInPage(Browser* browser, bool find_next, bool forward_direction) {
854 ShowFindBar(browser);
857 FindTabHelper* find_helper = FindTabHelper::FromWebContents(
858 browser->tab_strip_model()->GetActiveWebContents());
859 #if defined(OS_MACOSX)
860 // We always want to search for the current contents of the find bar on
861 // OS X. For regular profile it's always the current find pboard. For
862 // Incognito window it's the newest value of the find pboard content and
864 FindBar* find_bar = browser->GetFindBarController()->find_bar();
865 find_text = find_bar->GetFindText();
867 find_helper->StartFinding(find_text, forward_direction, false);
871 void Zoom(Browser* browser, content::PageZoom zoom) {
872 if (browser->is_devtools())
875 chrome_page_zoom::Zoom(browser->tab_strip_model()->GetActiveWebContents(),
879 void FocusToolbar(Browser* browser) {
880 content::RecordAction(UserMetricsAction("FocusToolbar"));
881 browser->window()->FocusToolbar();
884 void FocusLocationBar(Browser* browser) {
885 content::RecordAction(UserMetricsAction("FocusLocation"));
886 browser->window()->SetFocusToLocationBar(true);
889 void FocusSearch(Browser* browser) {
890 // TODO(beng): replace this with FocusLocationBar
891 content::RecordAction(UserMetricsAction("FocusSearch"));
892 browser->window()->GetLocationBar()->FocusSearch();
895 void FocusAppMenu(Browser* browser) {
896 content::RecordAction(UserMetricsAction("FocusAppMenu"));
897 browser->window()->FocusAppMenu();
900 void FocusBookmarksToolbar(Browser* browser) {
901 content::RecordAction(UserMetricsAction("FocusBookmarksToolbar"));
902 browser->window()->FocusBookmarksToolbar();
905 void FocusInfobars(Browser* browser) {
906 content::RecordAction(UserMetricsAction("FocusInfobars"));
907 browser->window()->FocusInfobars();
910 void FocusNextPane(Browser* browser) {
911 content::RecordAction(UserMetricsAction("FocusNextPane"));
912 browser->window()->RotatePaneFocus(true);
915 void FocusPreviousPane(Browser* browser) {
916 content::RecordAction(UserMetricsAction("FocusPreviousPane"));
917 browser->window()->RotatePaneFocus(false);
920 void ToggleDevToolsWindow(Browser* browser, DevToolsToggleAction action) {
921 if (action.type() == DevToolsToggleAction::kShowConsole)
922 content::RecordAction(UserMetricsAction("DevTools_ToggleConsole"));
924 content::RecordAction(UserMetricsAction("DevTools_ToggleWindow"));
925 DevToolsWindow::ToggleDevToolsWindow(browser, action);
928 bool CanOpenTaskManager() {
930 // In metro we can't display the task manager, as it is a native window.
931 return !win8::IsSingleWindowMetroMode();
937 void OpenTaskManager(Browser* browser) {
938 content::RecordAction(UserMetricsAction("TaskManager"));
939 chrome::ShowTaskManager(browser);
942 void OpenFeedbackDialog(Browser* browser) {
943 content::RecordAction(UserMetricsAction("Feedback"));
944 chrome::ShowFeedbackPage(browser, std::string(), std::string());
947 void ToggleBookmarkBar(Browser* browser) {
948 content::RecordAction(UserMetricsAction("ShowBookmarksBar"));
949 ToggleBookmarkBarWhenVisible(browser->profile());
952 void ShowAppMenu(Browser* browser) {
953 // We record the user metric for this event in WrenchMenu::RunMenu.
954 browser->window()->ShowAppMenu();
957 void ShowAvatarMenu(Browser* browser) {
958 browser->window()->ShowAvatarBubbleFromAvatarButton();
961 void OpenUpdateChromeDialog(Browser* browser) {
962 if (UpgradeDetector::GetInstance()->is_outdated_install()) {
963 content::NotificationService::current()->Notify(
964 chrome::NOTIFICATION_OUTDATED_INSTALL,
965 content::NotificationService::AllSources(),
966 content::NotificationService::NoDetails());
968 content::RecordAction(UserMetricsAction("UpdateChrome"));
969 browser->window()->ShowUpdateChromeDialog();
973 void ToggleSpeechInput(Browser* browser) {
974 browser->tab_strip_model()->GetActiveWebContents()->
975 GetRenderViewHost()->ToggleSpeechInput();
976 if (browser->instant_controller())
977 browser->instant_controller()->ToggleVoiceSearch();
980 bool CanRequestTabletSite(WebContents* current_tab) {
983 return current_tab->GetController().GetActiveEntry() != NULL;
986 bool IsRequestingTabletSite(Browser* browser) {
987 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
990 content::NavigationEntry* entry =
991 current_tab->GetController().GetActiveEntry();
994 return entry->GetIsOverridingUserAgent();
997 void ToggleRequestTabletSite(Browser* browser) {
998 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
1001 NavigationController& controller = current_tab->GetController();
1002 NavigationEntry* entry = controller.GetActiveEntry();
1005 if (entry->GetIsOverridingUserAgent()) {
1006 entry->SetIsOverridingUserAgent(false);
1008 entry->SetIsOverridingUserAgent(true);
1009 chrome::VersionInfo version_info;
1010 std::string product;
1011 if (version_info.is_valid())
1012 product = version_info.ProductNameAndVersionForUserAgent();
1013 current_tab->SetUserAgentOverride(
1014 webkit_glue::BuildUserAgentFromOSAndProduct(
1015 kOsOverrideForTabletSite, product));
1017 controller.ReloadOriginalRequestURL(true);
1020 void ToggleFullscreenMode(Browser* browser) {
1021 browser->fullscreen_controller()->ToggleFullscreenMode();
1024 void ClearCache(Browser* browser) {
1025 BrowsingDataRemover* remover =
1026 BrowsingDataRemover::CreateForUnboundedRange(browser->profile());
1027 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
1028 BrowsingDataHelper::UNPROTECTED_WEB);
1029 // BrowsingDataRemover takes care of deleting itself when done.
1032 bool IsDebuggerAttachedToCurrentTab(Browser* browser) {
1033 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
1035 content::DevToolsAgentHost::IsDebuggerAttached(contents) : false;
1038 void ViewSource(Browser* browser, WebContents* contents) {
1041 // Use the last committed entry, since the pending entry hasn't loaded yet and
1042 // won't be copied into the cloned tab.
1043 NavigationEntry* entry = contents->GetController().GetLastCommittedEntry();
1047 ViewSource(browser, contents, entry->GetURL(), entry->GetPageState());
1050 void ViewSource(Browser* browser,
1051 WebContents* contents,
1053 const content::PageState& page_state) {
1054 content::RecordAction(UserMetricsAction("ViewSource"));
1057 // Note that Clone does not copy the pending or transient entries, so the
1058 // active entry in view_source_contents will be the last committed entry.
1059 WebContents* view_source_contents = contents->Clone();
1060 DCHECK(view_source_contents->GetController().CanPruneAllButVisible());
1061 view_source_contents->GetController().PruneAllButVisible();
1062 NavigationEntry* active_entry =
1063 view_source_contents->GetController().GetActiveEntry();
1067 GURL view_source_url =
1068 GURL(content::kViewSourceScheme + std::string(":") + url.spec());
1069 active_entry->SetVirtualURL(view_source_url);
1071 // Do not restore scroller position.
1072 active_entry->SetPageState(page_state.RemoveScrollOffset());
1074 // Do not restore title, derive it from the url.
1075 active_entry->SetTitle(string16());
1077 // Now show view-source entry.
1078 if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) {
1079 // If this is a tabbed browser, just create a duplicate tab inside the same
1080 // window next to the tab being duplicated.
1081 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents);
1082 int add_types = TabStripModel::ADD_ACTIVE |
1083 TabStripModel::ADD_INHERIT_GROUP;
1084 browser->tab_strip_model()->InsertWebContentsAt(
1086 view_source_contents,
1089 Browser* b = new Browser(
1090 Browser::CreateParams(Browser::TYPE_TABBED, browser->profile(),
1091 browser->host_desktop_type()));
1093 // Preserve the size of the original window. The new window has already
1094 // been given an offset by the OS, so we shouldn't copy the old bounds.
1095 BrowserWindow* new_window = b->window();
1096 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
1097 browser->window()->GetRestoredBounds().size()));
1099 // We need to show the browser now. Otherwise ContainerWin assumes the
1100 // WebContents is invisible and won't size it.
1101 b->window()->Show();
1103 // The page transition below is only for the purpose of inserting the tab.
1104 b->tab_strip_model()->AddWebContents(view_source_contents, -1,
1105 content::PAGE_TRANSITION_LINK,
1106 TabStripModel::ADD_ACTIVE);
1109 SessionService* session_service =
1110 SessionServiceFactory::GetForProfileIfExisting(browser->profile());
1111 if (session_service)
1112 session_service->TabRestored(view_source_contents, false);
1115 void ViewSelectedSource(Browser* browser) {
1116 ViewSource(browser, browser->tab_strip_model()->GetActiveWebContents());
1119 bool CanViewSource(const Browser* browser) {
1120 return browser->tab_strip_model()->GetActiveWebContents()->
1121 GetController().CanViewSource();
1124 void CreateApplicationShortcuts(Browser* browser) {
1125 content::RecordAction(UserMetricsAction("CreateShortcut"));
1126 extensions::TabHelper::FromWebContents(
1127 browser->tab_strip_model()->GetActiveWebContents())->
1128 CreateApplicationShortcuts();
1131 bool CanCreateApplicationShortcuts(const Browser* browser) {
1132 return extensions::TabHelper::FromWebContents(
1133 browser->tab_strip_model()->GetActiveWebContents())->
1134 CanCreateApplicationShortcuts();
1137 void ConvertTabToAppWindow(Browser* browser,
1138 content::WebContents* contents) {
1139 const GURL& url = contents->GetController().GetActiveEntry()->GetURL();
1140 std::string app_name = web_app::GenerateApplicationNameFromURL(url);
1142 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents);
1144 browser->tab_strip_model()->DetachWebContentsAt(index);
1146 Browser* app_browser = new Browser(
1147 Browser::CreateParams::CreateForApp(
1148 Browser::TYPE_POPUP, app_name, gfx::Rect(), browser->profile(),
1149 browser->host_desktop_type()));
1150 app_browser->tab_strip_model()->AppendWebContents(contents, true);
1152 contents->GetMutableRendererPrefs()->can_accept_load_drops = false;
1153 contents->GetRenderViewHost()->SyncRendererPrefs();
1154 app_browser->window()->Show();
1157 } // namespace chrome