- add sources.
[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/sessions/session_service_factory.h"
30 #include "chrome/browser/sessions/tab_restore_service.h"
31 #include "chrome/browser/sessions/tab_restore_service_delegate.h"
32 #include "chrome/browser/sessions/tab_restore_service_factory.h"
33 #include "chrome/browser/translate/translate_tab_helper.h"
34 #include "chrome/browser/ui/bookmarks/bookmark_prompt_controller.h"
35 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
36 #include "chrome/browser/ui/browser.h"
37 #include "chrome/browser/ui/browser_command_controller.h"
38 #include "chrome/browser/ui/browser_dialogs.h"
39 #include "chrome/browser/ui/browser_instant_controller.h"
40 #include "chrome/browser/ui/browser_tab_restore_service_delegate.h"
41 #include "chrome/browser/ui/browser_tabstrip.h"
42 #include "chrome/browser/ui/browser_window.h"
43 #include "chrome/browser/ui/chrome_pages.h"
44 #include "chrome/browser/ui/find_bar/find_bar.h"
45 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
46 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
47 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
48 #include "chrome/browser/ui/omnibox/location_bar.h"
49 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
50 #include "chrome/browser/ui/status_bubble.h"
51 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
52 #include "chrome/browser/ui/tabs/tab_strip_model.h"
53 #include "chrome/browser/ui/translate/translate_bubble_model.h"
54 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
55 #include "chrome/browser/upgrade_detector.h"
56 #include "chrome/browser/web_applications/web_app.h"
57 #include "chrome/common/chrome_switches.h"
58 #include "chrome/common/chrome_version_info.h"
59 #include "chrome/common/content_restriction.h"
60 #include "chrome/common/pref_names.h"
61 #include "components/web_modal/web_contents_modal_dialog_manager.h"
62 #include "content/public/browser/devtools_agent_host.h"
63 #include "content/public/browser/navigation_controller.h"
64 #include "content/public/browser/navigation_entry.h"
65 #include "content/public/browser/notification_service.h"
66 #include "content/public/browser/page_navigator.h"
67 #include "content/public/browser/render_view_host.h"
68 #include "content/public/browser/user_metrics.h"
69 #include "content/public/browser/web_contents.h"
70 #include "content/public/browser/web_contents_view.h"
71 #include "content/public/common/renderer_preferences.h"
72 #include "content/public/common/url_constants.h"
73 #include "content/public/common/url_utils.h"
74 #include "net/base/escape.h"
75 #include "webkit/common/user_agent/user_agent_util.h"
76
77 #if defined(OS_WIN)
78 #include "chrome/browser/ui/metro_pin_tab_helper_win.h"
79 #include "win8/util/win8_util.h"
80 #endif
81
82 #if defined(ENABLE_PRINTING)
83 #if defined(ENABLE_FULL_PRINTING)
84 #include "chrome/browser/printing/print_preview_dialog_controller.h"
85 #include "chrome/browser/printing/print_view_manager.h"
86 #else
87 #include "chrome/browser/printing/print_view_manager_basic.h"
88 #endif  // defined(ENABLE_FULL_PRINTING)
89 #endif  // defined(ENABLE_PRINTING)
90
91 namespace {
92 const char kOsOverrideForTabletSite[] = "Linux; Android 4.0.3";
93 }
94
95 using content::NavigationController;
96 using content::NavigationEntry;
97 using content::OpenURLParams;
98 using content::Referrer;
99 using content::SSLStatus;
100 using content::UserMetricsAction;
101 using content::WebContents;
102 using web_modal::WebContentsModalDialogManager;
103
104 namespace chrome {
105 namespace {
106
107 void BookmarkCurrentPageInternal(Browser* browser, bool from_star) {
108   content::RecordAction(UserMetricsAction("Star"));
109
110   BookmarkModel* model =
111       BookmarkModelFactory::GetForProfile(browser->profile());
112   if (!model || !model->loaded())
113     return;  // Ignore requests until bookmarks are loaded.
114
115   GURL url;
116   string16 title;
117   WebContents* web_contents =
118       browser->tab_strip_model()->GetActiveWebContents();
119   GetURLAndTitleToBookmark(web_contents, &url, &title);
120   bool was_bookmarked = model->IsBookmarked(url);
121   if (!was_bookmarked && web_contents->GetBrowserContext()->IsOffTheRecord()) {
122     // If we're incognito the favicon may not have been saved. Save it now
123     // so that bookmarks have an icon for the page.
124     FaviconTabHelper::FromWebContents(web_contents)->SaveFavicon();
125   }
126   bookmark_utils::AddIfNotBookmarked(model, url, title);
127   if (from_star && !was_bookmarked)
128     BookmarkPromptController::AddedBookmark(browser, url);
129   // Make sure the model actually added a bookmark before showing the star. A
130   // bookmark isn't created if the url is invalid.
131   if (browser->window()->IsActive() && model->IsBookmarked(url)) {
132     // Only show the bubble if the window is active, otherwise we may get into
133     // weird situations where the bubble is deleted as soon as it is shown.
134     browser->window()->ShowBookmarkBubble(url, was_bookmarked);
135   }
136 }
137
138 WebContents* GetOrCloneTabForDisposition(Browser* browser,
139                                          WindowOpenDisposition disposition) {
140   WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
141   switch (disposition) {
142     case NEW_FOREGROUND_TAB:
143     case NEW_BACKGROUND_TAB: {
144       current_tab = current_tab->Clone();
145       browser->tab_strip_model()->AddWebContents(
146           current_tab, -1, content::PAGE_TRANSITION_LINK,
147           disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_ACTIVE :
148                                               TabStripModel::ADD_NONE);
149       break;
150     }
151     case NEW_WINDOW: {
152       current_tab = current_tab->Clone();
153       Browser* b = new Browser(Browser::CreateParams(
154           browser->profile(), browser->host_desktop_type()));
155       b->tab_strip_model()->AddWebContents(
156           current_tab, -1, content::PAGE_TRANSITION_LINK,
157           TabStripModel::ADD_ACTIVE);
158       b->window()->Show();
159       break;
160     }
161     default:
162       break;
163   }
164   return current_tab;
165 }
166
167 void ReloadInternal(Browser* browser,
168                     WindowOpenDisposition disposition,
169                     bool ignore_cache) {
170   // As this is caused by a user action, give the focus to the page.
171   //
172   // Also notify RenderViewHostDelegate of the user gesture; this is
173   // normally done in Browser::Navigate, but a reload bypasses Navigate.
174   WebContents* web_contents = GetOrCloneTabForDisposition(browser, disposition);
175   web_contents->UserGestureDone();
176   if (!web_contents->FocusLocationBarByDefault())
177     web_contents->GetView()->Focus();
178   if (ignore_cache)
179     web_contents->GetController().ReloadIgnoringCache(true);
180   else
181     web_contents->GetController().Reload(true);
182 }
183
184 bool IsShowingWebContentsModalDialog(const Browser* browser) {
185   WebContents* web_contents =
186       browser->tab_strip_model()->GetActiveWebContents();
187   if (!web_contents)
188     return false;
189
190   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
191       WebContentsModalDialogManager::FromWebContents(web_contents);
192   return web_contents_modal_dialog_manager->IsDialogActive();
193 }
194
195 bool PrintPreviewShowing(const Browser* browser) {
196 #if defined(ENABLE_FULL_PRINTING)
197   WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
198   printing::PrintPreviewDialogController* controller =
199       printing::PrintPreviewDialogController::GetInstance();
200   return controller && (controller->GetPrintPreviewForContents(contents) ||
201                         controller->is_creating_print_preview_dialog());
202 #else
203   return false;
204 #endif
205 }
206
207 }  // namespace
208
209 bool IsCommandEnabled(Browser* browser, int command) {
210   return browser->command_controller()->command_updater()->IsCommandEnabled(
211       command);
212 }
213
214 bool SupportsCommand(Browser* browser, int command) {
215   return browser->command_controller()->command_updater()->SupportsCommand(
216       command);
217 }
218
219 bool ExecuteCommand(Browser* browser, int command) {
220   return browser->command_controller()->command_updater()->ExecuteCommand(
221       command);
222 }
223
224 bool ExecuteCommandWithDisposition(Browser* browser,
225                                    int command,
226                                    WindowOpenDisposition disposition) {
227   return browser->command_controller()->command_updater()->
228       ExecuteCommandWithDisposition(command, disposition);
229 }
230
231 void UpdateCommandEnabled(Browser* browser, int command, bool enabled) {
232   browser->command_controller()->command_updater()->UpdateCommandEnabled(
233       command, enabled);
234 }
235
236 void AddCommandObserver(Browser* browser,
237                         int command,
238                         CommandObserver* observer) {
239   browser->command_controller()->command_updater()->AddCommandObserver(
240       command, observer);
241 }
242
243 void RemoveCommandObserver(Browser* browser,
244                            int command,
245                            CommandObserver* observer) {
246   browser->command_controller()->command_updater()->RemoveCommandObserver(
247       command, observer);
248 }
249
250 int GetContentRestrictions(const Browser* browser) {
251   int content_restrictions = 0;
252   WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
253   if (current_tab) {
254     CoreTabHelper* core_tab_helper =
255         CoreTabHelper::FromWebContents(current_tab);
256     content_restrictions = core_tab_helper->content_restrictions();
257     NavigationEntry* active_entry =
258         current_tab->GetController().GetActiveEntry();
259     // See comment in UpdateCommandsForTabState about why we call url().
260     if (!content::IsSavableURL(
261             active_entry ? active_entry->GetURL() : GURL()) ||
262         current_tab->ShowingInterstitialPage())
263       content_restrictions |= CONTENT_RESTRICTION_SAVE;
264     if (current_tab->ShowingInterstitialPage())
265       content_restrictions |= CONTENT_RESTRICTION_PRINT;
266   }
267   return content_restrictions;
268 }
269
270 void NewEmptyWindow(Profile* profile, HostDesktopType desktop_type) {
271   bool incognito = profile->IsOffTheRecord();
272   PrefService* prefs = profile->GetPrefs();
273   if (incognito) {
274     if (IncognitoModePrefs::GetAvailability(prefs) ==
275           IncognitoModePrefs::DISABLED) {
276       incognito = false;
277     }
278   } else {
279     if (browser_defaults::kAlwaysOpenIncognitoWindow &&
280         IncognitoModePrefs::ShouldLaunchIncognito(
281             *CommandLine::ForCurrentProcess(), prefs)) {
282       incognito = true;
283     }
284   }
285
286   if (incognito) {
287     content::RecordAction(UserMetricsAction("NewIncognitoWindow"));
288     OpenEmptyWindow(profile->GetOffTheRecordProfile(), desktop_type);
289   } else {
290     content::RecordAction(UserMetricsAction("NewWindow"));
291     SessionService* session_service =
292         SessionServiceFactory::GetForProfileForSessionRestore(
293             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   ScopedTabbedBrowserDisplayer displayer(profile->GetOffTheRecordProfile(),
320                                          desktop_type);
321   AddSelectedTabWithURL(displayer.browser(), url,
322       content::PAGE_TRANSITION_LINK);
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->GetDestinationURL());
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(&params);
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     ScopedTabbedBrowserDisplayer displayer(browser->profile(),
490                                            browser->host_desktop_type());
491     Browser* b = displayer.browser();
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 Translate(Browser* browser) {
686   if (!browser->window()->IsActive())
687     return;
688
689   WebContents* web_contents =
690       browser->tab_strip_model()->GetActiveWebContents();
691   TranslateTabHelper* translate_tab_helper =
692       TranslateTabHelper::FromWebContents(web_contents);
693
694   TranslateBubbleModel::ViewState view_state =
695       TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE;
696   if (translate_tab_helper) {
697     if (translate_tab_helper->language_state().translation_pending())
698       view_state = TranslateBubbleModel::VIEW_STATE_TRANSLATING;
699     else if (translate_tab_helper->language_state().IsPageTranslated())
700       view_state = TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE;
701   }
702   browser->window()->ShowTranslateBubble(web_contents, view_state);
703 }
704
705 void TogglePagePinnedToStartScreen(Browser* browser) {
706 #if defined(OS_WIN)
707   MetroPinTabHelper::FromWebContents(
708       browser->tab_strip_model()->GetActiveWebContents())->
709           TogglePinnedToStartScreen();
710 #endif
711 }
712
713 void SavePage(Browser* browser) {
714   content::RecordAction(UserMetricsAction("SavePage"));
715   WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
716   if (current_tab && current_tab->GetContentsMimeType() == "application/pdf")
717     content::RecordAction(UserMetricsAction("PDF.SavePage"));
718   current_tab->OnSavePage();
719 }
720
721 bool CanSavePage(const Browser* browser) {
722   // LocalState can be NULL in tests.
723   if (g_browser_process->local_state() &&
724       !g_browser_process->local_state()->GetBoolean(
725       prefs::kAllowFileSelectionDialogs)) {
726     return false;
727   }
728   return !browser->is_devtools() &&
729       !(GetContentRestrictions(browser) & CONTENT_RESTRICTION_SAVE);
730 }
731
732 void ShowFindBar(Browser* browser) {
733   browser->GetFindBarController()->Show();
734 }
735
736 void ShowWebsiteSettings(Browser* browser,
737                          content::WebContents* web_contents,
738                          const GURL& url,
739                          const SSLStatus& ssl) {
740   browser->window()->ShowWebsiteSettings(
741       Profile::FromBrowserContext(web_contents->GetBrowserContext()),
742       web_contents, url, ssl);
743 }
744
745
746 void Print(Browser* browser) {
747 #if defined(ENABLE_PRINTING)
748   WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
749 #if defined(ENABLE_FULL_PRINTING)
750   printing::PrintViewManager* print_view_manager =
751       printing::PrintViewManager::FromWebContents(contents);
752   if (browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintPreviewDisabled))
753     print_view_manager->PrintNow();
754   else
755     print_view_manager->PrintPreviewNow(false);
756 #else
757   printing::PrintViewManagerBasic* print_view_manager =
758       printing::PrintViewManagerBasic::FromWebContents(contents);
759   print_view_manager->PrintNow();
760 #endif  // defined(ENABLE_FULL_PRINTING)
761 #endif  // defined(ENABLE_PRINTING)
762 }
763
764 bool CanPrint(const Browser* browser) {
765   // Do not print when printing is disabled via pref or policy.
766   // Do not print when a constrained window is showing. It's confusing.
767   return browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) &&
768       !(IsShowingWebContentsModalDialog(browser) ||
769       GetContentRestrictions(browser) & CONTENT_RESTRICTION_PRINT);
770 }
771
772 void AdvancedPrint(Browser* browser) {
773 #if defined(ENABLE_FULL_PRINTING)
774   printing::PrintViewManager* print_view_manager =
775       printing::PrintViewManager::FromWebContents(
776           browser->tab_strip_model()->GetActiveWebContents());
777   print_view_manager->AdvancedPrintNow();
778 #endif
779 }
780
781 bool CanAdvancedPrint(const Browser* browser) {
782   // If printing is not disabled via pref or policy, it is always possible to
783   // advanced print when the print preview is visible.  The exception to this
784   // is under Win8 ash, since showing the advanced print dialog will open it
785   // modally on the Desktop and hang the browser.  We can remove this check
786   // once we integrate with the system print charm.
787 #if defined(OS_WIN)
788   if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH)
789     return false;
790 #endif
791
792   return browser->profile()->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) &&
793       (PrintPreviewShowing(browser) || CanPrint(browser));
794 }
795
796 void PrintToDestination(Browser* browser) {
797 #if defined(ENABLE_FULL_PRINTING)
798   printing::PrintViewManager* print_view_manager =
799       printing::PrintViewManager::FromWebContents(
800           browser->tab_strip_model()->GetActiveWebContents());
801   print_view_manager->PrintToDestination();
802 #endif
803 }
804
805 void EmailPageLocation(Browser* browser) {
806   content::RecordAction(UserMetricsAction("EmailPageLocation"));
807   WebContents* wc = browser->tab_strip_model()->GetActiveWebContents();
808   DCHECK(wc);
809
810   std::string title = net::EscapeQueryParamValue(
811       UTF16ToUTF8(wc->GetTitle()), false);
812   std::string page_url = net::EscapeQueryParamValue(wc->GetURL().spec(), false);
813   std::string mailto = std::string("mailto:?subject=Fwd:%20") +
814       title + "&body=%0A%0A" + page_url;
815   platform_util::OpenExternal(GURL(mailto));
816 }
817
818 bool CanEmailPageLocation(const Browser* browser) {
819   return browser->toolbar_model()->ShouldDisplayURL() &&
820       browser->tab_strip_model()->GetActiveWebContents()->GetURL().is_valid();
821 }
822
823 void Cut(Browser* browser) {
824   content::RecordAction(UserMetricsAction("Cut"));
825   browser->window()->Cut();
826 }
827
828 void Copy(Browser* browser) {
829   content::RecordAction(UserMetricsAction("Copy"));
830   browser->window()->Copy();
831 }
832
833 void Paste(Browser* browser) {
834   content::RecordAction(UserMetricsAction("Paste"));
835   browser->window()->Paste();
836 }
837
838 void Find(Browser* browser) {
839   content::RecordAction(UserMetricsAction("Find"));
840   FindInPage(browser, false, false);
841 }
842
843 void FindNext(Browser* browser) {
844   content::RecordAction(UserMetricsAction("FindNext"));
845   FindInPage(browser, true, true);
846 }
847
848 void FindPrevious(Browser* browser) {
849   content::RecordAction(UserMetricsAction("FindPrevious"));
850   FindInPage(browser, true, false);
851 }
852
853 void FindInPage(Browser* browser, bool find_next, bool forward_direction) {
854   ShowFindBar(browser);
855   if (find_next) {
856     string16 find_text;
857     FindTabHelper* find_helper = FindTabHelper::FromWebContents(
858         browser->tab_strip_model()->GetActiveWebContents());
859 #if defined(OS_MACOSX)
860     // We always want to search for the current contents of the find bar on
861     // OS X. For regular profile it's always the current find pboard. For
862     // Incognito window it's the newest value of the find pboard content and
863     // user-typed text.
864     FindBar* find_bar = browser->GetFindBarController()->find_bar();
865     find_text = find_bar->GetFindText();
866 #endif
867     find_helper->StartFinding(find_text, forward_direction, false);
868   }
869 }
870
871 void Zoom(Browser* browser, content::PageZoom zoom) {
872   if (browser->is_devtools())
873     return;
874
875   chrome_page_zoom::Zoom(browser->tab_strip_model()->GetActiveWebContents(),
876                          zoom);
877 }
878
879 void FocusToolbar(Browser* browser) {
880   content::RecordAction(UserMetricsAction("FocusToolbar"));
881   browser->window()->FocusToolbar();
882 }
883
884 void FocusLocationBar(Browser* browser) {
885   content::RecordAction(UserMetricsAction("FocusLocation"));
886   browser->window()->SetFocusToLocationBar(true);
887 }
888
889 void FocusSearch(Browser* browser) {
890   // TODO(beng): replace this with FocusLocationBar
891   content::RecordAction(UserMetricsAction("FocusSearch"));
892   browser->window()->GetLocationBar()->FocusSearch();
893 }
894
895 void FocusAppMenu(Browser* browser) {
896   content::RecordAction(UserMetricsAction("FocusAppMenu"));
897   browser->window()->FocusAppMenu();
898 }
899
900 void FocusBookmarksToolbar(Browser* browser) {
901   content::RecordAction(UserMetricsAction("FocusBookmarksToolbar"));
902   browser->window()->FocusBookmarksToolbar();
903 }
904
905 void FocusInfobars(Browser* browser) {
906   content::RecordAction(UserMetricsAction("FocusInfobars"));
907   browser->window()->FocusInfobars();
908 }
909
910 void FocusNextPane(Browser* browser) {
911   content::RecordAction(UserMetricsAction("FocusNextPane"));
912   browser->window()->RotatePaneFocus(true);
913 }
914
915 void FocusPreviousPane(Browser* browser) {
916   content::RecordAction(UserMetricsAction("FocusPreviousPane"));
917   browser->window()->RotatePaneFocus(false);
918 }
919
920 void ToggleDevToolsWindow(Browser* browser, DevToolsToggleAction action) {
921   if (action.type() == DevToolsToggleAction::kShowConsole)
922     content::RecordAction(UserMetricsAction("DevTools_ToggleConsole"));
923   else
924     content::RecordAction(UserMetricsAction("DevTools_ToggleWindow"));
925   DevToolsWindow::ToggleDevToolsWindow(browser, action);
926 }
927
928 bool CanOpenTaskManager() {
929 #if defined(OS_WIN)
930   // In metro we can't display the task manager, as it is a native window.
931   return !win8::IsSingleWindowMetroMode();
932 #else
933   return true;
934 #endif
935 }
936
937 void OpenTaskManager(Browser* browser) {
938   content::RecordAction(UserMetricsAction("TaskManager"));
939   chrome::ShowTaskManager(browser);
940 }
941
942 void OpenFeedbackDialog(Browser* browser) {
943   content::RecordAction(UserMetricsAction("Feedback"));
944   chrome::ShowFeedbackPage(browser, std::string(), std::string());
945 }
946
947 void ToggleBookmarkBar(Browser* browser) {
948   content::RecordAction(UserMetricsAction("ShowBookmarksBar"));
949   ToggleBookmarkBarWhenVisible(browser->profile());
950 }
951
952 void ShowAppMenu(Browser* browser) {
953   // We record the user metric for this event in WrenchMenu::RunMenu.
954   browser->window()->ShowAppMenu();
955 }
956
957 void ShowAvatarMenu(Browser* browser) {
958   browser->window()->ShowAvatarBubbleFromAvatarButton();
959 }
960
961 void OpenUpdateChromeDialog(Browser* browser) {
962   if (UpgradeDetector::GetInstance()->is_outdated_install()) {
963     content::NotificationService::current()->Notify(
964         chrome::NOTIFICATION_OUTDATED_INSTALL,
965         content::NotificationService::AllSources(),
966         content::NotificationService::NoDetails());
967   } else {
968     content::RecordAction(UserMetricsAction("UpdateChrome"));
969     browser->window()->ShowUpdateChromeDialog();
970   }
971 }
972
973 void ToggleSpeechInput(Browser* browser) {
974   browser->tab_strip_model()->GetActiveWebContents()->
975       GetRenderViewHost()->ToggleSpeechInput();
976   if (browser->instant_controller())
977     browser->instant_controller()->ToggleVoiceSearch();
978 }
979
980 bool CanRequestTabletSite(WebContents* current_tab) {
981   if (!current_tab)
982     return false;
983   return current_tab->GetController().GetActiveEntry() != NULL;
984 }
985
986 bool IsRequestingTabletSite(Browser* browser) {
987   WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
988   if (!current_tab)
989     return false;
990   content::NavigationEntry* entry =
991       current_tab->GetController().GetActiveEntry();
992   if (!entry)
993     return false;
994   return entry->GetIsOverridingUserAgent();
995 }
996
997 void ToggleRequestTabletSite(Browser* browser) {
998   WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents();
999   if (!current_tab)
1000     return;
1001   NavigationController& controller = current_tab->GetController();
1002   NavigationEntry* entry = controller.GetActiveEntry();
1003   if (!entry)
1004     return;
1005   if (entry->GetIsOverridingUserAgent()) {
1006     entry->SetIsOverridingUserAgent(false);
1007   } else {
1008     entry->SetIsOverridingUserAgent(true);
1009     chrome::VersionInfo version_info;
1010     std::string product;
1011     if (version_info.is_valid())
1012       product = version_info.ProductNameAndVersionForUserAgent();
1013     current_tab->SetUserAgentOverride(
1014         webkit_glue::BuildUserAgentFromOSAndProduct(
1015             kOsOverrideForTabletSite, product));
1016   }
1017   controller.ReloadOriginalRequestURL(true);
1018 }
1019
1020 void ToggleFullscreenMode(Browser* browser) {
1021   browser->fullscreen_controller()->ToggleFullscreenMode();
1022 }
1023
1024 void ClearCache(Browser* browser) {
1025   BrowsingDataRemover* remover =
1026       BrowsingDataRemover::CreateForUnboundedRange(browser->profile());
1027   remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
1028                   BrowsingDataHelper::UNPROTECTED_WEB);
1029   // BrowsingDataRemover takes care of deleting itself when done.
1030 }
1031
1032 bool IsDebuggerAttachedToCurrentTab(Browser* browser) {
1033   WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
1034   return contents ?
1035       content::DevToolsAgentHost::IsDebuggerAttached(contents) : false;
1036 }
1037
1038 void ViewSource(Browser* browser, WebContents* contents) {
1039   DCHECK(contents);
1040
1041   // Use the last committed entry, since the pending entry hasn't loaded yet and
1042   // won't be copied into the cloned tab.
1043   NavigationEntry* entry = contents->GetController().GetLastCommittedEntry();
1044   if (!entry)
1045     return;
1046
1047   ViewSource(browser, contents, entry->GetURL(), entry->GetPageState());
1048 }
1049
1050 void ViewSource(Browser* browser,
1051                 WebContents* contents,
1052                 const GURL& url,
1053                 const content::PageState& page_state) {
1054   content::RecordAction(UserMetricsAction("ViewSource"));
1055   DCHECK(contents);
1056
1057   // Note that Clone does not copy the pending or transient entries, so the
1058   // active entry in view_source_contents will be the last committed entry.
1059   WebContents* view_source_contents = contents->Clone();
1060   DCHECK(view_source_contents->GetController().CanPruneAllButVisible());
1061   view_source_contents->GetController().PruneAllButVisible();
1062   NavigationEntry* active_entry =
1063       view_source_contents->GetController().GetActiveEntry();
1064   if (!active_entry)
1065     return;
1066
1067   GURL view_source_url =
1068       GURL(content::kViewSourceScheme + std::string(":") + url.spec());
1069   active_entry->SetVirtualURL(view_source_url);
1070
1071   // Do not restore scroller position.
1072   active_entry->SetPageState(page_state.RemoveScrollOffset());
1073
1074   // Do not restore title, derive it from the url.
1075   active_entry->SetTitle(string16());
1076
1077   // Now show view-source entry.
1078   if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) {
1079     // If this is a tabbed browser, just create a duplicate tab inside the same
1080     // window next to the tab being duplicated.
1081     int index = browser->tab_strip_model()->GetIndexOfWebContents(contents);
1082     int add_types = TabStripModel::ADD_ACTIVE |
1083         TabStripModel::ADD_INHERIT_GROUP;
1084     browser->tab_strip_model()->InsertWebContentsAt(
1085         index + 1,
1086         view_source_contents,
1087         add_types);
1088   } else {
1089     Browser* b = new Browser(
1090         Browser::CreateParams(Browser::TYPE_TABBED, browser->profile(),
1091                               browser->host_desktop_type()));
1092
1093     // Preserve the size of the original window. The new window has already
1094     // been given an offset by the OS, so we shouldn't copy the old bounds.
1095     BrowserWindow* new_window = b->window();
1096     new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
1097                           browser->window()->GetRestoredBounds().size()));
1098
1099     // We need to show the browser now. Otherwise ContainerWin assumes the
1100     // WebContents is invisible and won't size it.
1101     b->window()->Show();
1102
1103     // The page transition below is only for the purpose of inserting the tab.
1104     b->tab_strip_model()->AddWebContents(view_source_contents, -1,
1105                                          content::PAGE_TRANSITION_LINK,
1106                                          TabStripModel::ADD_ACTIVE);
1107   }
1108
1109   SessionService* session_service =
1110       SessionServiceFactory::GetForProfileIfExisting(browser->profile());
1111   if (session_service)
1112     session_service->TabRestored(view_source_contents, false);
1113 }
1114
1115 void ViewSelectedSource(Browser* browser) {
1116   ViewSource(browser, browser->tab_strip_model()->GetActiveWebContents());
1117 }
1118
1119 bool CanViewSource(const Browser* browser) {
1120   return browser->tab_strip_model()->GetActiveWebContents()->
1121       GetController().CanViewSource();
1122 }
1123
1124 void CreateApplicationShortcuts(Browser* browser) {
1125   content::RecordAction(UserMetricsAction("CreateShortcut"));
1126   extensions::TabHelper::FromWebContents(
1127       browser->tab_strip_model()->GetActiveWebContents())->
1128           CreateApplicationShortcuts();
1129 }
1130
1131 bool CanCreateApplicationShortcuts(const Browser* browser) {
1132   return extensions::TabHelper::FromWebContents(
1133       browser->tab_strip_model()->GetActiveWebContents())->
1134           CanCreateApplicationShortcuts();
1135 }
1136
1137 void ConvertTabToAppWindow(Browser* browser,
1138                            content::WebContents* contents) {
1139   const GURL& url = contents->GetController().GetActiveEntry()->GetURL();
1140   std::string app_name = web_app::GenerateApplicationNameFromURL(url);
1141
1142   int index = browser->tab_strip_model()->GetIndexOfWebContents(contents);
1143   if (index >= 0)
1144     browser->tab_strip_model()->DetachWebContentsAt(index);
1145
1146   Browser* app_browser = new Browser(
1147       Browser::CreateParams::CreateForApp(
1148           Browser::TYPE_POPUP, app_name, gfx::Rect(), browser->profile(),
1149           browser->host_desktop_type()));
1150   app_browser->tab_strip_model()->AppendWebContents(contents, true);
1151
1152   contents->GetMutableRendererPrefs()->can_accept_load_drops = false;
1153   contents->GetRenderViewHost()->SyncRendererPrefs();
1154   app_browser->window()->Show();
1155 }
1156
1157 }  // namespace chrome