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/extensions/api/commands/command_service.h"
20 #include "chrome/browser/extensions/tab_helper.h"
21 #include "chrome/browser/favicon/favicon_tab_helper.h"
22 #include "chrome/browser/google/google_util.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/translate/translate_tab_helper.h"
34 #include "chrome/browser/ui/accelerator_utils.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/search/search_tab_helper.h"
51 #include "chrome/browser/ui/status_bubble.h"
52 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
53 #include "chrome/browser/ui/tabs/tab_strip_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/extensions/manifest_handlers/app_launch_info.h"
61 #include "chrome/common/pref_names.h"
62 #include "components/bookmarks/core/browser/bookmark_model.h"
63 #include "components/bookmarks/core/browser/bookmark_utils.h"
64 #include "components/web_modal/web_contents_modal_dialog_manager.h"
65 #include "content/public/browser/devtools_agent_host.h"
66 #include "content/public/browser/navigation_controller.h"
67 #include "content/public/browser/navigation_entry.h"
68 #include "content/public/browser/notification_service.h"
69 #include "content/public/browser/page_navigator.h"
70 #include "content/public/browser/render_view_host.h"
71 #include "content/public/browser/render_widget_host_view.h"
72 #include "content/public/browser/user_metrics.h"
73 #include "content/public/browser/web_contents.h"
74 #include "content/public/common/renderer_preferences.h"
75 #include "content/public/common/url_constants.h"
76 #include "content/public/common/url_utils.h"
77 #include "content/public/common/user_agent.h"
78 #include "extensions/browser/extension_registry.h"
79 #include "extensions/common/extension.h"
80 #include "extensions/common/extension_set.h"
81 #include "net/base/escape.h"
82 #include "ui/events/keycodes/keyboard_codes.h"
85 #include "chrome/browser/ui/metro_pin_tab_helper_win.h"
88 #if defined(ENABLE_PRINTING)
89 #if defined(ENABLE_FULL_PRINTING)
90 #include "chrome/browser/printing/print_preview_dialog_controller.h"
91 #include "chrome/browser/printing/print_view_manager.h"
93 #include "chrome/browser/printing/print_view_manager_basic.h"
94 #endif // defined(ENABLE_FULL_PRINTING)
95 #endif // defined(ENABLE_PRINTING)
98 const char kOsOverrideForTabletSite[] = "Linux; Android 4.0.3";
101 using base::UserMetricsAction;
102 using content::NavigationController;
103 using content::NavigationEntry;
104 using content::OpenURLParams;
105 using content::Referrer;
106 using content::SSLStatus;
107 using content::WebContents;
108 using web_modal::WebContentsModalDialogManager;
113 bool CanBookmarkCurrentPageInternal(const Browser* browser,
114 bool check_remove_bookmark_ui) {
115 BookmarkModel* model =
116 BookmarkModelFactory::GetForProfile(browser->profile());
117 return browser_defaults::bookmarks_enabled &&
118 browser->profile()->GetPrefs()->GetBoolean(
119 prefs::kEditBookmarksEnabled) &&
120 model && model->loaded() && browser->is_type_tabbed() &&
121 (!check_remove_bookmark_ui ||
122 !chrome::ShouldRemoveBookmarkThisPageUI(browser->profile()));
125 bool GetBookmarkOverrideCommand(
127 const extensions::Extension** extension,
128 extensions::Command* command,
129 extensions::CommandService::ExtensionCommandType* command_type) {
132 DCHECK(command_type);
134 ui::Accelerator bookmark_page_accelerator =
135 chrome::GetPrimaryChromeAcceleratorForCommandId(IDC_BOOKMARK_PAGE);
136 if (bookmark_page_accelerator.key_code() == ui::VKEY_UNKNOWN)
139 extensions::CommandService* command_service =
140 extensions::CommandService::Get(profile);
141 const extensions::ExtensionSet& extension_set =
142 extensions::ExtensionRegistry::Get(profile)->enabled_extensions();
143 for (extensions::ExtensionSet::const_iterator i = extension_set.begin();
144 i != extension_set.end();
146 extensions::Command prospective_command;
147 extensions::CommandService::ExtensionCommandType prospective_command_type;
148 if (command_service->GetBoundExtensionCommand((*i)->id(),
149 bookmark_page_accelerator,
150 &prospective_command,
151 &prospective_command_type)) {
152 *extension = i->get();
153 *command = prospective_command;
154 *command_type = prospective_command_type;
162 void BookmarkCurrentPageInternal(Browser* browser) {
163 content::RecordAction(UserMetricsAction("Star"));
165 BookmarkModel* model =
166 BookmarkModelFactory::GetForProfile(browser->profile());
167 if (!model || !model->loaded())
168 return; // Ignore requests until bookmarks are loaded.
171 base::string16 title;
172 WebContents* web_contents =
173 browser->tab_strip_model()->GetActiveWebContents();
174 GetURLAndTitleToBookmark(web_contents, &url, &title);
175 bool was_bookmarked = model->IsBookmarked(url);
176 if (!was_bookmarked && web_contents->GetBrowserContext()->IsOffTheRecord()) {
177 // If we're incognito the favicon may not have been saved. Save it now
178 // so that bookmarks have an icon for the page.
179 FaviconTabHelper::FromWebContents(web_contents)->SaveFavicon();
181 bookmark_utils::AddIfNotBookmarked(model, url, title);
182 // Make sure the model actually added a bookmark before showing the star. A
183 // bookmark isn't created if the url is invalid.
184 if (browser->window()->IsActive() && model->IsBookmarked(url)) {
185 // Only show the bubble if the window is active, otherwise we may get into
186 // weird situations where the bubble is deleted as soon as it is shown.
187 browser->window()->ShowBookmarkBubble(url, was_bookmarked);
191 // Based on |disposition|, creates a new tab as necessary, and returns the
192 // appropriate tab to navigate. If that tab is the current tab, reverts the
193 // location bar contents, since all browser-UI-triggered navigations should
194 // revert any omnibox edits in the current tab.
195 WebContents* GetTabAndRevertIfNecessary(Browser* browser,
196 WindowOpenDisposition disposition) {
197 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
198 switch (disposition) {
199 case NEW_FOREGROUND_TAB:
200 case NEW_BACKGROUND_TAB: {
201 WebContents* new_tab = current_tab->Clone();
202 browser->tab_strip_model()->AddWebContents(
203 new_tab, -1, content::PAGE_TRANSITION_LINK,
204 (disposition == NEW_FOREGROUND_TAB) ?
205 TabStripModel::ADD_ACTIVE : TabStripModel::ADD_NONE);
209 WebContents* new_tab = current_tab->Clone();
210 Browser* new_browser = new Browser(Browser::CreateParams(
211 browser->profile(), browser->host_desktop_type()));
212 new_browser->tab_strip_model()->AddWebContents(
213 new_tab, -1, content::PAGE_TRANSITION_LINK,
214 TabStripModel::ADD_ACTIVE);
215 new_browser->window()->Show();
219 browser->window()->GetLocationBar()->Revert();
224 void ReloadInternal(Browser* browser,
225 WindowOpenDisposition disposition,
227 // As this is caused by a user action, give the focus to the page.
229 // Also notify RenderViewHostDelegate of the user gesture; this is
230 // normally done in Browser::Navigate, but a reload bypasses Navigate.
231 WebContents* new_tab = GetTabAndRevertIfNecessary(browser, disposition);
232 new_tab->UserGestureDone();
233 if (!new_tab->FocusLocationBarByDefault())
236 new_tab->GetController().ReloadIgnoringCache(true);
238 new_tab->GetController().Reload(true);
241 bool IsShowingWebContentsModalDialog(const Browser* browser) {
242 WebContents* web_contents =
243 browser->tab_strip_model()->GetActiveWebContents();
247 WebContentsModalDialogManager* web_contents_modal_dialog_manager =
248 WebContentsModalDialogManager::FromWebContents(web_contents);
249 return web_contents_modal_dialog_manager->IsDialogActive();
252 bool PrintPreviewShowing(const Browser* browser) {
253 #if defined(ENABLE_FULL_PRINTING)
254 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
255 printing::PrintPreviewDialogController* controller =
256 printing::PrintPreviewDialogController::GetInstance();
257 return controller && (controller->GetPrintPreviewForContents(contents) ||
258 controller->is_creating_print_preview_dialog());
266 bool IsCommandEnabled(Browser* browser, int command) {
267 return browser->command_controller()->command_updater()->IsCommandEnabled(
271 bool SupportsCommand(Browser* browser, int command) {
272 return browser->command_controller()->command_updater()->SupportsCommand(
276 bool ExecuteCommand(Browser* browser, int command) {
277 return browser->command_controller()->command_updater()->ExecuteCommand(
281 bool ExecuteCommandWithDisposition(Browser* browser,
283 WindowOpenDisposition disposition) {
284 return browser->command_controller()->command_updater()->
285 ExecuteCommandWithDisposition(command, disposition);
288 void UpdateCommandEnabled(Browser* browser, int command, bool enabled) {
289 browser->command_controller()->command_updater()->UpdateCommandEnabled(
293 void AddCommandObserver(Browser* browser,
295 CommandObserver* observer) {
296 browser->command_controller()->command_updater()->AddCommandObserver(
300 void RemoveCommandObserver(Browser* browser,
302 CommandObserver* observer) {
303 browser->command_controller()->command_updater()->RemoveCommandObserver(
307 int GetContentRestrictions(const Browser* browser) {
308 int content_restrictions = 0;
309 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
311 CoreTabHelper* core_tab_helper =
312 CoreTabHelper::FromWebContents(current_tab);
313 content_restrictions = core_tab_helper->content_restrictions();
314 NavigationEntry* active_entry =
315 current_tab->GetController().GetActiveEntry();
316 // See comment in UpdateCommandsForTabState about why we call url().
317 if (!content::IsSavableURL(
318 active_entry ? active_entry->GetURL() : GURL()) ||
319 current_tab->ShowingInterstitialPage())
320 content_restrictions |= CONTENT_RESTRICTION_SAVE;
321 if (current_tab->ShowingInterstitialPage())
322 content_restrictions |= CONTENT_RESTRICTION_PRINT;
324 return content_restrictions;
327 void NewEmptyWindow(Profile* profile, HostDesktopType desktop_type) {
328 bool incognito = profile->IsOffTheRecord();
329 PrefService* prefs = profile->GetPrefs();
331 if (IncognitoModePrefs::GetAvailability(prefs) ==
332 IncognitoModePrefs::DISABLED) {
335 } else if (profile->IsGuestSession() ||
336 (browser_defaults::kAlwaysOpenIncognitoWindow &&
337 IncognitoModePrefs::ShouldLaunchIncognito(
338 *CommandLine::ForCurrentProcess(), prefs))) {
343 content::RecordAction(UserMetricsAction("NewIncognitoWindow"));
344 OpenEmptyWindow(profile->GetOffTheRecordProfile(), desktop_type);
346 content::RecordAction(UserMetricsAction("NewWindow"));
347 SessionService* session_service =
348 SessionServiceFactory::GetForProfileForSessionRestore(
349 profile->GetOriginalProfile());
350 if (!session_service ||
351 !session_service->RestoreIfNecessary(std::vector<GURL>())) {
352 OpenEmptyWindow(profile->GetOriginalProfile(), desktop_type);
357 Browser* OpenEmptyWindow(Profile* profile, HostDesktopType desktop_type) {
358 Browser* browser = new Browser(
359 Browser::CreateParams(Browser::TYPE_TABBED, profile, desktop_type));
360 AddTabAt(browser, GURL(), -1, true);
361 browser->window()->Show();
365 void OpenWindowWithRestoredTabs(Profile* profile,
366 HostDesktopType host_desktop_type) {
367 TabRestoreService* service = TabRestoreServiceFactory::GetForProfile(profile);
369 service->RestoreMostRecentEntry(NULL, host_desktop_type);
372 void OpenURLOffTheRecord(Profile* profile,
374 chrome::HostDesktopType desktop_type) {
375 ScopedTabbedBrowserDisplayer displayer(profile->GetOffTheRecordProfile(),
377 AddSelectedTabWithURL(displayer.browser(), url,
378 content::PAGE_TRANSITION_LINK);
381 bool CanGoBack(const Browser* browser) {
382 return browser->tab_strip_model()->GetActiveWebContents()->
383 GetController().CanGoBack();
386 void GoBack(Browser* browser, WindowOpenDisposition disposition) {
387 content::RecordAction(UserMetricsAction("Back"));
389 if (CanGoBack(browser)) {
390 WebContents* current_tab =
391 browser->tab_strip_model()->GetActiveWebContents();
392 WebContents* new_tab = GetTabAndRevertIfNecessary(browser, disposition);
393 // If we are on an interstitial page and clone the tab, it won't be copied
394 // to the new tab, so we don't need to go back.
395 if ((new_tab == current_tab) || !current_tab->ShowingInterstitialPage())
396 new_tab->GetController().GoBack();
400 bool CanGoForward(const Browser* browser) {
401 return browser->tab_strip_model()->GetActiveWebContents()->
402 GetController().CanGoForward();
405 void GoForward(Browser* browser, WindowOpenDisposition disposition) {
406 content::RecordAction(UserMetricsAction("Forward"));
407 if (CanGoForward(browser)) {
408 GetTabAndRevertIfNecessary(browser, disposition)->
409 GetController().GoForward();
413 bool NavigateToIndexWithDisposition(Browser* browser,
415 WindowOpenDisposition disposition) {
416 NavigationController* controller =
417 &GetTabAndRevertIfNecessary(browser, disposition)->GetController();
418 if (index < 0 || index >= controller->GetEntryCount())
420 controller->GoToIndex(index);
424 void Reload(Browser* browser, WindowOpenDisposition disposition) {
425 content::RecordAction(UserMetricsAction("Reload"));
426 ReloadInternal(browser, disposition, false);
429 void ReloadIgnoringCache(Browser* browser, WindowOpenDisposition disposition) {
430 content::RecordAction(UserMetricsAction("ReloadIgnoringCache"));
431 ReloadInternal(browser, disposition, true);
434 bool CanReload(const Browser* browser) {
435 return !browser->is_devtools();
438 void Home(Browser* browser, WindowOpenDisposition disposition) {
439 content::RecordAction(UserMetricsAction("Home"));
441 std::string extra_headers;
442 #if defined(ENABLE_RLZ) && !defined(OS_IOS)
443 // If the home page is a Google home page, add the RLZ header to the request.
444 PrefService* pref_service = browser->profile()->GetPrefs();
446 if (google_util::IsGoogleHomePageUrl(
447 GURL(pref_service->GetString(prefs::kHomePage)))) {
448 extra_headers = RLZTracker::GetAccessPointHttpHeader(
449 RLZTracker::CHROME_HOME_PAGE);
452 #endif // defined(ENABLE_RLZ) && !defined(OS_IOS)
454 GURL url = browser->profile()->GetHomePage();
456 // Streamlined hosted apps should return to their launch page when the home
457 // button is pressed.
458 if (browser->is_app()) {
459 const extensions::Extension* extension =
460 extensions::ExtensionRegistry::Get(browser->profile())
462 web_app::GetExtensionIdFromApplicationName(browser->app_name()),
463 extensions::ExtensionRegistry::EVERYTHING);
467 url = extensions::AppLaunchInfo::GetLaunchWebURL(extension);
470 OpenURLParams params(
471 url, Referrer(), disposition,
472 content::PageTransitionFromInt(
473 content::PAGE_TRANSITION_AUTO_BOOKMARK |
474 content::PAGE_TRANSITION_HOME_PAGE),
476 params.extra_headers = extra_headers;
477 browser->OpenURL(params);
480 void OpenCurrentURL(Browser* browser) {
481 content::RecordAction(UserMetricsAction("LoadURL"));
482 LocationBar* location_bar = browser->window()->GetLocationBar();
486 GURL url(location_bar->GetDestinationURL());
488 content::PageTransition page_transition = location_bar->GetPageTransition();
489 content::PageTransition page_transition_without_qualifier(
490 PageTransitionStripQualifier(page_transition));
491 WindowOpenDisposition open_disposition =
492 location_bar->GetWindowOpenDisposition();
493 // A PAGE_TRANSITION_TYPED means the user has typed a URL. We do not want to
494 // open URLs with instant_controller since in some cases it disregards it
495 // and performs a search instead. For example, when using CTRL-Enter, the
496 // location_bar is aware of the URL but instant is not.
497 // Instant should also not handle PAGE_TRANSITION_RELOAD because its knowledge
498 // of the omnibox text may be stale if the user focuses in the omnibox and
499 // presses enter without typing anything.
500 if (page_transition_without_qualifier != content::PAGE_TRANSITION_TYPED &&
501 page_transition_without_qualifier != content::PAGE_TRANSITION_RELOAD &&
502 browser->instant_controller() &&
503 browser->instant_controller()->OpenInstant(open_disposition, url))
506 NavigateParams params(browser, url, page_transition);
507 params.disposition = open_disposition;
508 // Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least
509 // inherit the opener. In some cases the tabstrip will determine the group
510 // should be inherited, in which case the group is inherited instead of the
512 params.tabstrip_add_types =
513 TabStripModel::ADD_FORCE_INDEX | TabStripModel::ADD_INHERIT_OPENER;
516 DCHECK(browser->profile()->GetExtensionService());
517 const extensions::Extension* extension =
518 extensions::ExtensionRegistry::Get(browser->profile())
519 ->enabled_extensions().GetAppByURL(url);
521 CoreAppLauncherHandler::RecordAppLaunchType(
522 extension_misc::APP_LAUNCH_OMNIBOX_LOCATION,
523 extension->GetType());
527 void Stop(Browser* browser) {
528 content::RecordAction(UserMetricsAction("Stop"));
529 browser->tab_strip_model()->GetActiveWebContents()->Stop();
532 void NewWindow(Browser* browser) {
533 NewEmptyWindow(browser->profile()->GetOriginalProfile(),
534 browser->host_desktop_type());
537 void NewIncognitoWindow(Browser* browser) {
538 NewEmptyWindow(browser->profile()->GetOffTheRecordProfile(),
539 browser->host_desktop_type());
542 void CloseWindow(Browser* browser) {
543 content::RecordAction(UserMetricsAction("CloseWindow"));
544 browser->window()->Close();
547 void NewTab(Browser* browser) {
548 content::RecordAction(UserMetricsAction("NewTab"));
549 // TODO(asvitkine): This is invoked programmatically from several places.
550 // Audit the code and change it so that the histogram only gets collected for
551 // user-initiated commands.
552 UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", TabStripModel::NEW_TAB_COMMAND,
553 TabStripModel::NEW_TAB_ENUM_COUNT);
555 if (browser->is_type_tabbed()) {
556 AddTabAt(browser, GURL(), -1, true);
557 browser->tab_strip_model()->GetActiveWebContents()->RestoreFocus();
559 ScopedTabbedBrowserDisplayer displayer(browser->profile(),
560 browser->host_desktop_type());
561 Browser* b = displayer.browser();
562 AddTabAt(b, GURL(), -1, true);
564 // The call to AddBlankTabAt above did not set the focus to the tab as its
565 // window was not active, so we have to do it explicitly.
566 // See http://crbug.com/6380.
567 b->tab_strip_model()->GetActiveWebContents()->RestoreFocus();
571 void CloseTab(Browser* browser) {
572 content::RecordAction(UserMetricsAction("CloseTab_Accelerator"));
573 browser->tab_strip_model()->CloseSelectedTabs();
576 void RestoreTab(Browser* browser) {
577 content::RecordAction(UserMetricsAction("RestoreTab"));
578 TabRestoreService* service =
579 TabRestoreServiceFactory::GetForProfile(browser->profile());
581 service->RestoreMostRecentEntry(browser->tab_restore_service_delegate(),
582 browser->host_desktop_type());
585 TabStripModelDelegate::RestoreTabType GetRestoreTabType(
586 const Browser* browser) {
587 TabRestoreService* service =
588 TabRestoreServiceFactory::GetForProfile(browser->profile());
589 if (!service || service->entries().empty())
590 return TabStripModelDelegate::RESTORE_NONE;
591 if (service->entries().front()->type == TabRestoreService::WINDOW)
592 return TabStripModelDelegate::RESTORE_WINDOW;
593 return TabStripModelDelegate::RESTORE_TAB;
596 void SelectNextTab(Browser* browser) {
597 content::RecordAction(UserMetricsAction("SelectNextTab"));
598 browser->tab_strip_model()->SelectNextTab();
601 void SelectPreviousTab(Browser* browser) {
602 content::RecordAction(UserMetricsAction("SelectPrevTab"));
603 browser->tab_strip_model()->SelectPreviousTab();
606 void MoveTabNext(Browser* browser) {
607 content::RecordAction(UserMetricsAction("MoveTabNext"));
608 browser->tab_strip_model()->MoveTabNext();
611 void MoveTabPrevious(Browser* browser) {
612 content::RecordAction(UserMetricsAction("MoveTabPrevious"));
613 browser->tab_strip_model()->MoveTabPrevious();
616 void SelectNumberedTab(Browser* browser, int index) {
617 if (index < browser->tab_strip_model()->count()) {
618 content::RecordAction(UserMetricsAction("SelectNumberedTab"));
619 browser->tab_strip_model()->ActivateTabAt(index, true);
623 void SelectLastTab(Browser* browser) {
624 content::RecordAction(UserMetricsAction("SelectLastTab"));
625 browser->tab_strip_model()->SelectLastTab();
628 void DuplicateTab(Browser* browser) {
629 content::RecordAction(UserMetricsAction("Duplicate"));
630 DuplicateTabAt(browser, browser->tab_strip_model()->active_index());
633 bool CanDuplicateTab(const Browser* browser) {
634 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
635 return contents && contents->GetController().GetLastCommittedEntry();
638 WebContents* DuplicateTabAt(Browser* browser, int index) {
639 WebContents* contents = browser->tab_strip_model()->GetWebContentsAt(index);
641 WebContents* contents_dupe = contents->Clone();
644 if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) {
645 // If this is a tabbed browser, just create a duplicate tab inside the same
646 // window next to the tab being duplicated.
647 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents);
648 pinned = browser->tab_strip_model()->IsTabPinned(index);
649 int add_types = TabStripModel::ADD_ACTIVE |
650 TabStripModel::ADD_INHERIT_GROUP |
651 (pinned ? TabStripModel::ADD_PINNED : 0);
652 browser->tab_strip_model()->InsertWebContentsAt(
653 index + 1, contents_dupe, add_types);
655 Browser* new_browser = NULL;
656 if (browser->is_app() && !browser->is_type_popup()) {
657 new_browser = new Browser(
658 Browser::CreateParams::CreateForApp(browser->app_name(),
659 browser->is_trusted_source(),
662 browser->host_desktop_type()));
664 new_browser = new Browser(
665 Browser::CreateParams(browser->type(), browser->profile(),
666 browser->host_desktop_type()));
668 // Preserve the size of the original window. The new window has already
669 // been given an offset by the OS, so we shouldn't copy the old bounds.
670 BrowserWindow* new_window = new_browser->window();
671 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
672 browser->window()->GetRestoredBounds().size()));
674 // We need to show the browser now. Otherwise ContainerWin assumes the
675 // WebContents is invisible and won't size it.
676 new_browser->window()->Show();
678 // The page transition below is only for the purpose of inserting the tab.
679 new_browser->tab_strip_model()->AddWebContents(
681 content::PAGE_TRANSITION_LINK,
682 TabStripModel::ADD_ACTIVE);
685 SessionService* session_service =
686 SessionServiceFactory::GetForProfileIfExisting(browser->profile());
688 session_service->TabRestored(contents_dupe, pinned);
689 return contents_dupe;
692 bool CanDuplicateTabAt(Browser* browser, int index) {
693 content::NavigationController& nc =
694 browser->tab_strip_model()->GetWebContentsAt(index)->GetController();
695 return nc.GetWebContents() && nc.GetLastCommittedEntry();
698 void ConvertPopupToTabbedBrowser(Browser* browser) {
699 content::RecordAction(UserMetricsAction("ShowAsTab"));
700 TabStripModel* tab_strip = browser->tab_strip_model();
701 WebContents* contents =
702 tab_strip->DetachWebContentsAt(tab_strip->active_index());
703 Browser* b = new Browser(Browser::CreateParams(browser->profile(),
704 browser->host_desktop_type()));
705 b->tab_strip_model()->AppendWebContents(contents, true);
710 content::RecordAction(UserMetricsAction("Exit"));
711 chrome::AttemptUserExit();
714 void BookmarkCurrentPage(Browser* browser) {
715 DCHECK(!chrome::ShouldRemoveBookmarkThisPageUI(browser->profile()));
717 const extensions::Extension* extension = NULL;
718 extensions::Command command;
719 extensions::CommandService::ExtensionCommandType command_type;
720 if (GetBookmarkOverrideCommand(browser->profile(),
724 switch (command_type) {
725 case extensions::CommandService::NAMED:
726 browser->window()->ExecuteExtensionCommand(extension, command);
729 case extensions::CommandService::BROWSER_ACTION:
730 // BookmarkCurrentPage is called through a user gesture, so it is safe
731 // to call ShowBrowserActionPopup.
732 browser->window()->ShowBrowserActionPopup(extension);
735 case extensions::CommandService::PAGE_ACTION:
736 browser->window()->ShowPageActionPopup(extension);
741 BookmarkCurrentPageInternal(browser);
744 bool CanBookmarkCurrentPage(const Browser* browser) {
745 return CanBookmarkCurrentPageInternal(browser, true);
748 void BookmarkAllTabs(Browser* browser) {
749 chrome::ShowBookmarkAllTabsDialog(browser);
752 bool CanBookmarkAllTabs(const Browser* browser) {
753 return browser->tab_strip_model()->count() > 1 &&
754 !chrome::ShouldRemoveBookmarkOpenPagesUI(browser->profile()) &&
755 CanBookmarkCurrentPageInternal(browser, false);
758 void Translate(Browser* browser) {
759 if (!browser->window()->IsActive())
762 WebContents* web_contents =
763 browser->tab_strip_model()->GetActiveWebContents();
764 TranslateTabHelper* translate_tab_helper =
765 TranslateTabHelper::FromWebContents(web_contents);
767 translate::TranslateStep step = translate::TRANSLATE_STEP_BEFORE_TRANSLATE;
768 if (translate_tab_helper) {
769 if (translate_tab_helper->GetLanguageState().translation_pending())
770 step = translate::TRANSLATE_STEP_TRANSLATING;
771 else if (translate_tab_helper->GetLanguageState().IsPageTranslated())
772 step = translate::TRANSLATE_STEP_AFTER_TRANSLATE;
774 browser->window()->ShowTranslateBubble(
775 web_contents, step, TranslateErrors::NONE);
778 void ManagePasswordsForPage(Browser* browser) {
779 // TODO(mkwst): Implement this feature on Mac: http://crbug.com/261628
780 #if !defined(OS_MACOSX)
781 if (!browser->window()->IsActive())
784 WebContents* web_contents =
785 browser->tab_strip_model()->GetActiveWebContents();
786 chrome::ShowManagePasswordsBubble(web_contents);
790 void TogglePagePinnedToStartScreen(Browser* browser) {
792 MetroPinTabHelper::FromWebContents(
793 browser->tab_strip_model()->GetActiveWebContents())->
794 TogglePinnedToStartScreen();
798 void SavePage(Browser* browser) {
799 content::RecordAction(UserMetricsAction("SavePage"));
800 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
801 if (current_tab && current_tab->GetContentsMimeType() == "application/pdf")
802 content::RecordAction(UserMetricsAction("PDF.SavePage"));
803 current_tab->OnSavePage();
806 bool CanSavePage(const Browser* browser) {
807 // LocalState can be NULL in tests.
808 if (g_browser_process->local_state() &&
809 !g_browser_process->local_state()->GetBoolean(
810 prefs::kAllowFileSelectionDialogs)) {
813 return !browser->is_devtools() &&
814 !(GetContentRestrictions(browser) & CONTENT_RESTRICTION_SAVE);
817 void ShowFindBar(Browser* browser) {
818 browser->GetFindBarController()->Show();
821 void ShowWebsiteSettings(Browser* browser,
822 content::WebContents* web_contents,
824 const SSLStatus& ssl) {
825 browser->window()->ShowWebsiteSettings(
826 Profile::FromBrowserContext(web_contents->GetBrowserContext()),
827 web_contents, url, ssl);
831 void Print(Browser* browser) {
832 #if defined(ENABLE_PRINTING)
833 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
834 #if defined(ENABLE_FULL_PRINTING)
835 printing::PrintViewManager* print_view_manager =
836 printing::PrintViewManager::FromWebContents(contents);
837 if (browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintPreviewDisabled))
838 print_view_manager->PrintNow();
840 print_view_manager->PrintPreviewNow(false);
842 printing::PrintViewManagerBasic* print_view_manager =
843 printing::PrintViewManagerBasic::FromWebContents(contents);
844 print_view_manager->PrintNow();
845 #endif // defined(ENABLE_FULL_PRINTING)
846 #endif // defined(ENABLE_PRINTING)
849 bool CanPrint(const Browser* browser) {
850 // Do not print when printing is disabled via pref or policy.
851 // Do not print when a constrained window is showing. It's confusing.
852 return browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) &&
853 !(IsShowingWebContentsModalDialog(browser) ||
854 GetContentRestrictions(browser) & CONTENT_RESTRICTION_PRINT);
857 void AdvancedPrint(Browser* browser) {
858 #if defined(ENABLE_FULL_PRINTING)
859 printing::PrintViewManager* print_view_manager =
860 printing::PrintViewManager::FromWebContents(
861 browser->tab_strip_model()->GetActiveWebContents());
862 print_view_manager->AdvancedPrintNow();
866 bool CanAdvancedPrint(const Browser* browser) {
867 // If printing is not disabled via pref or policy, it is always possible to
868 // advanced print when the print preview is visible. The exception to this
869 // is under Win8 ash, since showing the advanced print dialog will open it
870 // modally on the Desktop and hang the browser. We can remove this check
871 // once we integrate with the system print charm.
873 if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH)
877 return browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) &&
878 (PrintPreviewShowing(browser) || CanPrint(browser));
881 void PrintToDestination(Browser* browser) {
882 #if defined(ENABLE_FULL_PRINTING)
883 printing::PrintViewManager* print_view_manager =
884 printing::PrintViewManager::FromWebContents(
885 browser->tab_strip_model()->GetActiveWebContents());
886 print_view_manager->PrintToDestination();
890 void EmailPageLocation(Browser* browser) {
891 content::RecordAction(UserMetricsAction("EmailPageLocation"));
892 WebContents* wc = browser->tab_strip_model()->GetActiveWebContents();
895 std::string title = net::EscapeQueryParamValue(
896 base::UTF16ToUTF8(wc->GetTitle()), false);
897 std::string page_url = net::EscapeQueryParamValue(wc->GetURL().spec(), false);
898 std::string mailto = std::string("mailto:?subject=Fwd:%20") +
899 title + "&body=%0A%0A" + page_url;
900 platform_util::OpenExternal(browser->profile(), GURL(mailto));
903 bool CanEmailPageLocation(const Browser* browser) {
904 return browser->toolbar_model()->ShouldDisplayURL() &&
905 browser->tab_strip_model()->GetActiveWebContents()->GetURL().is_valid();
908 void Cut(Browser* browser) {
909 content::RecordAction(UserMetricsAction("Cut"));
910 browser->window()->Cut();
913 void Copy(Browser* browser) {
914 content::RecordAction(UserMetricsAction("Copy"));
915 browser->window()->Copy();
918 void Paste(Browser* browser) {
919 content::RecordAction(UserMetricsAction("Paste"));
920 browser->window()->Paste();
923 void Find(Browser* browser) {
924 content::RecordAction(UserMetricsAction("Find"));
925 FindInPage(browser, false, false);
928 void FindNext(Browser* browser) {
929 content::RecordAction(UserMetricsAction("FindNext"));
930 FindInPage(browser, true, true);
933 void FindPrevious(Browser* browser) {
934 content::RecordAction(UserMetricsAction("FindPrevious"));
935 FindInPage(browser, true, false);
938 void FindInPage(Browser* browser, bool find_next, bool forward_direction) {
939 ShowFindBar(browser);
941 base::string16 find_text;
942 FindTabHelper* find_helper = FindTabHelper::FromWebContents(
943 browser->tab_strip_model()->GetActiveWebContents());
944 #if defined(OS_MACOSX)
945 // We always want to search for the current contents of the find bar on
946 // OS X. For regular profile it's always the current find pboard. For
947 // Incognito window it's the newest value of the find pboard content and
949 FindBar* find_bar = browser->GetFindBarController()->find_bar();
950 find_text = find_bar->GetFindText();
952 find_helper->StartFinding(find_text, forward_direction, false);
956 void Zoom(Browser* browser, content::PageZoom zoom) {
957 chrome_page_zoom::Zoom(browser->tab_strip_model()->GetActiveWebContents(),
961 void FocusToolbar(Browser* browser) {
962 content::RecordAction(UserMetricsAction("FocusToolbar"));
963 browser->window()->FocusToolbar();
966 void FocusLocationBar(Browser* browser) {
967 content::RecordAction(UserMetricsAction("FocusLocation"));
968 browser->window()->SetFocusToLocationBar(true);
971 void FocusSearch(Browser* browser) {
972 // TODO(beng): replace this with FocusLocationBar
973 content::RecordAction(UserMetricsAction("FocusSearch"));
974 browser->window()->GetLocationBar()->FocusSearch();
977 void FocusAppMenu(Browser* browser) {
978 content::RecordAction(UserMetricsAction("FocusAppMenu"));
979 browser->window()->FocusAppMenu();
982 void FocusBookmarksToolbar(Browser* browser) {
983 content::RecordAction(UserMetricsAction("FocusBookmarksToolbar"));
984 browser->window()->FocusBookmarksToolbar();
987 void FocusInfobars(Browser* browser) {
988 content::RecordAction(UserMetricsAction("FocusInfobars"));
989 browser->window()->FocusInfobars();
992 void FocusNextPane(Browser* browser) {
993 content::RecordAction(UserMetricsAction("FocusNextPane"));
994 browser->window()->RotatePaneFocus(true);
997 void FocusPreviousPane(Browser* browser) {
998 content::RecordAction(UserMetricsAction("FocusPreviousPane"));
999 browser->window()->RotatePaneFocus(false);
1002 void ToggleDevToolsWindow(Browser* browser, DevToolsToggleAction action) {
1003 if (action.type() == DevToolsToggleAction::kShowConsole)
1004 content::RecordAction(UserMetricsAction("DevTools_ToggleConsole"));
1006 content::RecordAction(UserMetricsAction("DevTools_ToggleWindow"));
1007 DevToolsWindow::ToggleDevToolsWindow(browser, action);
1010 bool CanOpenTaskManager() {
1011 #if defined(ENABLE_TASK_MANAGER)
1018 void OpenTaskManager(Browser* browser) {
1019 #if defined(ENABLE_TASK_MANAGER)
1020 content::RecordAction(UserMetricsAction("TaskManager"));
1021 chrome::ShowTaskManager(browser);
1027 void OpenFeedbackDialog(Browser* browser) {
1028 content::RecordAction(UserMetricsAction("Feedback"));
1029 chrome::ShowFeedbackPage(browser, std::string(), std::string());
1032 void ToggleBookmarkBar(Browser* browser) {
1033 content::RecordAction(UserMetricsAction("ShowBookmarksBar"));
1034 ToggleBookmarkBarWhenVisible(browser->profile());
1037 void ShowAppMenu(Browser* browser) {
1038 // We record the user metric for this event in WrenchMenu::RunMenu.
1039 browser->window()->ShowAppMenu();
1042 void ShowAvatarMenu(Browser* browser) {
1043 browser->window()->ShowAvatarBubbleFromAvatarButton(
1044 BrowserWindow::AVATAR_BUBBLE_MODE_DEFAULT);
1047 void OpenUpdateChromeDialog(Browser* browser) {
1048 if (UpgradeDetector::GetInstance()->is_outdated_install()) {
1049 content::NotificationService::current()->Notify(
1050 chrome::NOTIFICATION_OUTDATED_INSTALL,
1051 content::NotificationService::AllSources(),
1052 content::NotificationService::NoDetails());
1053 } else if (UpgradeDetector::GetInstance()->is_outdated_install_no_au()) {
1054 content::NotificationService::current()->Notify(
1055 chrome::NOTIFICATION_OUTDATED_INSTALL_NO_AU,
1056 content::NotificationService::AllSources(),
1057 content::NotificationService::NoDetails());
1059 content::RecordAction(UserMetricsAction("UpdateChrome"));
1060 browser->window()->ShowUpdateChromeDialog();
1064 void ToggleSpeechInput(Browser* browser) {
1065 SearchTabHelper* search_tab_helper =
1066 SearchTabHelper::FromWebContents(
1067 browser->tab_strip_model()->GetActiveWebContents());
1068 // |search_tab_helper| can be null in unit tests.
1069 if (search_tab_helper)
1070 search_tab_helper->ToggleVoiceSearch();
1073 bool CanRequestTabletSite(WebContents* current_tab) {
1076 return current_tab->GetController().GetActiveEntry() != NULL;
1079 bool IsRequestingTabletSite(Browser* browser) {
1080 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
1083 content::NavigationEntry* entry =
1084 current_tab->GetController().GetActiveEntry();
1087 return entry->GetIsOverridingUserAgent();
1090 void ToggleRequestTabletSite(Browser* browser) {
1091 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
1094 NavigationController& controller = current_tab->GetController();
1095 NavigationEntry* entry = controller.GetActiveEntry();
1098 if (entry->GetIsOverridingUserAgent()) {
1099 entry->SetIsOverridingUserAgent(false);
1101 entry->SetIsOverridingUserAgent(true);
1102 chrome::VersionInfo version_info;
1103 std::string product;
1104 if (version_info.is_valid())
1105 product = version_info.ProductNameAndVersionForUserAgent();
1106 current_tab->SetUserAgentOverride(content::BuildUserAgentFromOSAndProduct(
1107 kOsOverrideForTabletSite, product));
1109 controller.ReloadOriginalRequestURL(true);
1112 void ToggleFullscreenMode(Browser* browser) {
1114 browser->fullscreen_controller()->ToggleBrowserFullscreenMode();
1117 void ClearCache(Browser* browser) {
1118 BrowsingDataRemover* remover =
1119 BrowsingDataRemover::CreateForUnboundedRange(browser->profile());
1120 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
1121 BrowsingDataHelper::UNPROTECTED_WEB);
1122 // BrowsingDataRemover takes care of deleting itself when done.
1125 bool IsDebuggerAttachedToCurrentTab(Browser* browser) {
1126 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
1128 content::DevToolsAgentHost::IsDebuggerAttached(contents) : false;
1131 void ViewSource(Browser* browser, WebContents* contents) {
1134 // Use the last committed entry, since the pending entry hasn't loaded yet and
1135 // won't be copied into the cloned tab.
1136 NavigationEntry* entry = contents->GetController().GetLastCommittedEntry();
1140 ViewSource(browser, contents, entry->GetURL(), entry->GetPageState());
1143 void ViewSource(Browser* browser,
1144 WebContents* contents,
1146 const content::PageState& page_state) {
1147 content::RecordAction(UserMetricsAction("ViewSource"));
1150 // Note that Clone does not copy the pending or transient entries, so the
1151 // active entry in view_source_contents will be the last committed entry.
1152 WebContents* view_source_contents = contents->Clone();
1153 DCHECK(view_source_contents->GetController().CanPruneAllButLastCommitted());
1154 view_source_contents->GetController().PruneAllButLastCommitted();
1155 NavigationEntry* active_entry =
1156 view_source_contents->GetController().GetActiveEntry();
1160 GURL view_source_url =
1161 GURL(content::kViewSourceScheme + std::string(":") + url.spec());
1162 active_entry->SetVirtualURL(view_source_url);
1164 // Do not restore scroller position.
1165 active_entry->SetPageState(page_state.RemoveScrollOffset());
1167 // Do not restore title, derive it from the url.
1168 active_entry->SetTitle(base::string16());
1170 // Now show view-source entry.
1171 if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) {
1172 // If this is a tabbed browser, just create a duplicate tab inside the same
1173 // window next to the tab being duplicated.
1174 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents);
1175 int add_types = TabStripModel::ADD_ACTIVE |
1176 TabStripModel::ADD_INHERIT_GROUP;
1177 browser->tab_strip_model()->InsertWebContentsAt(
1179 view_source_contents,
1182 Browser* b = new Browser(
1183 Browser::CreateParams(Browser::TYPE_TABBED, browser->profile(),
1184 browser->host_desktop_type()));
1186 // Preserve the size of the original window. The new window has already
1187 // been given an offset by the OS, so we shouldn't copy the old bounds.
1188 BrowserWindow* new_window = b->window();
1189 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
1190 browser->window()->GetRestoredBounds().size()));
1192 // We need to show the browser now. Otherwise ContainerWin assumes the
1193 // WebContents is invisible and won't size it.
1194 b->window()->Show();
1196 // The page transition below is only for the purpose of inserting the tab.
1197 b->tab_strip_model()->AddWebContents(view_source_contents, -1,
1198 content::PAGE_TRANSITION_LINK,
1199 TabStripModel::ADD_ACTIVE);
1202 SessionService* session_service =
1203 SessionServiceFactory::GetForProfileIfExisting(browser->profile());
1204 if (session_service)
1205 session_service->TabRestored(view_source_contents, false);
1208 void ViewSelectedSource(Browser* browser) {
1209 ViewSource(browser, browser->tab_strip_model()->GetActiveWebContents());
1212 bool CanViewSource(const Browser* browser) {
1213 return !browser->is_devtools() &&
1214 browser->tab_strip_model()->GetActiveWebContents()->GetController().
1218 void CreateApplicationShortcuts(Browser* browser) {
1219 content::RecordAction(UserMetricsAction("CreateShortcut"));
1220 extensions::TabHelper::FromWebContents(
1221 browser->tab_strip_model()->GetActiveWebContents())->
1222 CreateApplicationShortcuts();
1225 void CreateBookmarkAppFromCurrentWebContents(Browser* browser) {
1226 content::RecordAction(UserMetricsAction("CreateHostedApp"));
1227 extensions::TabHelper::FromWebContents(
1228 browser->tab_strip_model()->GetActiveWebContents())->
1229 CreateHostedAppFromWebContents();
1232 bool CanCreateApplicationShortcuts(const Browser* browser) {
1233 return extensions::TabHelper::FromWebContents(
1234 browser->tab_strip_model()->GetActiveWebContents())->
1235 CanCreateApplicationShortcuts();
1238 bool CanCreateBookmarkApp(const Browser* browser) {
1239 return extensions::TabHelper::FromWebContents(
1240 browser->tab_strip_model()->GetActiveWebContents())
1241 ->CanCreateBookmarkApp();
1244 void ConvertTabToAppWindow(Browser* browser,
1245 content::WebContents* contents) {
1246 const GURL& url = contents->GetController().GetActiveEntry()->GetURL();
1247 std::string app_name = web_app::GenerateApplicationNameFromURL(url);
1249 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents);
1251 browser->tab_strip_model()->DetachWebContentsAt(index);
1253 Browser* app_browser = new Browser(
1254 Browser::CreateParams::CreateForApp(app_name,
1255 true /* trusted_source */,
1258 browser->host_desktop_type()));
1259 app_browser->tab_strip_model()->AppendWebContents(contents, true);
1261 contents->GetMutableRendererPrefs()->can_accept_load_drops = false;
1262 contents->GetRenderViewHost()->SyncRendererPrefs();
1263 app_browser->window()->Show();
1266 } // namespace chrome