browser_commands.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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. 4 5#include "chrome/browser/ui/browser_commands.h" 6 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/ui/bookmarks/bookmark_prompt_controller.h" 34#include "chrome/browser/ui/bookmarks/bookmark_utils.h" 35#include "chrome/browser/ui/browser.h" 36#include "chrome/browser/ui/browser_command_controller.h" 37#include "chrome/browser/ui/browser_dialogs.h" 38#include "chrome/browser/ui/browser_finder.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/status_bubble.h" 50#include "chrome/browser/ui/tab_contents/core_tab_helper.h" 51#include "chrome/browser/ui/tabs/tab_strip_model.h" 52#include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h" 53#include "chrome/browser/upgrade_detector.h" 54#include "chrome/browser/web_applications/web_app.h" 55#include "chrome/common/chrome_switches.h" 56#include "chrome/common/chrome_version_info.h" 57#include "chrome/common/content_restriction.h" 58#include "chrome/common/pref_names.h" 59#include "components/web_modal/web_contents_modal_dialog_manager.h" 60#include "content/public/browser/devtools_agent_host.h" 61#include "content/public/browser/navigation_controller.h" 62#include "content/public/browser/navigation_entry.h" 63#include "content/public/browser/notification_service.h" 64#include "content/public/browser/page_navigator.h" 65#include "content/public/browser/render_view_host.h" 66#include "content/public/browser/user_metrics.h" 67#include "content/public/browser/web_contents.h" 68#include "content/public/browser/web_contents_view.h" 69#include "content/public/common/renderer_preferences.h" 70#include "content/public/common/url_constants.h" 71#include "content/public/common/url_utils.h" 72#include "net/base/escape.h" 73#include "webkit/common/user_agent/user_agent_util.h" 74 75#if defined(OS_WIN) 76#include "chrome/browser/ui/metro_pin_tab_helper_win.h" 77#include "win8/util/win8_util.h" 78#endif 79 80#if defined(ENABLE_PRINTING) 81#if defined(ENABLE_FULL_PRINTING) 82#include "chrome/browser/printing/print_preview_dialog_controller.h" 83#include "chrome/browser/printing/print_view_manager.h" 84#else 85#include "chrome/browser/printing/print_view_manager_basic.h" 86#endif // defined(ENABLE_FULL_PRINTING) 87#endif // defined(ENABLE_PRINTING) 88 89namespace { 90const char kOsOverrideForTabletSite[] = "Linux; Android 4.0.3"; 91} 92 93using content::NavigationController; 94using content::NavigationEntry; 95using content::OpenURLParams; 96using content::Referrer; 97using content::SSLStatus; 98using content::UserMetricsAction; 99using content::WebContents; 100using web_modal::WebContentsModalDialogManager; 101 102namespace chrome { 103namespace { 104 105void BookmarkCurrentPageInternal(Browser* browser, bool from_star) { 106 content::RecordAction(UserMetricsAction("Star")); 107 108 BookmarkModel* model = 109 BookmarkModelFactory::GetForProfile(browser->profile()); 110 if (!model || !model->loaded()) 111 return; // Ignore requests until bookmarks are loaded. 112 113 GURL url; 114 string16 title; 115 WebContents* web_contents = 116 browser->tab_strip_model()->GetActiveWebContents(); 117 GetURLAndTitleToBookmark(web_contents, &url, &title); 118 bool was_bookmarked = model->IsBookmarked(url); 119 if (!was_bookmarked && web_contents->GetBrowserContext()->IsOffTheRecord()) { 120 // If we're incognito the favicon may not have been saved. Save it now 121 // so that bookmarks have an icon for the page. 122 FaviconTabHelper::FromWebContents(web_contents)->SaveFavicon(); 123 } 124 bookmark_utils::AddIfNotBookmarked(model, url, title); 125 if (from_star && !was_bookmarked) 126 BookmarkPromptController::AddedBookmark(browser, url); 127 // Make sure the model actually added a bookmark before showing the star. A 128 // bookmark isn't created if the url is invalid. 129 if (browser->window()->IsActive() && model->IsBookmarked(url)) { 130 // Only show the bubble if the window is active, otherwise we may get into 131 // weird situations where the bubble is deleted as soon as it is shown. 132 browser->window()->ShowBookmarkBubble(url, was_bookmarked); 133 } 134} 135 136WebContents* GetOrCloneTabForDisposition(Browser* browser, 137 WindowOpenDisposition disposition) { 138 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents(); 139 switch (disposition) { 140 case NEW_FOREGROUND_TAB: 141 case NEW_BACKGROUND_TAB: { 142 current_tab = current_tab->Clone(); 143 browser->tab_strip_model()->AddWebContents( 144 current_tab, -1, content::PAGE_TRANSITION_LINK, 145 disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_ACTIVE : 146 TabStripModel::ADD_NONE); 147 break; 148 } 149 case NEW_WINDOW: { 150 current_tab = current_tab->Clone(); 151 Browser* b = new Browser(Browser::CreateParams( 152 browser->profile(), browser->host_desktop_type())); 153 b->tab_strip_model()->AddWebContents( 154 current_tab, -1, content::PAGE_TRANSITION_LINK, 155 TabStripModel::ADD_ACTIVE); 156 b->window()->Show(); 157 break; 158 } 159 default: 160 break; 161 } 162 return current_tab; 163} 164 165void ReloadInternal(Browser* browser, 166 WindowOpenDisposition disposition, 167 bool ignore_cache) { 168 // As this is caused by a user action, give the focus to the page. 169 // 170 // Also notify RenderViewHostDelegate of the user gesture; this is 171 // normally done in Browser::Navigate, but a reload bypasses Navigate. 172 WebContents* web_contents = GetOrCloneTabForDisposition(browser, disposition); 173 web_contents->UserGestureDone(); 174 if (!web_contents->FocusLocationBarByDefault()) 175 web_contents->GetView()->Focus(); 176 if (ignore_cache) 177 web_contents->GetController().ReloadIgnoringCache(true); 178 else 179 web_contents->GetController().Reload(true); 180} 181 182bool IsShowingWebContentsModalDialog(const Browser* browser) { 183 WebContents* web_contents = 184 browser->tab_strip_model()->GetActiveWebContents(); 185 if (!web_contents) 186 return false; 187 188 WebContentsModalDialogManager* web_contents_modal_dialog_manager = 189 WebContentsModalDialogManager::FromWebContents(web_contents); 190 return web_contents_modal_dialog_manager->IsDialogActive(); 191} 192 193bool PrintPreviewShowing(const Browser* browser) { 194#if defined(ENABLE_FULL_PRINTING) 195 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents(); 196 printing::PrintPreviewDialogController* controller = 197 printing::PrintPreviewDialogController::GetInstance(); 198 return controller && (controller->GetPrintPreviewForContents(contents) || 199 controller->is_creating_print_preview_dialog()); 200#else 201 return false; 202#endif 203} 204 205} // namespace 206 207bool IsCommandEnabled(Browser* browser, int command) { 208 return browser->command_controller()->command_updater()->IsCommandEnabled( 209 command); 210} 211 212bool SupportsCommand(Browser* browser, int command) { 213 return browser->command_controller()->command_updater()->SupportsCommand( 214 command); 215} 216 217bool ExecuteCommand(Browser* browser, int command) { 218 return browser->command_controller()->command_updater()->ExecuteCommand( 219 command); 220} 221 222bool ExecuteCommandWithDisposition(Browser* browser, 223 int command, 224 WindowOpenDisposition disposition) { 225 return browser->command_controller()->command_updater()-> 226 ExecuteCommandWithDisposition(command, disposition); 227} 228 229void UpdateCommandEnabled(Browser* browser, int command, bool enabled) { 230 browser->command_controller()->command_updater()->UpdateCommandEnabled( 231 command, enabled); 232} 233 234void AddCommandObserver(Browser* browser, 235 int command, 236 CommandObserver* observer) { 237 browser->command_controller()->command_updater()->AddCommandObserver( 238 command, observer); 239} 240 241void RemoveCommandObserver(Browser* browser, 242 int command, 243 CommandObserver* observer) { 244 browser->command_controller()->command_updater()->RemoveCommandObserver( 245 command, observer); 246} 247 248int GetContentRestrictions(const Browser* browser) { 249 int content_restrictions = 0; 250 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents(); 251 if (current_tab) { 252 CoreTabHelper* core_tab_helper = 253 CoreTabHelper::FromWebContents(current_tab); 254 content_restrictions = core_tab_helper->content_restrictions(); 255 NavigationEntry* active_entry = 256 current_tab->GetController().GetActiveEntry(); 257 // See comment in UpdateCommandsForTabState about why we call url(). 258 if (!content::IsSavableURL( 259 active_entry ? active_entry->GetURL() : GURL()) || 260 current_tab->ShowingInterstitialPage()) 261 content_restrictions |= CONTENT_RESTRICTION_SAVE; 262 if (current_tab->ShowingInterstitialPage()) 263 content_restrictions |= CONTENT_RESTRICTION_PRINT; 264 } 265 return content_restrictions; 266} 267 268void NewEmptyWindow(Profile* profile, HostDesktopType desktop_type) { 269 bool incognito = profile->IsOffTheRecord(); 270 PrefService* prefs = profile->GetPrefs(); 271 if (incognito) { 272 if (IncognitoModePrefs::GetAvailability(prefs) == 273 IncognitoModePrefs::DISABLED) { 274 incognito = false; 275 } 276 } else { 277 if (browser_defaults::kAlwaysOpenIncognitoWindow && 278 IncognitoModePrefs::ShouldLaunchIncognito( 279 *CommandLine::ForCurrentProcess(), prefs)) { 280 incognito = true; 281 } 282 } 283 284 if (incognito) { 285 content::RecordAction(UserMetricsAction("NewIncognitoWindow")); 286 OpenEmptyWindow(profile->GetOffTheRecordProfile(), desktop_type); 287 } else { 288 content::RecordAction(UserMetricsAction("NewWindow")); 289 SessionService* session_service = 290 SessionServiceFactory::GetForProfile(profile->GetOriginalProfile()); 291 if (!session_service || 292 !session_service->RestoreIfNecessary(std::vector<GURL>())) { 293 OpenEmptyWindow(profile->GetOriginalProfile(), desktop_type); 294 } 295 } 296} 297 298Browser* OpenEmptyWindow(Profile* profile, HostDesktopType desktop_type) { 299 Browser* browser = new Browser( 300 Browser::CreateParams(Browser::TYPE_TABBED, profile, desktop_type)); 301 AddBlankTabAt(browser, -1, true); 302 browser->window()->Show(); 303 return browser; 304} 305 306void OpenWindowWithRestoredTabs(Profile* profile, 307 HostDesktopType host_desktop_type) { 308 TabRestoreService* service = TabRestoreServiceFactory::GetForProfile(profile); 309 if (service) 310 service->RestoreMostRecentEntry(NULL, host_desktop_type); 311} 312 313void OpenURLOffTheRecord(Profile* profile, 314 const GURL& url, 315 chrome::HostDesktopType desktop_type) { 316 Browser* browser = chrome::FindOrCreateTabbedBrowser( 317 profile->GetOffTheRecordProfile(), desktop_type); 318 AddSelectedTabWithURL(browser, url, content::PAGE_TRANSITION_LINK); 319 browser->window()->Show(); 320} 321 322bool CanGoBack(const Browser* browser) { 323 return browser->tab_strip_model()->GetActiveWebContents()-> 324 GetController().CanGoBack(); 325} 326 327void GoBack(Browser* browser, WindowOpenDisposition disposition) { 328 content::RecordAction(UserMetricsAction("Back")); 329 330 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents(); 331 if (CanGoBack(browser)) { 332 WebContents* new_tab = GetOrCloneTabForDisposition(browser, disposition); 333 // If we are on an interstitial page and clone the tab, it won't be copied 334 // to the new tab, so we don't need to go back. 335 if (current_tab->ShowingInterstitialPage() && new_tab != current_tab) 336 return; 337 new_tab->GetController().GoBack(); 338 } 339} 340 341bool CanGoForward(const Browser* browser) { 342 return browser->tab_strip_model()->GetActiveWebContents()-> 343 GetController().CanGoForward(); 344} 345 346void GoForward(Browser* browser, WindowOpenDisposition disposition) { 347 content::RecordAction(UserMetricsAction("Forward")); 348 if (CanGoForward(browser)) { 349 GetOrCloneTabForDisposition(browser, disposition)-> 350 GetController().GoForward(); 351 } 352} 353 354bool NavigateToIndexWithDisposition(Browser* browser, 355 int index, 356 WindowOpenDisposition disp) { 357 NavigationController& controller = 358 GetOrCloneTabForDisposition(browser, disp)->GetController(); 359 if (index < 0 || index >= controller.GetEntryCount()) 360 return false; 361 controller.GoToIndex(index); 362 return true; 363} 364 365void Reload(Browser* browser, WindowOpenDisposition disposition) { 366 content::RecordAction(UserMetricsAction("Reload")); 367 ReloadInternal(browser, disposition, false); 368} 369 370void ReloadIgnoringCache(Browser* browser, WindowOpenDisposition disposition) { 371 content::RecordAction(UserMetricsAction("ReloadIgnoringCache")); 372 ReloadInternal(browser, disposition, true); 373} 374 375bool CanReload(const Browser* browser) { 376 return !browser->is_devtools(); 377} 378 379void Home(Browser* browser, WindowOpenDisposition disposition) { 380 content::RecordAction(UserMetricsAction("Home")); 381 382 std::string extra_headers; 383#if defined(ENABLE_RLZ) 384 // If the home page is a Google home page, add the RLZ header to the request. 385 PrefService* pref_service = browser->profile()->GetPrefs(); 386 if (pref_service) { 387 if (google_util::IsGoogleHomePageUrl( 388 GURL(pref_service->GetString(prefs::kHomePage)))) { 389 extra_headers = RLZTracker::GetAccessPointHttpHeader( 390 RLZTracker::CHROME_HOME_PAGE); 391 } 392 } 393#endif 394 395 OpenURLParams params( 396 browser->profile()->GetHomePage(), Referrer(), disposition, 397 content::PageTransitionFromInt( 398 content::PAGE_TRANSITION_AUTO_BOOKMARK | 399 content::PAGE_TRANSITION_HOME_PAGE), 400 false); 401 params.extra_headers = extra_headers; 402 browser->OpenURL(params); 403} 404 405void OpenCurrentURL(Browser* browser) { 406 content::RecordAction(UserMetricsAction("LoadURL")); 407 LocationBar* location_bar = browser->window()->GetLocationBar(); 408 if (!location_bar) 409 return; 410 411 GURL url(location_bar->GetDestinationURL()); 412 413 content::PageTransition page_transition = location_bar->GetPageTransition(); 414 content::PageTransition page_transition_without_qualifier( 415 PageTransitionStripQualifier(page_transition)); 416 WindowOpenDisposition open_disposition = 417 location_bar->GetWindowOpenDisposition(); 418 // A PAGE_TRANSITION_TYPED means the user has typed a URL. We do not want to 419 // open URLs with instant_controller since in some cases it disregards it 420 // and performs a search instead. For example, when using CTRL-Enter, the 421 // location_bar is aware of the URL but instant is not. 422 // Instant should also not handle PAGE_TRANSITION_RELOAD because its knowledge 423 // of the omnibox text may be stale if the user focuses in the omnibox and 424 // presses enter without typing anything. 425 if (page_transition_without_qualifier != content::PAGE_TRANSITION_TYPED && 426 page_transition_without_qualifier != content::PAGE_TRANSITION_RELOAD && 427 browser->instant_controller() && 428 browser->instant_controller()->OpenInstant(open_disposition, url)) 429 return; 430 431 NavigateParams params(browser, url, page_transition); 432 params.disposition = open_disposition; 433 // Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least 434 // inherit the opener. In some cases the tabstrip will determine the group 435 // should be inherited, in which case the group is inherited instead of the 436 // opener. 437 params.tabstrip_add_types = 438 TabStripModel::ADD_FORCE_INDEX | TabStripModel::ADD_INHERIT_OPENER; 439 Navigate(¶ms); 440 441 DCHECK(browser->profile()->GetExtensionService()); 442 const extensions::Extension* extension = 443 browser->profile()->GetExtensionService()->GetInstalledApp(url); 444 if (extension) { 445 CoreAppLauncherHandler::RecordAppLaunchType( 446 extension_misc::APP_LAUNCH_OMNIBOX_LOCATION, 447 extension->GetType()); 448 } 449} 450 451void Stop(Browser* browser) { 452 content::RecordAction(UserMetricsAction("Stop")); 453 browser->tab_strip_model()->GetActiveWebContents()->Stop(); 454} 455 456#if !defined(OS_WIN) 457void NewWindow(Browser* browser) { 458 NewEmptyWindow(browser->profile()->GetOriginalProfile(), 459 browser->host_desktop_type()); 460} 461 462void NewIncognitoWindow(Browser* browser) { 463 NewEmptyWindow(browser->profile()->GetOffTheRecordProfile(), 464 browser->host_desktop_type()); 465} 466#endif // OS_WIN 467 468void CloseWindow(Browser* browser) { 469 content::RecordAction(UserMetricsAction("CloseWindow")); 470 browser->window()->Close(); 471} 472 473void NewTab(Browser* browser) { 474 content::RecordAction(UserMetricsAction("NewTab")); 475 // TODO(asvitkine): This is invoked programmatically from several places. 476 // Audit the code and change it so that the histogram only gets collected for 477 // user-initiated commands. 478 UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", TabStripModel::NEW_TAB_COMMAND, 479 TabStripModel::NEW_TAB_ENUM_COUNT); 480 481 if (browser->is_type_tabbed()) { 482 AddBlankTabAt(browser, -1, true); 483 browser->tab_strip_model()->GetActiveWebContents()->GetView()-> 484 RestoreFocus(); 485 } else { 486 Browser* b = 487 chrome::FindOrCreateTabbedBrowser(browser->profile(), 488 browser->host_desktop_type()); 489 AddBlankTabAt(b, -1, true); 490 b->window()->Show(); 491 // The call to AddBlankTabAt above did not set the focus to the tab as its 492 // window was not active, so we have to do it explicitly. 493 // See http://crbug.com/6380. 494 b->tab_strip_model()->GetActiveWebContents()->GetView()->RestoreFocus(); 495 } 496} 497 498void CloseTab(Browser* browser) { 499 content::RecordAction(UserMetricsAction("CloseTab_Accelerator")); 500 browser->tab_strip_model()->CloseSelectedTabs(); 501} 502 503void RestoreTab(Browser* browser) { 504 content::RecordAction(UserMetricsAction("RestoreTab")); 505 TabRestoreService* service = 506 TabRestoreServiceFactory::GetForProfile(browser->profile()); 507 if (service) 508 service->RestoreMostRecentEntry(browser->tab_restore_service_delegate(), 509 browser->host_desktop_type()); 510} 511 512TabStripModelDelegate::RestoreTabType GetRestoreTabType( 513 const Browser* browser) { 514 TabRestoreService* service = 515 TabRestoreServiceFactory::GetForProfile(browser->profile()); 516 if (!service || service->entries().empty()) 517 return TabStripModelDelegate::RESTORE_NONE; 518 if (service->entries().front()->type == TabRestoreService::WINDOW) 519 return TabStripModelDelegate::RESTORE_WINDOW; 520 return TabStripModelDelegate::RESTORE_TAB; 521} 522 523void SelectNextTab(Browser* browser) { 524 content::RecordAction(UserMetricsAction("SelectNextTab")); 525 browser->tab_strip_model()->SelectNextTab(); 526} 527 528void SelectPreviousTab(Browser* browser) { 529 content::RecordAction(UserMetricsAction("SelectPrevTab")); 530 browser->tab_strip_model()->SelectPreviousTab(); 531} 532 533void OpenTabpose(Browser* browser) { 534#if defined(OS_MACOSX) 535 if (!CommandLine::ForCurrentProcess()->HasSwitch( 536 switches::kEnableExposeForTabs)) { 537 return; 538 } 539 540 content::RecordAction(UserMetricsAction("OpenTabpose")); 541 browser->window()->OpenTabpose(); 542#else 543 NOTREACHED(); 544#endif 545} 546 547void MoveTabNext(Browser* browser) { 548 content::RecordAction(UserMetricsAction("MoveTabNext")); 549 browser->tab_strip_model()->MoveTabNext(); 550} 551 552void MoveTabPrevious(Browser* browser) { 553 content::RecordAction(UserMetricsAction("MoveTabPrevious")); 554 browser->tab_strip_model()->MoveTabPrevious(); 555} 556 557void SelectNumberedTab(Browser* browser, int index) { 558 if (index < browser->tab_strip_model()->count()) { 559 content::RecordAction(UserMetricsAction("SelectNumberedTab")); 560 browser->tab_strip_model()->ActivateTabAt(index, true); 561 } 562} 563 564void SelectLastTab(Browser* browser) { 565 content::RecordAction(UserMetricsAction("SelectLastTab")); 566 browser->tab_strip_model()->SelectLastTab(); 567} 568 569void DuplicateTab(Browser* browser) { 570 content::RecordAction(UserMetricsAction("Duplicate")); 571 DuplicateTabAt(browser, browser->tab_strip_model()->active_index()); 572} 573 574bool CanDuplicateTab(const Browser* browser) { 575 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents(); 576 return contents && contents->GetController().GetLastCommittedEntry(); 577} 578 579WebContents* DuplicateTabAt(Browser* browser, int index) { 580 WebContents* contents = browser->tab_strip_model()->GetWebContentsAt(index); 581 CHECK(contents); 582 WebContents* contents_dupe = contents->Clone(); 583 584 bool pinned = false; 585 if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) { 586 // If this is a tabbed browser, just create a duplicate tab inside the same 587 // window next to the tab being duplicated. 588 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents); 589 pinned = browser->tab_strip_model()->IsTabPinned(index); 590 int add_types = TabStripModel::ADD_ACTIVE | 591 TabStripModel::ADD_INHERIT_GROUP | 592 (pinned ? TabStripModel::ADD_PINNED : 0); 593 browser->tab_strip_model()->InsertWebContentsAt( 594 index + 1, contents_dupe, add_types); 595 } else { 596 Browser* new_browser = NULL; 597 if (browser->is_app() && 598 !browser->is_type_popup()) { 599 new_browser = new Browser( 600 Browser::CreateParams::CreateForApp(browser->type(), 601 browser->app_name(), 602 gfx::Rect(), 603 browser->profile(), 604 browser->host_desktop_type())); 605 } else { 606 new_browser = new Browser( 607 Browser::CreateParams(browser->type(), browser->profile(), 608 browser->host_desktop_type())); 609 } 610 // Preserve the size of the original window. The new window has already 611 // been given an offset by the OS, so we shouldn't copy the old bounds. 612 BrowserWindow* new_window = new_browser->window(); 613 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(), 614 browser->window()->GetRestoredBounds().size())); 615 616 // We need to show the browser now. Otherwise ContainerWin assumes the 617 // WebContents is invisible and won't size it. 618 new_browser->window()->Show(); 619 620 // The page transition below is only for the purpose of inserting the tab. 621 new_browser->tab_strip_model()->AddWebContents( 622 contents_dupe, -1, 623 content::PAGE_TRANSITION_LINK, 624 TabStripModel::ADD_ACTIVE); 625 } 626 627 SessionService* session_service = 628 SessionServiceFactory::GetForProfileIfExisting(browser->profile()); 629 if (session_service) 630 session_service->TabRestored(contents_dupe, pinned); 631 return contents_dupe; 632} 633 634bool CanDuplicateTabAt(Browser* browser, int index) { 635 content::NavigationController& nc = 636 browser->tab_strip_model()->GetWebContentsAt(index)->GetController(); 637 return nc.GetWebContents() && nc.GetLastCommittedEntry(); 638} 639 640void ConvertPopupToTabbedBrowser(Browser* browser) { 641 content::RecordAction(UserMetricsAction("ShowAsTab")); 642 TabStripModel* tab_strip = browser->tab_strip_model(); 643 WebContents* contents = 644 tab_strip->DetachWebContentsAt(tab_strip->active_index()); 645 Browser* b = new Browser(Browser::CreateParams(browser->profile(), 646 browser->host_desktop_type())); 647 b->tab_strip_model()->AppendWebContents(contents, true); 648 b->window()->Show(); 649} 650 651void Exit() { 652 content::RecordAction(UserMetricsAction("Exit")); 653 chrome::AttemptUserExit(); 654} 655 656void BookmarkCurrentPage(Browser* browser) { 657 BookmarkCurrentPageInternal(browser, false); 658} 659 660void BookmarkCurrentPageFromStar(Browser* browser) { 661 BookmarkCurrentPageInternal(browser, true); 662} 663 664bool CanBookmarkCurrentPage(const Browser* browser) { 665 BookmarkModel* model = 666 BookmarkModelFactory::GetForProfile(browser->profile()); 667 return browser_defaults::bookmarks_enabled && 668 browser->profile()->GetPrefs()->GetBoolean( 669 prefs::kEditBookmarksEnabled) && 670 model && model->loaded() && browser->is_type_tabbed(); 671} 672 673void BookmarkAllTabs(Browser* browser) { 674 chrome::ShowBookmarkAllTabsDialog(browser); 675} 676 677bool CanBookmarkAllTabs(const Browser* browser) { 678 return browser->tab_strip_model()->count() > 1 && 679 CanBookmarkCurrentPage(browser); 680} 681 682void TogglePagePinnedToStartScreen(Browser* browser) { 683#if defined(OS_WIN) 684 MetroPinTabHelper::FromWebContents( 685 browser->tab_strip_model()->GetActiveWebContents())-> 686 TogglePinnedToStartScreen(); 687#endif 688} 689 690void SavePage(Browser* browser) { 691 content::RecordAction(UserMetricsAction("SavePage")); 692 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents(); 693 if (current_tab && current_tab->GetContentsMimeType() == "application/pdf") 694 content::RecordAction(UserMetricsAction("PDF.SavePage")); 695 current_tab->OnSavePage(); 696} 697 698bool CanSavePage(const Browser* browser) { 699 // LocalState can be NULL in tests. 700 if (g_browser_process->local_state() && 701 !g_browser_process->local_state()->GetBoolean( 702 prefs::kAllowFileSelectionDialogs)) { 703 return false; 704 } 705 return !browser->is_devtools() && 706 !(GetContentRestrictions(browser) & CONTENT_RESTRICTION_SAVE); 707} 708 709void ShowFindBar(Browser* browser) { 710 browser->GetFindBarController()->Show(); 711} 712 713void ShowWebsiteSettings(Browser* browser, 714 content::WebContents* web_contents, 715 const GURL& url, 716 const SSLStatus& ssl) { 717 browser->window()->ShowWebsiteSettings( 718 Profile::FromBrowserContext(web_contents->GetBrowserContext()), 719 web_contents, url, ssl); 720} 721 722 723void Print(Browser* browser) { 724#if defined(ENABLE_PRINTING) 725 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents(); 726#if defined(ENABLE_FULL_PRINTING) 727 printing::PrintViewManager* print_view_manager = 728 printing::PrintViewManager::FromWebContents(contents); 729 if (browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintPreviewDisabled)) 730 print_view_manager->PrintNow(); 731 else 732 print_view_manager->PrintPreviewNow(false); 733#else 734 printing::PrintViewManagerBasic* print_view_manager = 735 printing::PrintViewManagerBasic::FromWebContents(contents); 736 print_view_manager->PrintNow(); 737#endif // defined(ENABLE_FULL_PRINTING) 738#endif // defined(ENABLE_PRINTING) 739} 740 741bool CanPrint(const Browser* browser) { 742 // Do not print when printing is disabled via pref or policy. 743 // Do not print when a constrained window is showing. It's confusing. 744 return browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) && 745 !(IsShowingWebContentsModalDialog(browser) || 746 GetContentRestrictions(browser) & CONTENT_RESTRICTION_PRINT); 747} 748 749void AdvancedPrint(Browser* browser) { 750#if defined(ENABLE_FULL_PRINTING) 751 printing::PrintViewManager* print_view_manager = 752 printing::PrintViewManager::FromWebContents( 753 browser->tab_strip_model()->GetActiveWebContents()); 754 print_view_manager->AdvancedPrintNow(); 755#endif 756} 757 758bool CanAdvancedPrint(const Browser* browser) { 759 // If printing is not disabled via pref or policy, it is always possible to 760 // advanced print when the print preview is visible. The exception to this 761 // is under Win8 ash, since showing the advanced print dialog will open it 762 // modally on the Desktop and hang the browser. We can remove this check 763 // once we integrate with the system print charm. 764#if defined(OS_WIN) 765 if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH) 766 return false; 767#endif 768 769 return browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) && 770 (PrintPreviewShowing(browser) || CanPrint(browser)); 771} 772 773void PrintToDestination(Browser* browser) { 774#if defined(ENABLE_FULL_PRINTING) 775 printing::PrintViewManager* print_view_manager = 776 printing::PrintViewManager::FromWebContents( 777 browser->tab_strip_model()->GetActiveWebContents()); 778 print_view_manager->PrintToDestination(); 779#endif 780} 781 782void EmailPageLocation(Browser* browser) { 783 content::RecordAction(UserMetricsAction("EmailPageLocation")); 784 WebContents* wc = browser->tab_strip_model()->GetActiveWebContents(); 785 DCHECK(wc); 786 787 std::string title = net::EscapeQueryParamValue( 788 UTF16ToUTF8(wc->GetTitle()), false); 789 std::string page_url = net::EscapeQueryParamValue(wc->GetURL().spec(), false); 790 std::string mailto = std::string("mailto:?subject=Fwd:%20") + 791 title + "&body=%0A%0A" + page_url; 792 platform_util::OpenExternal(GURL(mailto)); 793} 794 795bool CanEmailPageLocation(const Browser* browser) { 796 return browser->toolbar_model()->ShouldDisplayURL() && 797 browser->tab_strip_model()->GetActiveWebContents()->GetURL().is_valid(); 798} 799 800void Cut(Browser* browser) { 801 content::RecordAction(UserMetricsAction("Cut")); 802 browser->window()->Cut(); 803} 804 805void Copy(Browser* browser) { 806 content::RecordAction(UserMetricsAction("Copy")); 807 browser->window()->Copy(); 808} 809 810void Paste(Browser* browser) { 811 content::RecordAction(UserMetricsAction("Paste")); 812 browser->window()->Paste(); 813} 814 815void Find(Browser* browser) { 816 content::RecordAction(UserMetricsAction("Find")); 817 FindInPage(browser, false, false); 818} 819 820void FindNext(Browser* browser) { 821 content::RecordAction(UserMetricsAction("FindNext")); 822 FindInPage(browser, true, true); 823} 824 825void FindPrevious(Browser* browser) { 826 content::RecordAction(UserMetricsAction("FindPrevious")); 827 FindInPage(browser, true, false); 828} 829 830void FindInPage(Browser* browser, bool find_next, bool forward_direction) { 831 ShowFindBar(browser); 832 if (find_next) { 833 string16 find_text; 834 FindTabHelper* find_helper = FindTabHelper::FromWebContents( 835 browser->tab_strip_model()->GetActiveWebContents()); 836#if defined(OS_MACOSX) 837 // We always want to search for the current contents of the find bar on 838 // OS X. For regular profile it's always the current find pboard. For 839 // Incognito window it's the newest value of the find pboard content and 840 // user-typed text. 841 FindBar* find_bar = browser->GetFindBarController()->find_bar(); 842 find_text = find_bar->GetFindText(); 843#endif 844 find_helper->StartFinding(find_text, forward_direction, false); 845 } 846} 847 848void Zoom(Browser* browser, content::PageZoom zoom) { 849 if (browser->is_devtools()) 850 return; 851 852 chrome_page_zoom::Zoom(browser->tab_strip_model()->GetActiveWebContents(), 853 zoom); 854} 855 856void FocusToolbar(Browser* browser) { 857 content::RecordAction(UserMetricsAction("FocusToolbar")); 858 browser->window()->FocusToolbar(); 859} 860 861void FocusLocationBar(Browser* browser) { 862 content::RecordAction(UserMetricsAction("FocusLocation")); 863 browser->window()->SetFocusToLocationBar(true); 864} 865 866void FocusSearch(Browser* browser) { 867 // TODO(beng): replace this with FocusLocationBar 868 content::RecordAction(UserMetricsAction("FocusSearch")); 869 browser->window()->GetLocationBar()->FocusSearch(); 870} 871 872void FocusAppMenu(Browser* browser) { 873 content::RecordAction(UserMetricsAction("FocusAppMenu")); 874 browser->window()->FocusAppMenu(); 875} 876 877void FocusBookmarksToolbar(Browser* browser) { 878 content::RecordAction(UserMetricsAction("FocusBookmarksToolbar")); 879 browser->window()->FocusBookmarksToolbar(); 880} 881 882void FocusInfobars(Browser* browser) { 883 content::RecordAction(UserMetricsAction("FocusInfobars")); 884 browser->window()->FocusInfobars(); 885} 886 887void FocusNextPane(Browser* browser) { 888 content::RecordAction(UserMetricsAction("FocusNextPane")); 889 browser->window()->RotatePaneFocus(true); 890} 891 892void FocusPreviousPane(Browser* browser) { 893 content::RecordAction(UserMetricsAction("FocusPreviousPane")); 894 browser->window()->RotatePaneFocus(false); 895} 896 897void ToggleDevToolsWindow(Browser* browser, DevToolsToggleAction action) { 898 if (action == DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE) 899 content::RecordAction(UserMetricsAction("DevTools_ToggleConsole")); 900 else 901 content::RecordAction(UserMetricsAction("DevTools_ToggleWindow")); 902 DevToolsWindow::ToggleDevToolsWindow(browser, action); 903} 904 905bool CanOpenTaskManager() { 906#if defined(OS_WIN) 907 // In metro we can't display the task manager, as it is a native window. 908 return !win8::IsSingleWindowMetroMode(); 909#else 910 return true; 911#endif 912} 913 914void OpenTaskManager(Browser* browser) { 915 content::RecordAction(UserMetricsAction("TaskManager")); 916 chrome::ShowTaskManager(browser); 917} 918 919void OpenFeedbackDialog(Browser* browser) { 920 content::RecordAction(UserMetricsAction("Feedback")); 921 chrome::ShowFeedbackPage(browser, std::string(), std::string()); 922} 923 924void ToggleBookmarkBar(Browser* browser) { 925 content::RecordAction(UserMetricsAction("ShowBookmarksBar")); 926 ToggleBookmarkBarWhenVisible(browser->profile()); 927} 928 929void ShowAppMenu(Browser* browser) { 930 // We record the user metric for this event in WrenchMenu::RunMenu. 931 browser->window()->ShowAppMenu(); 932} 933 934void ShowAvatarMenu(Browser* browser) { 935 browser->window()->ShowAvatarBubbleFromAvatarButton(); 936} 937 938void OpenUpdateChromeDialog(Browser* browser) { 939 if (UpgradeDetector::GetInstance()->is_outdated_install()) { 940 content::NotificationService::current()->Notify( 941 chrome::NOTIFICATION_OUTDATED_INSTALL, 942 content::NotificationService::AllSources(), 943 content::NotificationService::NoDetails()); 944 } else { 945 content::RecordAction(UserMetricsAction("UpdateChrome")); 946 browser->window()->ShowUpdateChromeDialog(); 947 } 948} 949 950void ToggleSpeechInput(Browser* browser) { 951 browser->tab_strip_model()->GetActiveWebContents()-> 952 GetRenderViewHost()->ToggleSpeechInput(); 953 if (browser->instant_controller()) 954 browser->instant_controller()->ToggleVoiceSearch(); 955} 956 957bool CanRequestTabletSite(WebContents* current_tab) { 958 if (!current_tab) 959 return false; 960 return current_tab->GetController().GetActiveEntry() != NULL; 961} 962 963bool IsRequestingTabletSite(Browser* browser) { 964 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents(); 965 if (!current_tab) 966 return false; 967 content::NavigationEntry* entry = 968 current_tab->GetController().GetActiveEntry(); 969 if (!entry) 970 return false; 971 return entry->GetIsOverridingUserAgent(); 972} 973 974void ToggleRequestTabletSite(Browser* browser) { 975 WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents(); 976 if (!current_tab) 977 return; 978 NavigationController& controller = current_tab->GetController(); 979 NavigationEntry* entry = controller.GetActiveEntry(); 980 if (!entry) 981 return; 982 if (entry->GetIsOverridingUserAgent()) { 983 entry->SetIsOverridingUserAgent(false); 984 } else { 985 entry->SetIsOverridingUserAgent(true); 986 chrome::VersionInfo version_info; 987 std::string product; 988 if (version_info.is_valid()) 989 product = version_info.ProductNameAndVersionForUserAgent(); 990 current_tab->SetUserAgentOverride( 991 webkit_glue::BuildUserAgentFromOSAndProduct( 992 kOsOverrideForTabletSite, product)); 993 } 994 controller.ReloadOriginalRequestURL(true); 995} 996 997void ToggleFullscreenMode(Browser* browser) { 998 browser->fullscreen_controller()->ToggleFullscreenMode(); 999} 1000 1001void ClearCache(Browser* browser) { 1002 BrowsingDataRemover* remover = 1003 BrowsingDataRemover::CreateForUnboundedRange(browser->profile()); 1004 remover->Remove(BrowsingDataRemover::REMOVE_CACHE, 1005 BrowsingDataHelper::UNPROTECTED_WEB); 1006 // BrowsingDataRemover takes care of deleting itself when done. 1007} 1008 1009bool IsDebuggerAttachedToCurrentTab(Browser* browser) { 1010 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents(); 1011 return contents ? 1012 content::DevToolsAgentHost::IsDebuggerAttached(contents) : false; 1013} 1014 1015void ViewSource(Browser* browser, WebContents* contents) { 1016 DCHECK(contents); 1017 1018 // Use the last committed entry, since the pending entry hasn't loaded yet and 1019 // won't be copied into the cloned tab. 1020 NavigationEntry* entry = contents->GetController().GetLastCommittedEntry(); 1021 if (!entry) 1022 return; 1023 1024 ViewSource(browser, contents, entry->GetURL(), entry->GetPageState()); 1025} 1026 1027void ViewSource(Browser* browser, 1028 WebContents* contents, 1029 const GURL& url, 1030 const content::PageState& page_state) { 1031 content::RecordAction(UserMetricsAction("ViewSource")); 1032 DCHECK(contents); 1033 1034 // Note that Clone does not copy the pending or transient entries, so the 1035 // active entry in view_source_contents will be the last committed entry. 1036 WebContents* view_source_contents = contents->Clone(); 1037 DCHECK(view_source_contents->GetController().CanPruneAllButVisible()); 1038 view_source_contents->GetController().PruneAllButVisible(); 1039 NavigationEntry* active_entry = 1040 view_source_contents->GetController().GetActiveEntry(); 1041 if (!active_entry) 1042 return; 1043 1044 GURL view_source_url = 1045 GURL(content::kViewSourceScheme + std::string(":") + url.spec()); 1046 active_entry->SetVirtualURL(view_source_url); 1047 1048 // Do not restore scroller position. 1049 active_entry->SetPageState(page_state.RemoveScrollOffset()); 1050 1051 // Do not restore title, derive it from the url. 1052 active_entry->SetTitle(string16()); 1053 1054 // Now show view-source entry. 1055 if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) { 1056 // If this is a tabbed browser, just create a duplicate tab inside the same 1057 // window next to the tab being duplicated. 1058 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents); 1059 int add_types = TabStripModel::ADD_ACTIVE | 1060 TabStripModel::ADD_INHERIT_GROUP; 1061 browser->tab_strip_model()->InsertWebContentsAt( 1062 index + 1, 1063 view_source_contents, 1064 add_types); 1065 } else { 1066 Browser* b = new Browser( 1067 Browser::CreateParams(Browser::TYPE_TABBED, browser->profile(), 1068 browser->host_desktop_type())); 1069 1070 // Preserve the size of the original window. The new window has already 1071 // been given an offset by the OS, so we shouldn't copy the old bounds. 1072 BrowserWindow* new_window = b->window(); 1073 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(), 1074 browser->window()->GetRestoredBounds().size())); 1075 1076 // We need to show the browser now. Otherwise ContainerWin assumes the 1077 // WebContents is invisible and won't size it. 1078 b->window()->Show(); 1079 1080 // The page transition below is only for the purpose of inserting the tab. 1081 b->tab_strip_model()->AddWebContents(view_source_contents, -1, 1082 content::PAGE_TRANSITION_LINK, 1083 TabStripModel::ADD_ACTIVE); 1084 } 1085 1086 SessionService* session_service = 1087 SessionServiceFactory::GetForProfileIfExisting(browser->profile()); 1088 if (session_service) 1089 session_service->TabRestored(view_source_contents, false); 1090} 1091 1092void ViewSelectedSource(Browser* browser) { 1093 ViewSource(browser, browser->tab_strip_model()->GetActiveWebContents()); 1094} 1095 1096bool CanViewSource(const Browser* browser) { 1097 return browser->tab_strip_model()->GetActiveWebContents()-> 1098 GetController().CanViewSource(); 1099} 1100 1101void CreateApplicationShortcuts(Browser* browser) { 1102 content::RecordAction(UserMetricsAction("CreateShortcut")); 1103 extensions::TabHelper::FromWebContents( 1104 browser->tab_strip_model()->GetActiveWebContents())-> 1105 CreateApplicationShortcuts(); 1106} 1107 1108bool CanCreateApplicationShortcuts(const Browser* browser) { 1109 return extensions::TabHelper::FromWebContents( 1110 browser->tab_strip_model()->GetActiveWebContents())-> 1111 CanCreateApplicationShortcuts(); 1112} 1113 1114void ConvertTabToAppWindow(Browser* browser, 1115 content::WebContents* contents) { 1116 const GURL& url = contents->GetController().GetActiveEntry()->GetURL(); 1117 std::string app_name = web_app::GenerateApplicationNameFromURL(url); 1118 1119 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents); 1120 if (index >= 0) 1121 browser->tab_strip_model()->DetachWebContentsAt(index); 1122 1123 Browser* app_browser = new Browser( 1124 Browser::CreateParams::CreateForApp( 1125 Browser::TYPE_POPUP, app_name, gfx::Rect(), browser->profile(), 1126 browser->host_desktop_type())); 1127 app_browser->tab_strip_model()->AppendWebContents(contents, true); 1128 1129 contents->GetMutableRendererPrefs()->can_accept_load_drops = false; 1130 contents->GetRenderViewHost()->SyncRendererPrefs(); 1131 app_browser->window()->Show(); 1132} 1133 1134} // namespace chrome 1135