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