blob: 5ff86c5562cc9ac64b3a00e77b1e6040b56f8396 [file] [log] [blame]
[email protected]a37d4b02012-06-25 21:56:101// Copyright (c) 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/utf_string_conversions.h"
[email protected]5d98294912012-06-27 22:57:4010#include "chrome/browser/bookmarks/bookmark_editor.h"
[email protected]a37d4b02012-06-25 21:56:1011#include "chrome/browser/bookmarks/bookmark_model.h"
12#include "chrome/browser/bookmarks/bookmark_utils.h"
13#include "chrome/browser/browser_process.h"
[email protected]d3446bda2012-07-12 14:24:3914#include "chrome/browser/browsing_data_helper.h"
15#include "chrome/browser/browsing_data_remover.h"
[email protected]a37d4b02012-06-25 21:56:1016#include "chrome/browser/chrome_page_zoom.h"
17#include "chrome/browser/debugger/devtools_window.h"
[email protected]5d98294912012-06-27 22:57:4018#include "chrome/browser/download/download_util.h"
[email protected]a37d4b02012-06-25 21:56:1019#include "chrome/browser/extensions/extension_service.h"
[email protected]a6394ae2012-07-16 20:58:4320#include "chrome/browser/extensions/tab_helper.h"
[email protected]a37d4b02012-06-25 21:56:1021#include "chrome/browser/favicon/favicon_tab_helper.h"
22#include "chrome/browser/lifetime/application_lifetime.h"
23#include "chrome/browser/platform_util.h"
24#include "chrome/browser/prefs/incognito_mode_prefs.h"
25#include "chrome/browser/prefs/pref_service.h"
[email protected]5d98294912012-06-27 22:57:4026#include "chrome/browser/printing/print_preview_tab_controller.h"
[email protected]a37d4b02012-06-25 21:56:1027#include "chrome/browser/printing/print_view_manager.h"
28#include "chrome/browser/profiles/profile.h"
29#include "chrome/browser/sessions/session_service_factory.h"
[email protected]a37d4b02012-06-25 21:56:1030#include "chrome/browser/sessions/tab_restore_service.h"
[email protected]5d98294912012-06-27 22:57:4031#include "chrome/browser/sessions/tab_restore_service_delegate.h"
[email protected]78e2edc2012-07-01 23:32:2832#include "chrome/browser/sessions/tab_restore_service_factory.h"
[email protected]a37d4b02012-06-25 21:56:1033#include "chrome/browser/ui/browser.h"
[email protected]5d98294912012-06-27 22:57:4034#include "chrome/browser/ui/browser_command_controller.h"
[email protected]a37d4b02012-06-25 21:56:1035#include "chrome/browser/ui/browser_finder.h"
[email protected]7acfaf92012-07-11 15:51:5936#include "chrome/browser/ui/browser_instant_controller.h"
[email protected]5d98294912012-06-27 22:57:4037#include "chrome/browser/ui/browser_tab_restore_service_delegate.h"
[email protected]52877dbc62012-06-29 22:22:0338#include "chrome/browser/ui/browser_tabstrip.h"
[email protected]a37d4b02012-06-25 21:56:1039#include "chrome/browser/ui/browser_window.h"
[email protected]5d98294912012-06-27 22:57:4040#include "chrome/browser/ui/constrained_window_tab_helper.h"
[email protected]a37d4b02012-06-25 21:56:1041#include "chrome/browser/ui/find_bar/find_bar_controller.h"
42#include "chrome/browser/ui/find_bar/find_tab_helper.h"
[email protected]3f32b9b2012-07-09 16:59:2843#include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
[email protected]a37d4b02012-06-25 21:56:1044#include "chrome/browser/ui/omnibox/location_bar.h"
[email protected]43aafff2012-06-29 21:20:4945#include "chrome/browser/ui/search/search.h"
46#include "chrome/browser/ui/search/search_model.h"
[email protected]a37d4b02012-06-25 21:56:1047#include "chrome/browser/ui/status_bubble.h"
48#include "chrome/browser/ui/tab_contents/tab_contents.h"
49#include "chrome/browser/ui/tabs/tab_strip_model.h"
50#include "chrome/browser/ui/webui/feedback_ui.h"
51#include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
[email protected]5d98294912012-06-27 22:57:4052#include "chrome/browser/web_applications/web_app.h"
[email protected]a37d4b02012-06-25 21:56:1053#include "chrome/common/chrome_switches.h"
[email protected]a37d4b02012-06-25 21:56:1054#include "chrome/common/pref_names.h"
[email protected]d3446bda2012-07-12 14:24:3955#include "content/public/browser/devtools_agent_host_registry.h"
[email protected]a37d4b02012-06-25 21:56:1056#include "content/public/browser/navigation_controller.h"
57#include "content/public/browser/navigation_entry.h"
58#include "content/public/browser/page_navigator.h"
59#include "content/public/browser/render_view_host.h"
60#include "content/public/browser/user_metrics.h"
61#include "content/public/browser/web_contents.h"
62#include "content/public/browser/web_contents_view.h"
[email protected]78e2edc2012-07-01 23:32:2863#include "content/public/common/content_restriction.h"
64#include "content/public/common/renderer_preferences.h"
[email protected]2cd4fde2012-06-26 03:10:2665#include "content/public/common/url_constants.h"
[email protected]a37d4b02012-06-25 21:56:1066#include "net/base/escape.h"
[email protected]2cd4fde2012-06-26 03:10:2667#include "webkit/glue/webkit_glue.h"
[email protected]a37d4b02012-06-25 21:56:1068
69#if defined(OS_MACOSX)
70#include "ui/base/cocoa/find_pasteboard.h"
71#endif
72
73#if defined(OS_WIN)
74#include "base/win/metro.h"
75#endif
76
77using content::NavigationController;
78using content::NavigationEntry;
79using content::OpenURLParams;
80using content::Referrer;
81using content::SSLStatus;
82using content::UserMetricsAction;
83using content::WebContents;
84
85namespace chrome {
86namespace {
87
88WebContents* GetOrCloneTabForDisposition(Browser* browser,
89 WindowOpenDisposition disposition) {
[email protected]855370052012-07-10 19:30:3290 TabContents* current_tab = GetActiveTabContents(browser);
[email protected]a37d4b02012-06-25 21:56:1091 switch (disposition) {
92 case NEW_FOREGROUND_TAB:
93 case NEW_BACKGROUND_TAB: {
94 current_tab = current_tab->Clone();
95 browser->tab_strip_model()->AddTabContents(
96 current_tab, -1, content::PAGE_TRANSITION_LINK,
97 disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_ACTIVE :
98 TabStripModel::ADD_NONE);
99 break;
100 }
101 case NEW_WINDOW: {
102 current_tab = current_tab->Clone();
103 Browser* b = Browser::Create(browser->profile());
104 b->tab_strip_model()->AddTabContents(
105 current_tab, -1, content::PAGE_TRANSITION_LINK,
106 TabStripModel::ADD_ACTIVE);
107 b->window()->Show();
108 break;
109 }
110 default:
111 break;
112 }
113 return current_tab->web_contents();
114}
115
116void ReloadInternal(Browser* browser,
117 WindowOpenDisposition disposition,
118 bool ignore_cache) {
119 // If we are showing an interstitial, treat this as an OpenURL.
[email protected]855370052012-07-10 19:30:32120 WebContents* current_tab = GetActiveWebContents(browser);
[email protected]a37d4b02012-06-25 21:56:10121 if (current_tab && current_tab->ShowingInterstitialPage()) {
122 NavigationEntry* entry = current_tab->GetController().GetActiveEntry();
123 DCHECK(entry); // Should exist if interstitial is showing.
124 browser->OpenURL(OpenURLParams(
125 entry->GetURL(), Referrer(), disposition,
126 content::PAGE_TRANSITION_RELOAD, false));
127 return;
128 }
129
130 // As this is caused by a user action, give the focus to the page.
131 //
132 // Also notify RenderViewHostDelegate of the user gesture; this is
133 // normally done in Browser::Navigate, but a reload bypasses Navigate.
134 WebContents* web_contents = GetOrCloneTabForDisposition(browser, disposition);
135 web_contents->UserGestureDone();
136 if (!web_contents->FocusLocationBarByDefault())
137 web_contents->Focus();
138 if (ignore_cache)
139 web_contents->GetController().ReloadIgnoringCache(true);
140 else
141 web_contents->GetController().Reload(true);
142}
143
[email protected]5d98294912012-06-27 22:57:40144bool HasConstrainedWindow(const Browser* browser) {
[email protected]52877dbc62012-06-29 22:22:03145 TabContents* tab_contents = GetActiveTabContents(browser);
[email protected]5d98294912012-06-27 22:57:40146 return tab_contents && tab_contents->constrained_window_tab_helper()->
147 constrained_window_count();
148}
149
150bool PrintPreviewShowing(const Browser* browser) {
[email protected]52877dbc62012-06-29 22:22:03151 TabContents* contents = GetActiveTabContents(browser);
[email protected]5d98294912012-06-27 22:57:40152 printing::PrintPreviewTabController* controller =
153 printing::PrintPreviewTabController::GetInstance();
154 return controller && (controller->GetPrintPreviewForTab(contents) ||
155 controller->is_creating_print_preview_tab());
156}
157
[email protected]db9747252012-07-02 19:28:00158bool IsNTPModeForInstantExtendedAPI(const Browser* browser) {
159 return browser->search_model() &&
[email protected]855370052012-07-10 19:30:32160 search::IsInstantExtendedAPIEnabled(browser->profile()) &&
161 browser->search_model()->mode().is_ntp();
[email protected]db9747252012-07-02 19:28:00162}
163
[email protected]a37d4b02012-06-25 21:56:10164} // namespace
165
[email protected]5d98294912012-06-27 22:57:40166bool IsCommandEnabled(Browser* browser, int command) {
167 return browser->command_controller()->command_updater()->IsCommandEnabled(
168 command);
169}
170
171bool SupportsCommand(Browser* browser, int command) {
172 return browser->command_controller()->command_updater()->SupportsCommand(
173 command);
174}
175
176bool ExecuteCommand(Browser* browser, int command) {
177 return browser->command_controller()->command_updater()->ExecuteCommand(
178 command);
179}
180
181bool ExecuteCommandWithDisposition(Browser* browser,
182 int command,
183 WindowOpenDisposition disposition) {
184 return browser->command_controller()->command_updater()->
185 ExecuteCommandWithDisposition(command, disposition);
186}
187
188void UpdateCommandEnabled(Browser* browser, int command, bool enabled) {
189 browser->command_controller()->command_updater()->UpdateCommandEnabled(
190 command, enabled);
191}
192
193void AddCommandObserver(Browser* browser,
194 int command,
195 CommandObserver* observer) {
196 browser->command_controller()->command_updater()->AddCommandObserver(
197 command, observer);
198}
199
200void RemoveCommandObserver(Browser* browser,
201 int command,
202 CommandObserver* observer) {
203 browser->command_controller()->command_updater()->RemoveCommandObserver(
204 command, observer);
205}
206
207int GetContentRestrictions(const Browser* browser) {
208 int content_restrictions = 0;
[email protected]52877dbc62012-06-29 22:22:03209 WebContents* current_tab = GetActiveWebContents(browser);
[email protected]5d98294912012-06-27 22:57:40210 if (current_tab) {
211 content_restrictions = current_tab->GetContentRestrictions();
212 NavigationEntry* active_entry =
213 current_tab->GetController().GetActiveEntry();
214 // See comment in UpdateCommandsForTabState about why we call url().
215 if (!download_util::IsSavableURL(
216 active_entry ? active_entry->GetURL() : GURL()) ||
217 current_tab->ShowingInterstitialPage())
218 content_restrictions |= content::CONTENT_RESTRICTION_SAVE;
219 if (current_tab->ShowingInterstitialPage())
220 content_restrictions |= content::CONTENT_RESTRICTION_PRINT;
221 }
222 return content_restrictions;
223}
224
[email protected]a37d4b02012-06-25 21:56:10225void NewEmptyWindow(Profile* profile) {
226 bool incognito = profile->IsOffTheRecord();
227 PrefService* prefs = profile->GetPrefs();
228 if (incognito) {
229 if (IncognitoModePrefs::GetAvailability(prefs) ==
230 IncognitoModePrefs::DISABLED) {
231 incognito = false;
232 }
233 } else {
234 if (browser_defaults::kAlwaysOpenIncognitoWindow &&
235 IncognitoModePrefs::ShouldLaunchIncognito(
236 *CommandLine::ForCurrentProcess(), prefs)) {
237 incognito = true;
238 }
239 }
240
241 if (incognito) {
242 content::RecordAction(UserMetricsAction("NewIncognitoWindow"));
243 OpenEmptyWindow(profile->GetOffTheRecordProfile());
244 } else {
245 content::RecordAction(UserMetricsAction("NewWindow"));
246 SessionService* session_service =
247 SessionServiceFactory::GetForProfile(profile->GetOriginalProfile());
248 if (!session_service ||
249 !session_service->RestoreIfNecessary(std::vector<GURL>())) {
250 OpenEmptyWindow(profile->GetOriginalProfile());
251 }
252 }
253}
254
255Browser* OpenEmptyWindow(Profile* profile) {
256 Browser* browser = Browser::Create(profile);
[email protected]855370052012-07-10 19:30:32257 AddBlankTab(browser, true);
[email protected]a37d4b02012-06-25 21:56:10258 browser->window()->Show();
259 return browser;
260}
261
262void OpenWindowWithRestoredTabs(Profile* profile) {
263 TabRestoreService* service = TabRestoreServiceFactory::GetForProfile(profile);
264 if (service)
265 service->RestoreMostRecentEntry(NULL);
266}
267
268void OpenURLOffTheRecord(Profile* profile, const GURL& url) {
269 Browser* browser = browser::FindOrCreateTabbedBrowser(
270 profile->GetOffTheRecordProfile());
[email protected]52877dbc62012-06-29 22:22:03271 AddSelectedTabWithURL(browser, url, content::PAGE_TRANSITION_LINK);
[email protected]a37d4b02012-06-25 21:56:10272 browser->window()->Show();
273}
274
[email protected]5d98294912012-06-27 22:57:40275bool CanGoBack(const Browser* browser) {
[email protected]52877dbc62012-06-29 22:22:03276 return GetActiveWebContents(browser)->GetController().CanGoBack();
[email protected]a37d4b02012-06-25 21:56:10277}
278
279void GoBack(Browser* browser, WindowOpenDisposition disposition) {
280 content::RecordAction(UserMetricsAction("Back"));
281
[email protected]52877dbc62012-06-29 22:22:03282 TabContents* current_tab = GetActiveTabContents(browser);
[email protected]a37d4b02012-06-25 21:56:10283 if (CanGoBack(browser)) {
284 WebContents* new_tab = GetOrCloneTabForDisposition(browser, disposition);
285 // If we are on an interstitial page and clone the tab, it won't be copied
286 // to the new tab, so we don't need to go back.
287 if (current_tab->web_contents()->ShowingInterstitialPage() &&
288 (new_tab != current_tab->web_contents()))
289 return;
290 new_tab->GetController().GoBack();
291 }
292}
293
[email protected]5d98294912012-06-27 22:57:40294bool CanGoForward(const Browser* browser) {
[email protected]52877dbc62012-06-29 22:22:03295 return GetActiveWebContents(browser)->GetController().CanGoForward();
[email protected]a37d4b02012-06-25 21:56:10296}
297
298void GoForward(Browser* browser, WindowOpenDisposition disposition) {
299 content::RecordAction(UserMetricsAction("Forward"));
300 if (CanGoForward(browser)) {
301 GetOrCloneTabForDisposition(browser, disposition)->
302 GetController().GoForward();
303 }
304}
305
306bool NavigateToIndexWithDisposition(Browser* browser,
307 int index,
308 WindowOpenDisposition disp) {
309 NavigationController& controller =
310 GetOrCloneTabForDisposition(browser, disp)->GetController();
311 if (index < 0 || index >= controller.GetEntryCount())
312 return false;
313 controller.GoToIndex(index);
314 return true;
315}
316
317void Reload(Browser* browser, WindowOpenDisposition disposition) {
318 content::RecordAction(UserMetricsAction("Reload"));
319 ReloadInternal(browser, disposition, false);
320}
321
322void ReloadIgnoringCache(Browser* browser, WindowOpenDisposition disposition) {
323 content::RecordAction(UserMetricsAction("ReloadIgnoringCache"));
324 ReloadInternal(browser, disposition, true);
325}
326
[email protected]5d98294912012-06-27 22:57:40327bool CanReload(const Browser* browser) {
[email protected]db9747252012-07-02 19:28:00328 return !browser->is_devtools() && !IsNTPModeForInstantExtendedAPI(browser);
[email protected]5d98294912012-06-27 22:57:40329}
330
[email protected]a37d4b02012-06-25 21:56:10331void Home(Browser* browser, WindowOpenDisposition disposition) {
332 content::RecordAction(UserMetricsAction("Home"));
333 browser->OpenURL(OpenURLParams(
334 browser->profile()->GetHomePage(), Referrer(), disposition,
335 content::PageTransitionFromInt(
336 content::PAGE_TRANSITION_AUTO_BOOKMARK |
337 content::PAGE_TRANSITION_HOME_PAGE),
338 false));
339}
340
341void OpenCurrentURL(Browser* browser) {
342 content::RecordAction(UserMetricsAction("LoadURL"));
343 LocationBar* location_bar = browser->window()->GetLocationBar();
344 if (!location_bar)
345 return;
346
347 WindowOpenDisposition open_disposition =
348 location_bar->GetWindowOpenDisposition();
[email protected]7acfaf92012-07-11 15:51:59349 if (browser->instant_controller()->OpenInstant(open_disposition))
[email protected]a37d4b02012-06-25 21:56:10350 return;
351
352 GURL url(location_bar->GetInputString());
353
[email protected]855370052012-07-10 19:30:32354 NavigateParams params(browser, url, location_bar->GetPageTransition());
[email protected]a37d4b02012-06-25 21:56:10355 params.disposition = open_disposition;
356 // Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least
357 // inherit the opener. In some cases the tabstrip will determine the group
358 // should be inherited, in which case the group is inherited instead of the
359 // opener.
360 params.tabstrip_add_types =
361 TabStripModel::ADD_FORCE_INDEX | TabStripModel::ADD_INHERIT_OPENER;
[email protected]855370052012-07-10 19:30:32362 Navigate(&params);
[email protected]a37d4b02012-06-25 21:56:10363
364 DCHECK(browser->profile()->GetExtensionService());
365 if (browser->profile()->GetExtensionService()->IsInstalledApp(url)) {
366 AppLauncherHandler::RecordAppLaunchType(
367 extension_misc::APP_LAUNCH_OMNIBOX_LOCATION);
368 }
369}
370
371void Stop(Browser* browser) {
372 content::RecordAction(UserMetricsAction("Stop"));
[email protected]52877dbc62012-06-29 22:22:03373 GetActiveWebContents(browser)->Stop();
[email protected]a37d4b02012-06-25 21:56:10374}
375
376#if !defined(OS_WIN)
377void NewWindow(Browser* browser) {
378 NewEmptyWindow(browser->profile()->GetOriginalProfile());
379}
380
381void NewIncognitoWindow(Browser* browser) {
382 NewEmptyWindow(browser->profile()->GetOffTheRecordProfile());
383}
384#endif // OS_WIN
385
386void CloseWindow(Browser* browser) {
387 content::RecordAction(UserMetricsAction("CloseWindow"));
388 browser->window()->Close();
389}
390
391void NewTab(Browser* browser) {
392 content::RecordAction(UserMetricsAction("NewTab"));
393 // TODO(asvitkine): This is invoked programmatically from several places.
394 // Audit the code and change it so that the histogram only gets collected for
395 // user-initiated commands.
396 UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", TabStripModel::NEW_TAB_COMMAND,
397 TabStripModel::NEW_TAB_ENUM_COUNT);
398
399 if (browser->is_type_tabbed()) {
[email protected]855370052012-07-10 19:30:32400 AddBlankTab(browser, true);
[email protected]52877dbc62012-06-29 22:22:03401 GetActiveWebContents(browser)->GetView()->RestoreFocus();
[email protected]a37d4b02012-06-25 21:56:10402 } else {
403 Browser* b = browser::FindOrCreateTabbedBrowser(browser->profile());
[email protected]855370052012-07-10 19:30:32404 AddBlankTab(b, true);
[email protected]a37d4b02012-06-25 21:56:10405 b->window()->Show();
406 // The call to AddBlankTab above did not set the focus to the tab as its
407 // window was not active, so we have to do it explicitly.
408 // See http://crbug.com/6380.
[email protected]855370052012-07-10 19:30:32409 GetActiveWebContents(b)->GetView()->RestoreFocus();
[email protected]a37d4b02012-06-25 21:56:10410 }
411}
412
413void CloseTab(Browser* browser) {
414 content::RecordAction(UserMetricsAction("CloseTab_Accelerator"));
415 browser->tab_strip_model()->CloseSelectedTabs();
416}
417
[email protected]5d98294912012-06-27 22:57:40418void RestoreTab(Browser* browser) {
419 content::RecordAction(UserMetricsAction("RestoreTab"));
420 TabRestoreService* service =
421 TabRestoreServiceFactory::GetForProfile(browser->profile());
422 if (service)
423 service->RestoreMostRecentEntry(browser->tab_restore_service_delegate());
424}
425
426bool CanRestoreTab(const Browser* browser) {
427 TabRestoreService* service =
428 TabRestoreServiceFactory::GetForProfile(browser->profile());
429 return service && !service->entries().empty();
430}
431
[email protected]a37d4b02012-06-25 21:56:10432void SelectNextTab(Browser* browser) {
433 content::RecordAction(UserMetricsAction("SelectNextTab"));
434 browser->tab_strip_model()->SelectNextTab();
435}
436
437void SelectPreviousTab(Browser* browser) {
438 content::RecordAction(UserMetricsAction("SelectPrevTab"));
439 browser->tab_strip_model()->SelectPreviousTab();
440}
441
442void OpenTabpose(Browser* browser) {
443#if defined(OS_MACOSX)
444 if (!CommandLine::ForCurrentProcess()->HasSwitch(
445 switches::kEnableExposeForTabs)) {
446 return;
447 }
448
449 content::RecordAction(UserMetricsAction("OpenTabpose"));
450 browser->window()->OpenTabpose();
451#else
452 NOTREACHED();
453#endif
454}
455
456void MoveTabNext(Browser* browser) {
457 content::RecordAction(UserMetricsAction("MoveTabNext"));
458 browser->tab_strip_model()->MoveTabNext();
459}
460
461void MoveTabPrevious(Browser* browser) {
462 content::RecordAction(UserMetricsAction("MoveTabPrevious"));
463 browser->tab_strip_model()->MoveTabPrevious();
464}
465
466void SelectNumberedTab(Browser* browser, int index) {
467 if (index < browser->tab_count()) {
468 content::RecordAction(UserMetricsAction("SelectNumberedTab"));
[email protected]52877dbc62012-06-29 22:22:03469 ActivateTabAt(browser, index, true);
[email protected]a37d4b02012-06-25 21:56:10470 }
471}
472
473void SelectLastTab(Browser* browser) {
474 content::RecordAction(UserMetricsAction("SelectLastTab"));
475 browser->tab_strip_model()->SelectLastTab();
476}
477
478void DuplicateTab(Browser* browser) {
479 content::RecordAction(UserMetricsAction("Duplicate"));
[email protected]855370052012-07-10 19:30:32480 DuplicateTabAt(browser, browser->active_index());
[email protected]a37d4b02012-06-25 21:56:10481}
482
[email protected]5d98294912012-06-27 22:57:40483bool CanDuplicateTab(const Browser* browser) {
[email protected]52877dbc62012-06-29 22:22:03484 WebContents* contents = GetActiveWebContents(browser);
[email protected]5d98294912012-06-27 22:57:40485 return contents && contents->GetController().GetLastCommittedEntry();
486}
487
[email protected]855370052012-07-10 19:30:32488void DuplicateTabAt(Browser* browser, int index) {
489 TabContents* contents = GetTabContentsAt(browser, index);
490 CHECK(contents);
491 TabContents* contents_dupe = contents->Clone();
492
493 bool pinned = false;
494 if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) {
495 // If this is a tabbed browser, just create a duplicate tab inside the same
496 // window next to the tab being duplicated.
497 int index = browser->tab_strip_model()->GetIndexOfTabContents(contents);
498 pinned = browser->tab_strip_model()->IsTabPinned(index);
499 int add_types = TabStripModel::ADD_ACTIVE |
500 TabStripModel::ADD_INHERIT_GROUP |
501 (pinned ? TabStripModel::ADD_PINNED : 0);
502 browser->tab_strip_model()->InsertTabContentsAt(
503 index + 1, contents_dupe, add_types);
504 } else {
505 Browser* browser = NULL;
506 if (browser->is_app()) {
507 CHECK(!browser->is_type_popup());
508 CHECK(!browser->is_type_panel());
509 browser = Browser::CreateWithParams(
510 Browser::CreateParams::CreateForApp(Browser::TYPE_POPUP,
511 browser->app_name(),
512 gfx::Rect(),
513 browser->profile()));
514 } else if (browser->is_type_popup()) {
515 browser = Browser::CreateWithParams(
516 Browser::CreateParams(Browser::TYPE_POPUP, browser->profile()));
517 }
518
519 // Preserve the size of the original window. The new window has already
520 // been given an offset by the OS, so we shouldn't copy the old bounds.
521 BrowserWindow* new_window = browser->window();
522 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
523 browser->window()->GetRestoredBounds().size()));
524
525 // We need to show the browser now. Otherwise ContainerWin assumes the
526 // WebContents is invisible and won't size it.
527 browser->window()->Show();
528
529 // The page transition below is only for the purpose of inserting the tab.
530 AddTab(browser, contents_dupe, content::PAGE_TRANSITION_LINK);
531 }
532
533 SessionService* session_service =
534 SessionServiceFactory::GetForProfileIfExisting(browser->profile());
535 if (session_service)
536 session_service->TabRestored(contents_dupe, pinned);
537}
538
539bool CanDuplicateTabAt(Browser* browser, int index) {
540 content::NavigationController& nc =
541 GetWebContentsAt(browser, index)->GetController();
542 return nc.GetWebContents() && nc.GetLastCommittedEntry();
543}
544
[email protected]a37d4b02012-06-25 21:56:10545void ConvertPopupToTabbedBrowser(Browser* browser) {
546 content::RecordAction(UserMetricsAction("ShowAsTab"));
547 TabContents* contents =
548 browser->tab_strip_model()->DetachTabContentsAt(browser->active_index());
549 Browser* b = Browser::Create(browser->profile());
550 b->tab_strip_model()->AppendTabContents(contents, true);
551 b->window()->Show();
552}
553
554void Exit() {
555 content::RecordAction(UserMetricsAction("Exit"));
556 browser::AttemptUserExit();
557}
558
559void BookmarkCurrentPage(Browser* browser) {
560 content::RecordAction(UserMetricsAction("Star"));
561
562 BookmarkModel* model = browser->profile()->GetBookmarkModel();
563 if (!model || !model->IsLoaded())
564 return; // Ignore requests until bookmarks are loaded.
565
566 GURL url;
567 string16 title;
[email protected]52877dbc62012-06-29 22:22:03568 TabContents* tab = GetActiveTabContents(browser);
[email protected]a37d4b02012-06-25 21:56:10569 bookmark_utils::GetURLAndTitleToBookmark(tab->web_contents(), &url, &title);
570 bool was_bookmarked = model->IsBookmarked(url);
571 if (!was_bookmarked && browser->profile()->IsOffTheRecord()) {
572 // If we're incognito the favicon may not have been saved. Save it now
573 // so that bookmarks have an icon for the page.
574 tab->favicon_tab_helper()->SaveFavicon();
575 }
576 bookmark_utils::AddIfNotBookmarked(model, url, title);
577 // Make sure the model actually added a bookmark before showing the star. A
578 // bookmark isn't created if the url is invalid.
579 if (browser->window()->IsActive() && model->IsBookmarked(url)) {
580 // Only show the bubble if the window is active, otherwise we may get into
581 // weird situations where the bubble is deleted as soon as it is shown.
582 browser->window()->ShowBookmarkBubble(url, was_bookmarked);
583 }
584}
585
[email protected]5d98294912012-06-27 22:57:40586bool CanBookmarkCurrentPage(const Browser* browser) {
587 BookmarkModel* model = browser->profile()->GetBookmarkModel();
588 return browser_defaults::bookmarks_enabled &&
589 browser->profile()->GetPrefs()->GetBoolean(
590 prefs::kEditBookmarksEnabled) &&
591 model && model->IsLoaded() && browser->is_type_tabbed();
592}
593
594void BookmarkAllTabs(Browser* browser) {
595 BookmarkEditor::ShowBookmarkAllTabsDialog(browser);
596}
597
598bool CanBookmarkAllTabs(const Browser* browser) {
599 return browser->tab_count() > 1 && CanBookmarkCurrentPage(browser);
600}
601
[email protected]a37d4b02012-06-25 21:56:10602#if !defined(OS_WIN)
603void PinCurrentPageToStartScreen(Browser* browser) {
604}
605#endif
606
607void SavePage(Browser* browser) {
608 content::RecordAction(UserMetricsAction("SavePage"));
[email protected]52877dbc62012-06-29 22:22:03609 WebContents* current_tab = GetActiveWebContents(browser);
[email protected]a37d4b02012-06-25 21:56:10610 if (current_tab && current_tab->GetContentsMimeType() == "application/pdf")
611 content::RecordAction(UserMetricsAction("PDF.SavePage"));
612 current_tab->OnSavePage();
613}
614
[email protected]5d98294912012-06-27 22:57:40615bool CanSavePage(const Browser* browser) {
616 // LocalState can be NULL in tests.
617 if (g_browser_process->local_state() &&
618 !g_browser_process->local_state()->GetBoolean(
619 prefs::kAllowFileSelectionDialogs)) {
620 return false;
621 }
622 return !browser->is_devtools() &&
623 !(GetContentRestrictions(browser) & content::CONTENT_RESTRICTION_SAVE);
624}
625
[email protected]a37d4b02012-06-25 21:56:10626void ShowFindBar(Browser* browser) {
627 browser->GetFindBarController()->Show();
628}
629
630void ShowPageInfo(Browser* browser,
631 content::WebContents* web_contents,
632 const GURL& url,
633 const SSLStatus& ssl,
634 bool show_history) {
635 Profile* profile = Profile::FromBrowserContext(
636 web_contents->GetBrowserContext());
637 TabContents* tab_contents = TabContents::FromWebContents(web_contents);
638
639 if (CommandLine::ForCurrentProcess()->HasSwitch(
640 switches::kEnableWebsiteSettings)) {
641 browser->window()->ShowWebsiteSettings(
642 profile, tab_contents, url, ssl, show_history);
643 } else {
644 browser->window()->ShowPageInfo(web_contents, url, ssl, show_history);
645 }
646}
647
648void ShowChromeToMobileBubble(Browser* browser) {
649 // Only show the bubble if the window is active, otherwise we may get into
650 // weird situations where the bubble is deleted as soon as it is shown.
651 if (browser->window()->IsActive())
652 browser->window()->ShowChromeToMobileBubble();
653}
654
655void Print(Browser* browser) {
656 if (g_browser_process->local_state()->GetBoolean(
657 prefs::kPrintPreviewDisabled)) {
[email protected]52877dbc62012-06-29 22:22:03658 GetActiveTabContents(browser)->print_view_manager()->PrintNow();
[email protected]a37d4b02012-06-25 21:56:10659 } else {
[email protected]52877dbc62012-06-29 22:22:03660 GetActiveTabContents(browser)->print_view_manager()->
661 PrintPreviewNow();
[email protected]a37d4b02012-06-25 21:56:10662 }
663}
664
[email protected]5d98294912012-06-27 22:57:40665bool CanPrint(const Browser* browser) {
666 // LocalState can be NULL in tests.
667 if (g_browser_process->local_state() &&
668 !g_browser_process->local_state()->GetBoolean(prefs::kPrintingEnabled)) {
669 return false;
670 }
671
672 // Do not print when a constrained window is showing. It's confusing.
[email protected]db9747252012-07-02 19:28:00673 // Do not print if instant extended API is enabled and mode is NTP.
[email protected]5d98294912012-06-27 22:57:40674 return !(HasConstrainedWindow(browser) ||
[email protected]db9747252012-07-02 19:28:00675 GetContentRestrictions(browser) & content::CONTENT_RESTRICTION_PRINT ||
676 IsNTPModeForInstantExtendedAPI(browser));
[email protected]5d98294912012-06-27 22:57:40677}
678
[email protected]a37d4b02012-06-25 21:56:10679void AdvancedPrint(Browser* browser) {
[email protected]52877dbc62012-06-29 22:22:03680 GetActiveTabContents(browser)->print_view_manager()->
681 AdvancedPrintNow();
[email protected]a37d4b02012-06-25 21:56:10682}
683
[email protected]5d98294912012-06-27 22:57:40684bool CanAdvancedPrint(const Browser* browser) {
685 // LocalState can be NULL in tests.
686 if (g_browser_process->local_state() &&
687 !g_browser_process->local_state()->GetBoolean(prefs::kPrintingEnabled)) {
688 return false;
689 }
690
691 // It is always possible to advanced print when print preview is visible.
692 return PrintPreviewShowing(browser) || CanPrint(browser);
693}
694
[email protected]d53e4032012-06-29 18:58:34695void PrintToDestination(Browser* browser) {
[email protected]52877dbc62012-06-29 22:22:03696 GetActiveTabContents(browser)->print_view_manager()->PrintToDestination();
[email protected]d53e4032012-06-29 18:58:34697}
698
[email protected]a37d4b02012-06-25 21:56:10699void EmailPageLocation(Browser* browser) {
700 content::RecordAction(UserMetricsAction("EmailPageLocation"));
[email protected]52877dbc62012-06-29 22:22:03701 WebContents* wc = GetActiveWebContents(browser);
[email protected]a37d4b02012-06-25 21:56:10702 DCHECK(wc);
703
704 std::string title = net::EscapeQueryParamValue(
705 UTF16ToUTF8(wc->GetTitle()), false);
706 std::string page_url = net::EscapeQueryParamValue(wc->GetURL().spec(), false);
707 std::string mailto = std::string("mailto:?subject=Fwd:%20") +
708 title + "&body=%0A%0A" + page_url;
709 platform_util::OpenExternal(GURL(mailto));
710}
711
[email protected]5d98294912012-06-27 22:57:40712bool CanEmailPageLocation(const Browser* browser) {
713 return browser->toolbar_model()->ShouldDisplayURL() &&
[email protected]52877dbc62012-06-29 22:22:03714 GetActiveWebContents(browser)->GetURL().is_valid();
[email protected]5d98294912012-06-27 22:57:40715}
716
[email protected]a37d4b02012-06-25 21:56:10717void Cut(Browser* browser) {
718 content::RecordAction(UserMetricsAction("Cut"));
719 browser->window()->Cut();
720}
721
722void Copy(Browser* browser) {
723 content::RecordAction(UserMetricsAction("Copy"));
724 browser->window()->Copy();
725}
726
727void Paste(Browser* browser) {
728 content::RecordAction(UserMetricsAction("Paste"));
729 browser->window()->Paste();
730}
731
732void Find(Browser* browser) {
733 content::RecordAction(UserMetricsAction("Find"));
734 FindInPage(browser, false, false);
735}
736
737void FindNext(Browser* browser) {
738 content::RecordAction(UserMetricsAction("FindNext"));
739 FindInPage(browser, true, true);
740}
741
742void FindPrevious(Browser* browser) {
743 content::RecordAction(UserMetricsAction("FindPrevious"));
744 FindInPage(browser, true, false);
745}
746
747void FindInPage(Browser* browser, bool find_next, bool forward_direction) {
748 ShowFindBar(browser);
749 if (find_next) {
750 string16 find_text;
751#if defined(OS_MACOSX)
752 // We always want to search for the contents of the find pasteboard on OS X.
753 find_text = GetFindPboardText();
754#endif
[email protected]52877dbc62012-06-29 22:22:03755 GetActiveTabContents(browser)->
[email protected]a37d4b02012-06-25 21:56:10756 find_tab_helper()->StartFinding(find_text,
757 forward_direction,
758 false); // Not case sensitive.
759 }
760}
761
762void Zoom(Browser* browser, content::PageZoom zoom) {
763 if (browser->is_devtools())
764 return;
765
[email protected]8233cbc2012-07-13 16:14:52766 chrome_page_zoom::Zoom(GetActiveWebContents(browser), zoom);
[email protected]a37d4b02012-06-25 21:56:10767}
768
769void FocusToolbar(Browser* browser) {
770 content::RecordAction(UserMetricsAction("FocusToolbar"));
771 browser->window()->FocusToolbar();
772}
773
774void FocusLocationBar(Browser* browser) {
775 content::RecordAction(UserMetricsAction("FocusLocation"));
776 browser->window()->SetFocusToLocationBar(true);
777}
778
779void FocusSearch(Browser* browser) {
780 // TODO(beng): replace this with FocusLocationBar
781 content::RecordAction(UserMetricsAction("FocusSearch"));
782 browser->window()->GetLocationBar()->FocusSearch();
783}
784
785void FocusAppMenu(Browser* browser) {
786 content::RecordAction(UserMetricsAction("FocusAppMenu"));
787 browser->window()->FocusAppMenu();
788}
789
790void FocusBookmarksToolbar(Browser* browser) {
791 content::RecordAction(UserMetricsAction("FocusBookmarksToolbar"));
792 browser->window()->FocusBookmarksToolbar();
793}
794
795void FocusNextPane(Browser* browser) {
796 content::RecordAction(UserMetricsAction("FocusNextPane"));
797 browser->window()->RotatePaneFocus(true);
798}
799
800void FocusPreviousPane(Browser* browser) {
801 content::RecordAction(UserMetricsAction("FocusPreviousPane"));
802 browser->window()->RotatePaneFocus(false);
803}
804
805void ToggleDevToolsWindow(Browser* browser, DevToolsToggleAction action) {
806 if (action == DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE)
807 content::RecordAction(UserMetricsAction("DevTools_ToggleConsole"));
808 else
809 content::RecordAction(UserMetricsAction("DevTools_ToggleWindow"));
810
811 DevToolsWindow::ToggleDevToolsWindow(
[email protected]52877dbc62012-06-29 22:22:03812 GetActiveWebContents(browser)->GetRenderViewHost(),
[email protected]a37d4b02012-06-25 21:56:10813 action);
814}
815
816bool CanOpenTaskManager() {
817#if defined(OS_WIN)
818 // In metro we can't display the task manager, as it is a native window.
819 return !base::win::IsMetroProcess();
820#else
821 return true;
822#endif
823}
824
825void OpenTaskManager(Browser* browser, bool highlight_background_resources) {
826 content::RecordAction(UserMetricsAction("TaskManager"));
827 if (highlight_background_resources)
828 browser->window()->ShowBackgroundPages();
829 else
830 browser->window()->ShowTaskManager();
831}
832
833void OpenFeedbackDialog(Browser* browser) {
834 content::RecordAction(UserMetricsAction("Feedback"));
835 browser::ShowWebFeedbackView(browser, std::string(), std::string());
836}
837
838void ToggleBookmarkBar(Browser* browser) {
839 content::RecordAction(UserMetricsAction("ShowBookmarksBar"));
840 browser->window()->ToggleBookmarkBar();
841}
842
843void ShowAppMenu(Browser* browser) {
844 // We record the user metric for this event in WrenchMenu::RunMenu.
845 browser->window()->ShowAppMenu();
846}
847
848void ShowAvatarMenu(Browser* browser) {
849 browser->window()->ShowAvatarBubbleFromAvatarButton();
850}
851
852void OpenUpdateChromeDialog(Browser* browser) {
853 content::RecordAction(UserMetricsAction("UpdateChrome"));
854 browser->window()->ShowUpdateChromeDialog();
855}
856
857void ToggleSpeechInput(Browser* browser) {
[email protected]52877dbc62012-06-29 22:22:03858 GetActiveWebContents(browser)->GetRenderViewHost()->ToggleSpeechInput();
[email protected]a37d4b02012-06-25 21:56:10859}
860
[email protected]3f32b9b2012-07-09 16:59:28861void ToggleFullscreenMode(Browser* browser) {
862 browser->fullscreen_controller()->ToggleFullscreenMode();
863}
864
[email protected]d3446bda2012-07-12 14:24:39865void ClearCache(Browser* browser) {
866 BrowsingDataRemover* remover = new BrowsingDataRemover(browser->profile(),
867 BrowsingDataRemover::EVERYTHING,
868 base::Time());
869 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
870 BrowsingDataHelper::UNPROTECTED_WEB);
871 // BrowsingDataRemover takes care of deleting itself when done.
872}
873
874bool IsDebuggerAttachedToCurrentTab(Browser* browser) {
875 WebContents* contents = chrome::GetActiveWebContents(browser);
876 return contents ?
877 content::DevToolsAgentHostRegistry::IsDebuggerAttached(contents) : false;
878}
879
[email protected]2cd4fde2012-06-26 03:10:26880void ViewSource(Browser* browser, TabContents* contents) {
881 DCHECK(contents);
882
883 NavigationEntry* active_entry =
884 contents->web_contents()->GetController().GetActiveEntry();
885 if (!active_entry)
886 return;
887
888 ViewSource(browser, contents, active_entry->GetURL(),
889 active_entry->GetContentState());
890}
891
892void ViewSource(Browser* browser,
893 TabContents* contents,
894 const GURL& url,
895 const std::string& content_state) {
896 content::RecordAction(UserMetricsAction("ViewSource"));
897 DCHECK(contents);
898
899 TabContents* view_source_contents = contents->Clone();
900 view_source_contents->web_contents()->GetController().PruneAllButActive();
901 NavigationEntry* active_entry =
902 view_source_contents->web_contents()->GetController().GetActiveEntry();
903 if (!active_entry)
904 return;
905
[email protected]52877dbc62012-06-29 22:22:03906 GURL view_source_url = GURL(kViewSourceScheme + std::string(":") +
[email protected]2cd4fde2012-06-26 03:10:26907 url.spec());
908 active_entry->SetVirtualURL(view_source_url);
909
910 // Do not restore scroller position.
911 active_entry->SetContentState(
912 webkit_glue::RemoveScrollOffsetFromHistoryState(content_state));
913
914 // Do not restore title, derive it from the url.
915 active_entry->SetTitle(string16());
916
917 // Now show view-source entry.
918 if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) {
919 // If this is a tabbed browser, just create a duplicate tab inside the same
920 // window next to the tab being duplicated.
921 int index = browser->tab_strip_model()->GetIndexOfTabContents(contents);
922 int add_types = TabStripModel::ADD_ACTIVE |
923 TabStripModel::ADD_INHERIT_GROUP;
924 browser->tab_strip_model()->InsertTabContentsAt(index + 1,
925 view_source_contents,
926 add_types);
927 } else {
928 Browser* b = Browser::CreateWithParams(
929 Browser::CreateParams(Browser::TYPE_TABBED, browser->profile()));
930
931 // Preserve the size of the original window. The new window has already
932 // been given an offset by the OS, so we shouldn't copy the old bounds.
933 BrowserWindow* new_window = b->window();
934 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
935 browser->window()->GetRestoredBounds().size()));
936
937 // We need to show the browser now. Otherwise ContainerWin assumes the
938 // WebContents is invisible and won't size it.
939 b->window()->Show();
940
941 // The page transition below is only for the purpose of inserting the tab.
[email protected]855370052012-07-10 19:30:32942 AddTab(b, view_source_contents, content::PAGE_TRANSITION_LINK);
[email protected]2cd4fde2012-06-26 03:10:26943 }
944
945 SessionService* session_service =
946 SessionServiceFactory::GetForProfileIfExisting(browser->profile());
947 if (session_service)
948 session_service->TabRestored(view_source_contents, false);
949}
950
951void ViewSelectedSource(Browser* browser) {
[email protected]855370052012-07-10 19:30:32952 ViewSource(browser, GetActiveTabContents(browser));
[email protected]2cd4fde2012-06-26 03:10:26953}
954
[email protected]5d98294912012-06-27 22:57:40955bool CanViewSource(const Browser* browser) {
[email protected]855370052012-07-10 19:30:32956 return GetActiveWebContents(browser)->GetController().CanViewSource();
[email protected]5d98294912012-06-27 22:57:40957}
958
[email protected]619f86182012-07-03 21:30:18959void CreateApplicationShortcuts(Browser* browser) {
960 content::RecordAction(UserMetricsAction("CreateShortcut"));
[email protected]855370052012-07-10 19:30:32961 GetActiveTabContents(browser)->extension_tab_helper()->
[email protected]619f86182012-07-03 21:30:18962 CreateApplicationShortcuts();
963}
964
[email protected]5d98294912012-06-27 22:57:40965bool CanCreateApplicationShortcuts(const Browser* browser) {
[email protected]855370052012-07-10 19:30:32966 return GetActiveTabContents(browser)->extension_tab_helper()->
[email protected]619f86182012-07-03 21:30:18967 CanCreateApplicationShortcuts();
[email protected]5d98294912012-06-27 22:57:40968}
969
[email protected]40df6f52012-06-28 17:08:52970void ConvertTabToAppWindow(Browser* browser,
971 content::WebContents* contents) {
972 const GURL& url = contents->GetController().GetActiveEntry()->GetURL();
973 std::string app_name = web_app::GenerateApplicationNameFromURL(url);
974
975 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents);
976 if (index >= 0)
977 browser->tab_strip_model()->DetachTabContentsAt(index);
978
979 Browser* app_browser = Browser::CreateWithParams(
980 Browser::CreateParams::CreateForApp(
981 Browser::TYPE_POPUP, app_name, gfx::Rect(), browser->profile()));
982 TabContents* tab_contents = TabContents::FromWebContents(contents);
983 if (!tab_contents)
984 tab_contents = new TabContents(contents);
985 app_browser->tab_strip_model()->AppendTabContents(tab_contents, true);
986
987 contents->GetMutableRendererPrefs()->can_accept_load_drops = false;
988 contents->GetRenderViewHost()->SyncRendererPrefs();
989 app_browser->window()->Show();
990}
991
[email protected]a37d4b02012-06-25 21:56:10992} // namespace chrome