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