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