blob: e918faa6c064b9c4d5b88c06e3fe6fc0fa816c77 [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"
14#include "chrome/browser/chrome_page_zoom.h"
15#include "chrome/browser/debugger/devtools_window.h"
[email protected]5d98294912012-06-27 22:57:4016#include "chrome/browser/download/download_util.h"
[email protected]a37d4b02012-06-25 21:56:1017#include "chrome/browser/extensions/extension_service.h"
[email protected]619f86182012-07-03 21:30:1818#include "chrome/browser/extensions/extension_tab_helper.h"
[email protected]a37d4b02012-06-25 21:56:1019#include "chrome/browser/favicon/favicon_tab_helper.h"
20#include "chrome/browser/lifetime/application_lifetime.h"
21#include "chrome/browser/platform_util.h"
22#include "chrome/browser/prefs/incognito_mode_prefs.h"
23#include "chrome/browser/prefs/pref_service.h"
[email protected]5d98294912012-06-27 22:57:4024#include "chrome/browser/printing/print_preview_tab_controller.h"
[email protected]a37d4b02012-06-25 21:56:1025#include "chrome/browser/printing/print_view_manager.h"
26#include "chrome/browser/profiles/profile.h"
27#include "chrome/browser/sessions/session_service_factory.h"
[email protected]a37d4b02012-06-25 21:56:1028#include "chrome/browser/sessions/tab_restore_service.h"
[email protected]5d98294912012-06-27 22:57:4029#include "chrome/browser/sessions/tab_restore_service_delegate.h"
[email protected]78e2edc2012-07-01 23:32:2830#include "chrome/browser/sessions/tab_restore_service_factory.h"
[email protected]a37d4b02012-06-25 21:56:1031#include "chrome/browser/ui/browser.h"
[email protected]5d98294912012-06-27 22:57:4032#include "chrome/browser/ui/browser_command_controller.h"
[email protected]a37d4b02012-06-25 21:56:1033#include "chrome/browser/ui/browser_finder.h"
[email protected]7acfaf92012-07-11 15:51:5934#include "chrome/browser/ui/browser_instant_controller.h"
[email protected]5d98294912012-06-27 22:57:4035#include "chrome/browser/ui/browser_tab_restore_service_delegate.h"
[email protected]52877dbc62012-06-29 22:22:0336#include "chrome/browser/ui/browser_tabstrip.h"
[email protected]a37d4b02012-06-25 21:56:1037#include "chrome/browser/ui/browser_window.h"
[email protected]5d98294912012-06-27 22:57:4038#include "chrome/browser/ui/constrained_window_tab_helper.h"
[email protected]a37d4b02012-06-25 21:56:1039#include "chrome/browser/ui/find_bar/find_bar_controller.h"
40#include "chrome/browser/ui/find_bar/find_tab_helper.h"
[email protected]3f32b9b2012-07-09 16:59:2841#include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
[email protected]a37d4b02012-06-25 21:56:1042#include "chrome/browser/ui/omnibox/location_bar.h"
[email protected]43aafff2012-06-29 21:20:4943#include "chrome/browser/ui/search/search.h"
44#include "chrome/browser/ui/search/search_model.h"
[email protected]a37d4b02012-06-25 21:56:1045#include "chrome/browser/ui/status_bubble.h"
46#include "chrome/browser/ui/tab_contents/tab_contents.h"
47#include "chrome/browser/ui/tabs/tab_strip_model.h"
48#include "chrome/browser/ui/webui/feedback_ui.h"
49#include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
[email protected]5d98294912012-06-27 22:57:4050#include "chrome/browser/web_applications/web_app.h"
[email protected]a37d4b02012-06-25 21:56:1051#include "chrome/common/chrome_switches.h"
[email protected]a37d4b02012-06-25 21:56:1052#include "chrome/common/pref_names.h"
53#include "content/public/browser/navigation_controller.h"
54#include "content/public/browser/navigation_entry.h"
55#include "content/public/browser/page_navigator.h"
56#include "content/public/browser/render_view_host.h"
57#include "content/public/browser/user_metrics.h"
58#include "content/public/browser/web_contents.h"
59#include "content/public/browser/web_contents_view.h"
[email protected]78e2edc2012-07-01 23:32:2860#include "content/public/common/content_restriction.h"
61#include "content/public/common/renderer_preferences.h"
[email protected]2cd4fde2012-06-26 03:10:2662#include "content/public/common/url_constants.h"
[email protected]a37d4b02012-06-25 21:56:1063#include "net/base/escape.h"
[email protected]2cd4fde2012-06-26 03:10:2664#include "webkit/glue/webkit_glue.h"
[email protected]a37d4b02012-06-25 21:56:1065
66#if defined(OS_MACOSX)
67#include "ui/base/cocoa/find_pasteboard.h"
68#endif
69
70#if defined(OS_WIN)
71#include "base/win/metro.h"
72#endif
73
74using content::NavigationController;
75using content::NavigationEntry;
76using content::OpenURLParams;
77using content::Referrer;
78using content::SSLStatus;
79using content::UserMetricsAction;
80using content::WebContents;
81
82namespace chrome {
83namespace {
84
85WebContents* GetOrCloneTabForDisposition(Browser* browser,
86 WindowOpenDisposition disposition) {
[email protected]855370052012-07-10 19:30:3287 TabContents* current_tab = GetActiveTabContents(browser);
[email protected]a37d4b02012-06-25 21:56:1088 switch (disposition) {
89 case NEW_FOREGROUND_TAB:
90 case NEW_BACKGROUND_TAB: {
91 current_tab = current_tab->Clone();
92 browser->tab_strip_model()->AddTabContents(
93 current_tab, -1, content::PAGE_TRANSITION_LINK,
94 disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_ACTIVE :
95 TabStripModel::ADD_NONE);
96 break;
97 }
98 case NEW_WINDOW: {
99 current_tab = current_tab->Clone();
100 Browser* b = Browser::Create(browser->profile());
101 b->tab_strip_model()->AddTabContents(
102 current_tab, -1, content::PAGE_TRANSITION_LINK,
103 TabStripModel::ADD_ACTIVE);
104 b->window()->Show();
105 break;
106 }
107 default:
108 break;
109 }
110 return current_tab->web_contents();
111}
112
113void ReloadInternal(Browser* browser,
114 WindowOpenDisposition disposition,
115 bool ignore_cache) {
116 // If we are showing an interstitial, treat this as an OpenURL.
[email protected]855370052012-07-10 19:30:32117 WebContents* current_tab = GetActiveWebContents(browser);
[email protected]a37d4b02012-06-25 21:56:10118 if (current_tab && current_tab->ShowingInterstitialPage()) {
119 NavigationEntry* entry = current_tab->GetController().GetActiveEntry();
120 DCHECK(entry); // Should exist if interstitial is showing.
121 browser->OpenURL(OpenURLParams(
122 entry->GetURL(), Referrer(), disposition,
123 content::PAGE_TRANSITION_RELOAD, false));
124 return;
125 }
126
127 // As this is caused by a user action, give the focus to the page.
128 //
129 // Also notify RenderViewHostDelegate of the user gesture; this is
130 // normally done in Browser::Navigate, but a reload bypasses Navigate.
131 WebContents* web_contents = GetOrCloneTabForDisposition(browser, disposition);
132 web_contents->UserGestureDone();
133 if (!web_contents->FocusLocationBarByDefault())
134 web_contents->Focus();
135 if (ignore_cache)
136 web_contents->GetController().ReloadIgnoringCache(true);
137 else
138 web_contents->GetController().Reload(true);
139}
140
[email protected]5d98294912012-06-27 22:57:40141bool HasConstrainedWindow(const Browser* browser) {
[email protected]52877dbc62012-06-29 22:22:03142 TabContents* tab_contents = GetActiveTabContents(browser);
[email protected]5d98294912012-06-27 22:57:40143 return tab_contents && tab_contents->constrained_window_tab_helper()->
144 constrained_window_count();
145}
146
147bool PrintPreviewShowing(const Browser* browser) {
[email protected]52877dbc62012-06-29 22:22:03148 TabContents* contents = GetActiveTabContents(browser);
[email protected]5d98294912012-06-27 22:57:40149 printing::PrintPreviewTabController* controller =
150 printing::PrintPreviewTabController::GetInstance();
151 return controller && (controller->GetPrintPreviewForTab(contents) ||
152 controller->is_creating_print_preview_tab());
153}
154
[email protected]db9747252012-07-02 19:28:00155bool IsNTPModeForInstantExtendedAPI(const Browser* browser) {
156 return browser->search_model() &&
[email protected]855370052012-07-10 19:30:32157 search::IsInstantExtendedAPIEnabled(browser->profile()) &&
158 browser->search_model()->mode().is_ntp();
[email protected]db9747252012-07-02 19:28:00159}
160
[email protected]a37d4b02012-06-25 21:56:10161} // namespace
162
[email protected]5d98294912012-06-27 22:57:40163bool IsCommandEnabled(Browser* browser, int command) {
164 return browser->command_controller()->command_updater()->IsCommandEnabled(
165 command);
166}
167
168bool SupportsCommand(Browser* browser, int command) {
169 return browser->command_controller()->command_updater()->SupportsCommand(
170 command);
171}
172
173bool ExecuteCommand(Browser* browser, int command) {
174 return browser->command_controller()->command_updater()->ExecuteCommand(
175 command);
176}
177
178bool ExecuteCommandWithDisposition(Browser* browser,
179 int command,
180 WindowOpenDisposition disposition) {
181 return browser->command_controller()->command_updater()->
182 ExecuteCommandWithDisposition(command, disposition);
183}
184
185void UpdateCommandEnabled(Browser* browser, int command, bool enabled) {
186 browser->command_controller()->command_updater()->UpdateCommandEnabled(
187 command, enabled);
188}
189
190void AddCommandObserver(Browser* browser,
191 int command,
192 CommandObserver* observer) {
193 browser->command_controller()->command_updater()->AddCommandObserver(
194 command, observer);
195}
196
197void RemoveCommandObserver(Browser* browser,
198 int command,
199 CommandObserver* observer) {
200 browser->command_controller()->command_updater()->RemoveCommandObserver(
201 command, observer);
202}
203
204int GetContentRestrictions(const Browser* browser) {
205 int content_restrictions = 0;
[email protected]52877dbc62012-06-29 22:22:03206 WebContents* current_tab = GetActiveWebContents(browser);
[email protected]5d98294912012-06-27 22:57:40207 if (current_tab) {
208 content_restrictions = current_tab->GetContentRestrictions();
209 NavigationEntry* active_entry =
210 current_tab->GetController().GetActiveEntry();
211 // See comment in UpdateCommandsForTabState about why we call url().
212 if (!download_util::IsSavableURL(
213 active_entry ? active_entry->GetURL() : GURL()) ||
214 current_tab->ShowingInterstitialPage())
215 content_restrictions |= content::CONTENT_RESTRICTION_SAVE;
216 if (current_tab->ShowingInterstitialPage())
217 content_restrictions |= content::CONTENT_RESTRICTION_PRINT;
218 }
219 return content_restrictions;
220}
221
[email protected]a37d4b02012-06-25 21:56:10222void NewEmptyWindow(Profile* profile) {
223 bool incognito = profile->IsOffTheRecord();
224 PrefService* prefs = profile->GetPrefs();
225 if (incognito) {
226 if (IncognitoModePrefs::GetAvailability(prefs) ==
227 IncognitoModePrefs::DISABLED) {
228 incognito = false;
229 }
230 } else {
231 if (browser_defaults::kAlwaysOpenIncognitoWindow &&
232 IncognitoModePrefs::ShouldLaunchIncognito(
233 *CommandLine::ForCurrentProcess(), prefs)) {
234 incognito = true;
235 }
236 }
237
238 if (incognito) {
239 content::RecordAction(UserMetricsAction("NewIncognitoWindow"));
240 OpenEmptyWindow(profile->GetOffTheRecordProfile());
241 } else {
242 content::RecordAction(UserMetricsAction("NewWindow"));
243 SessionService* session_service =
244 SessionServiceFactory::GetForProfile(profile->GetOriginalProfile());
245 if (!session_service ||
246 !session_service->RestoreIfNecessary(std::vector<GURL>())) {
247 OpenEmptyWindow(profile->GetOriginalProfile());
248 }
249 }
250}
251
252Browser* OpenEmptyWindow(Profile* profile) {
253 Browser* browser = Browser::Create(profile);
[email protected]855370052012-07-10 19:30:32254 AddBlankTab(browser, true);
[email protected]a37d4b02012-06-25 21:56:10255 browser->window()->Show();
256 return browser;
257}
258
259void OpenWindowWithRestoredTabs(Profile* profile) {
260 TabRestoreService* service = TabRestoreServiceFactory::GetForProfile(profile);
261 if (service)
262 service->RestoreMostRecentEntry(NULL);
263}
264
265void OpenURLOffTheRecord(Profile* profile, const GURL& url) {
266 Browser* browser = browser::FindOrCreateTabbedBrowser(
267 profile->GetOffTheRecordProfile());
[email protected]52877dbc62012-06-29 22:22:03268 AddSelectedTabWithURL(browser, url, content::PAGE_TRANSITION_LINK);
[email protected]a37d4b02012-06-25 21:56:10269 browser->window()->Show();
270}
271
[email protected]5d98294912012-06-27 22:57:40272bool CanGoBack(const Browser* browser) {
[email protected]52877dbc62012-06-29 22:22:03273 return GetActiveWebContents(browser)->GetController().CanGoBack();
[email protected]a37d4b02012-06-25 21:56:10274}
275
276void GoBack(Browser* browser, WindowOpenDisposition disposition) {
277 content::RecordAction(UserMetricsAction("Back"));
278
[email protected]52877dbc62012-06-29 22:22:03279 TabContents* current_tab = GetActiveTabContents(browser);
[email protected]a37d4b02012-06-25 21:56:10280 if (CanGoBack(browser)) {
281 WebContents* new_tab = GetOrCloneTabForDisposition(browser, disposition);
282 // If we are on an interstitial page and clone the tab, it won't be copied
283 // to the new tab, so we don't need to go back.
284 if (current_tab->web_contents()->ShowingInterstitialPage() &&
285 (new_tab != current_tab->web_contents()))
286 return;
287 new_tab->GetController().GoBack();
288 }
289}
290
[email protected]5d98294912012-06-27 22:57:40291bool CanGoForward(const Browser* browser) {
[email protected]52877dbc62012-06-29 22:22:03292 return GetActiveWebContents(browser)->GetController().CanGoForward();
[email protected]a37d4b02012-06-25 21:56:10293}
294
295void GoForward(Browser* browser, WindowOpenDisposition disposition) {
296 content::RecordAction(UserMetricsAction("Forward"));
297 if (CanGoForward(browser)) {
298 GetOrCloneTabForDisposition(browser, disposition)->
299 GetController().GoForward();
300 }
301}
302
303bool NavigateToIndexWithDisposition(Browser* browser,
304 int index,
305 WindowOpenDisposition disp) {
306 NavigationController& controller =
307 GetOrCloneTabForDisposition(browser, disp)->GetController();
308 if (index < 0 || index >= controller.GetEntryCount())
309 return false;
310 controller.GoToIndex(index);
311 return true;
312}
313
314void Reload(Browser* browser, WindowOpenDisposition disposition) {
315 content::RecordAction(UserMetricsAction("Reload"));
316 ReloadInternal(browser, disposition, false);
317}
318
319void ReloadIgnoringCache(Browser* browser, WindowOpenDisposition disposition) {
320 content::RecordAction(UserMetricsAction("ReloadIgnoringCache"));
321 ReloadInternal(browser, disposition, true);
322}
323
[email protected]5d98294912012-06-27 22:57:40324bool CanReload(const Browser* browser) {
[email protected]db9747252012-07-02 19:28:00325 return !browser->is_devtools() && !IsNTPModeForInstantExtendedAPI(browser);
[email protected]5d98294912012-06-27 22:57:40326}
327
[email protected]a37d4b02012-06-25 21:56:10328void Home(Browser* browser, WindowOpenDisposition disposition) {
329 content::RecordAction(UserMetricsAction("Home"));
330 browser->OpenURL(OpenURLParams(
331 browser->profile()->GetHomePage(), Referrer(), disposition,
332 content::PageTransitionFromInt(
333 content::PAGE_TRANSITION_AUTO_BOOKMARK |
334 content::PAGE_TRANSITION_HOME_PAGE),
335 false));
336}
337
338void OpenCurrentURL(Browser* browser) {
339 content::RecordAction(UserMetricsAction("LoadURL"));
340 LocationBar* location_bar = browser->window()->GetLocationBar();
341 if (!location_bar)
342 return;
343
344 WindowOpenDisposition open_disposition =
345 location_bar->GetWindowOpenDisposition();
[email protected]7acfaf92012-07-11 15:51:59346 if (browser->instant_controller()->OpenInstant(open_disposition))
[email protected]a37d4b02012-06-25 21:56:10347 return;
348
349 GURL url(location_bar->GetInputString());
350
[email protected]855370052012-07-10 19:30:32351 NavigateParams params(browser, url, location_bar->GetPageTransition());
[email protected]a37d4b02012-06-25 21:56:10352 params.disposition = open_disposition;
353 // Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least
354 // inherit the opener. In some cases the tabstrip will determine the group
355 // should be inherited, in which case the group is inherited instead of the
356 // opener.
357 params.tabstrip_add_types =
358 TabStripModel::ADD_FORCE_INDEX | TabStripModel::ADD_INHERIT_OPENER;
[email protected]855370052012-07-10 19:30:32359 Navigate(&params);
[email protected]a37d4b02012-06-25 21:56:10360
361 DCHECK(browser->profile()->GetExtensionService());
362 if (browser->profile()->GetExtensionService()->IsInstalledApp(url)) {
363 AppLauncherHandler::RecordAppLaunchType(
364 extension_misc::APP_LAUNCH_OMNIBOX_LOCATION);
365 }
366}
367
368void Stop(Browser* browser) {
369 content::RecordAction(UserMetricsAction("Stop"));
[email protected]52877dbc62012-06-29 22:22:03370 GetActiveWebContents(browser)->Stop();
[email protected]a37d4b02012-06-25 21:56:10371}
372
373#if !defined(OS_WIN)
374void NewWindow(Browser* browser) {
375 NewEmptyWindow(browser->profile()->GetOriginalProfile());
376}
377
378void NewIncognitoWindow(Browser* browser) {
379 NewEmptyWindow(browser->profile()->GetOffTheRecordProfile());
380}
381#endif // OS_WIN
382
383void CloseWindow(Browser* browser) {
384 content::RecordAction(UserMetricsAction("CloseWindow"));
385 browser->window()->Close();
386}
387
388void NewTab(Browser* browser) {
389 content::RecordAction(UserMetricsAction("NewTab"));
390 // TODO(asvitkine): This is invoked programmatically from several places.
391 // Audit the code and change it so that the histogram only gets collected for
392 // user-initiated commands.
393 UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", TabStripModel::NEW_TAB_COMMAND,
394 TabStripModel::NEW_TAB_ENUM_COUNT);
395
396 if (browser->is_type_tabbed()) {
[email protected]855370052012-07-10 19:30:32397 AddBlankTab(browser, true);
[email protected]52877dbc62012-06-29 22:22:03398 GetActiveWebContents(browser)->GetView()->RestoreFocus();
[email protected]a37d4b02012-06-25 21:56:10399 } else {
400 Browser* b = browser::FindOrCreateTabbedBrowser(browser->profile());
[email protected]855370052012-07-10 19:30:32401 AddBlankTab(b, true);
[email protected]a37d4b02012-06-25 21:56:10402 b->window()->Show();
403 // The call to AddBlankTab above did not set the focus to the tab as its
404 // window was not active, so we have to do it explicitly.
405 // See http://crbug.com/6380.
[email protected]855370052012-07-10 19:30:32406 GetActiveWebContents(b)->GetView()->RestoreFocus();
[email protected]a37d4b02012-06-25 21:56:10407 }
408}
409
410void CloseTab(Browser* browser) {
411 content::RecordAction(UserMetricsAction("CloseTab_Accelerator"));
412 browser->tab_strip_model()->CloseSelectedTabs();
413}
414
[email protected]5d98294912012-06-27 22:57:40415void RestoreTab(Browser* browser) {
416 content::RecordAction(UserMetricsAction("RestoreTab"));
417 TabRestoreService* service =
418 TabRestoreServiceFactory::GetForProfile(browser->profile());
419 if (service)
420 service->RestoreMostRecentEntry(browser->tab_restore_service_delegate());
421}
422
423bool CanRestoreTab(const Browser* browser) {
424 TabRestoreService* service =
425 TabRestoreServiceFactory::GetForProfile(browser->profile());
426 return service && !service->entries().empty();
427}
428
[email protected]a37d4b02012-06-25 21:56:10429void SelectNextTab(Browser* browser) {
430 content::RecordAction(UserMetricsAction("SelectNextTab"));
431 browser->tab_strip_model()->SelectNextTab();
432}
433
434void SelectPreviousTab(Browser* browser) {
435 content::RecordAction(UserMetricsAction("SelectPrevTab"));
436 browser->tab_strip_model()->SelectPreviousTab();
437}
438
439void OpenTabpose(Browser* browser) {
440#if defined(OS_MACOSX)
441 if (!CommandLine::ForCurrentProcess()->HasSwitch(
442 switches::kEnableExposeForTabs)) {
443 return;
444 }
445
446 content::RecordAction(UserMetricsAction("OpenTabpose"));
447 browser->window()->OpenTabpose();
448#else
449 NOTREACHED();
450#endif
451}
452
453void MoveTabNext(Browser* browser) {
454 content::RecordAction(UserMetricsAction("MoveTabNext"));
455 browser->tab_strip_model()->MoveTabNext();
456}
457
458void MoveTabPrevious(Browser* browser) {
459 content::RecordAction(UserMetricsAction("MoveTabPrevious"));
460 browser->tab_strip_model()->MoveTabPrevious();
461}
462
463void SelectNumberedTab(Browser* browser, int index) {
464 if (index < browser->tab_count()) {
465 content::RecordAction(UserMetricsAction("SelectNumberedTab"));
[email protected]52877dbc62012-06-29 22:22:03466 ActivateTabAt(browser, index, true);
[email protected]a37d4b02012-06-25 21:56:10467 }
468}
469
470void SelectLastTab(Browser* browser) {
471 content::RecordAction(UserMetricsAction("SelectLastTab"));
472 browser->tab_strip_model()->SelectLastTab();
473}
474
475void DuplicateTab(Browser* browser) {
476 content::RecordAction(UserMetricsAction("Duplicate"));
[email protected]855370052012-07-10 19:30:32477 DuplicateTabAt(browser, browser->active_index());
[email protected]a37d4b02012-06-25 21:56:10478}
479
[email protected]5d98294912012-06-27 22:57:40480bool CanDuplicateTab(const Browser* browser) {
[email protected]52877dbc62012-06-29 22:22:03481 WebContents* contents = GetActiveWebContents(browser);
[email protected]5d98294912012-06-27 22:57:40482 return contents && contents->GetController().GetLastCommittedEntry();
483}
484
[email protected]855370052012-07-10 19:30:32485void DuplicateTabAt(Browser* browser, int index) {
486 TabContents* contents = GetTabContentsAt(browser, index);
487 CHECK(contents);
488 TabContents* contents_dupe = contents->Clone();
489
490 bool pinned = false;
491 if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) {
492 // If this is a tabbed browser, just create a duplicate tab inside the same
493 // window next to the tab being duplicated.
494 int index = browser->tab_strip_model()->GetIndexOfTabContents(contents);
495 pinned = browser->tab_strip_model()->IsTabPinned(index);
496 int add_types = TabStripModel::ADD_ACTIVE |
497 TabStripModel::ADD_INHERIT_GROUP |
498 (pinned ? TabStripModel::ADD_PINNED : 0);
499 browser->tab_strip_model()->InsertTabContentsAt(
500 index + 1, contents_dupe, add_types);
501 } else {
502 Browser* browser = NULL;
503 if (browser->is_app()) {
504 CHECK(!browser->is_type_popup());
505 CHECK(!browser->is_type_panel());
506 browser = Browser::CreateWithParams(
507 Browser::CreateParams::CreateForApp(Browser::TYPE_POPUP,
508 browser->app_name(),
509 gfx::Rect(),
510 browser->profile()));
511 } else if (browser->is_type_popup()) {
512 browser = Browser::CreateWithParams(
513 Browser::CreateParams(Browser::TYPE_POPUP, browser->profile()));
514 }
515
516 // Preserve the size of the original window. The new window has already
517 // been given an offset by the OS, so we shouldn't copy the old bounds.
518 BrowserWindow* new_window = browser->window();
519 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
520 browser->window()->GetRestoredBounds().size()));
521
522 // We need to show the browser now. Otherwise ContainerWin assumes the
523 // WebContents is invisible and won't size it.
524 browser->window()->Show();
525
526 // The page transition below is only for the purpose of inserting the tab.
527 AddTab(browser, contents_dupe, content::PAGE_TRANSITION_LINK);
528 }
529
530 SessionService* session_service =
531 SessionServiceFactory::GetForProfileIfExisting(browser->profile());
532 if (session_service)
533 session_service->TabRestored(contents_dupe, pinned);
534}
535
536bool CanDuplicateTabAt(Browser* browser, int index) {
537 content::NavigationController& nc =
538 GetWebContentsAt(browser, index)->GetController();
539 return nc.GetWebContents() && nc.GetLastCommittedEntry();
540}
541
[email protected]a37d4b02012-06-25 21:56:10542void ConvertPopupToTabbedBrowser(Browser* browser) {
543 content::RecordAction(UserMetricsAction("ShowAsTab"));
544 TabContents* contents =
545 browser->tab_strip_model()->DetachTabContentsAt(browser->active_index());
546 Browser* b = Browser::Create(browser->profile());
547 b->tab_strip_model()->AppendTabContents(contents, true);
548 b->window()->Show();
549}
550
551void Exit() {
552 content::RecordAction(UserMetricsAction("Exit"));
553 browser::AttemptUserExit();
554}
555
556void BookmarkCurrentPage(Browser* browser) {
557 content::RecordAction(UserMetricsAction("Star"));
558
559 BookmarkModel* model = browser->profile()->GetBookmarkModel();
560 if (!model || !model->IsLoaded())
561 return; // Ignore requests until bookmarks are loaded.
562
563 GURL url;
564 string16 title;
[email protected]52877dbc62012-06-29 22:22:03565 TabContents* tab = GetActiveTabContents(browser);
[email protected]a37d4b02012-06-25 21:56:10566 bookmark_utils::GetURLAndTitleToBookmark(tab->web_contents(), &url, &title);
567 bool was_bookmarked = model->IsBookmarked(url);
568 if (!was_bookmarked && browser->profile()->IsOffTheRecord()) {
569 // If we're incognito the favicon may not have been saved. Save it now
570 // so that bookmarks have an icon for the page.
571 tab->favicon_tab_helper()->SaveFavicon();
572 }
573 bookmark_utils::AddIfNotBookmarked(model, url, title);
574 // Make sure the model actually added a bookmark before showing the star. A
575 // bookmark isn't created if the url is invalid.
576 if (browser->window()->IsActive() && model->IsBookmarked(url)) {
577 // Only show the bubble if the window is active, otherwise we may get into
578 // weird situations where the bubble is deleted as soon as it is shown.
579 browser->window()->ShowBookmarkBubble(url, was_bookmarked);
580 }
581}
582
[email protected]5d98294912012-06-27 22:57:40583bool CanBookmarkCurrentPage(const Browser* browser) {
584 BookmarkModel* model = browser->profile()->GetBookmarkModel();
585 return browser_defaults::bookmarks_enabled &&
586 browser->profile()->GetPrefs()->GetBoolean(
587 prefs::kEditBookmarksEnabled) &&
588 model && model->IsLoaded() && browser->is_type_tabbed();
589}
590
591void BookmarkAllTabs(Browser* browser) {
592 BookmarkEditor::ShowBookmarkAllTabsDialog(browser);
593}
594
595bool CanBookmarkAllTabs(const Browser* browser) {
596 return browser->tab_count() > 1 && CanBookmarkCurrentPage(browser);
597}
598
[email protected]a37d4b02012-06-25 21:56:10599#if !defined(OS_WIN)
600void PinCurrentPageToStartScreen(Browser* browser) {
601}
602#endif
603
604void SavePage(Browser* browser) {
605 content::RecordAction(UserMetricsAction("SavePage"));
[email protected]52877dbc62012-06-29 22:22:03606 WebContents* current_tab = GetActiveWebContents(browser);
[email protected]a37d4b02012-06-25 21:56:10607 if (current_tab && current_tab->GetContentsMimeType() == "application/pdf")
608 content::RecordAction(UserMetricsAction("PDF.SavePage"));
609 current_tab->OnSavePage();
610}
611
[email protected]5d98294912012-06-27 22:57:40612bool CanSavePage(const Browser* browser) {
613 // LocalState can be NULL in tests.
614 if (g_browser_process->local_state() &&
615 !g_browser_process->local_state()->GetBoolean(
616 prefs::kAllowFileSelectionDialogs)) {
617 return false;
618 }
619 return !browser->is_devtools() &&
620 !(GetContentRestrictions(browser) & content::CONTENT_RESTRICTION_SAVE);
621}
622
[email protected]a37d4b02012-06-25 21:56:10623void ShowFindBar(Browser* browser) {
624 browser->GetFindBarController()->Show();
625}
626
627void ShowPageInfo(Browser* browser,
628 content::WebContents* web_contents,
629 const GURL& url,
630 const SSLStatus& ssl,
631 bool show_history) {
632 Profile* profile = Profile::FromBrowserContext(
633 web_contents->GetBrowserContext());
634 TabContents* tab_contents = TabContents::FromWebContents(web_contents);
635
636 if (CommandLine::ForCurrentProcess()->HasSwitch(
637 switches::kEnableWebsiteSettings)) {
638 browser->window()->ShowWebsiteSettings(
639 profile, tab_contents, url, ssl, show_history);
640 } else {
641 browser->window()->ShowPageInfo(web_contents, url, ssl, show_history);
642 }
643}
644
645void ShowChromeToMobileBubble(Browser* browser) {
646 // Only show the bubble if the window is active, otherwise we may get into
647 // weird situations where the bubble is deleted as soon as it is shown.
648 if (browser->window()->IsActive())
649 browser->window()->ShowChromeToMobileBubble();
650}
651
652void Print(Browser* browser) {
653 if (g_browser_process->local_state()->GetBoolean(
654 prefs::kPrintPreviewDisabled)) {
[email protected]52877dbc62012-06-29 22:22:03655 GetActiveTabContents(browser)->print_view_manager()->PrintNow();
[email protected]a37d4b02012-06-25 21:56:10656 } else {
[email protected]52877dbc62012-06-29 22:22:03657 GetActiveTabContents(browser)->print_view_manager()->
658 PrintPreviewNow();
[email protected]a37d4b02012-06-25 21:56:10659 }
660}
661
[email protected]5d98294912012-06-27 22:57:40662bool CanPrint(const Browser* browser) {
663 // LocalState can be NULL in tests.
664 if (g_browser_process->local_state() &&
665 !g_browser_process->local_state()->GetBoolean(prefs::kPrintingEnabled)) {
666 return false;
667 }
668
669 // Do not print when a constrained window is showing. It's confusing.
[email protected]db9747252012-07-02 19:28:00670 // Do not print if instant extended API is enabled and mode is NTP.
[email protected]5d98294912012-06-27 22:57:40671 return !(HasConstrainedWindow(browser) ||
[email protected]db9747252012-07-02 19:28:00672 GetContentRestrictions(browser) & content::CONTENT_RESTRICTION_PRINT ||
673 IsNTPModeForInstantExtendedAPI(browser));
[email protected]5d98294912012-06-27 22:57:40674}
675
[email protected]a37d4b02012-06-25 21:56:10676void AdvancedPrint(Browser* browser) {
[email protected]52877dbc62012-06-29 22:22:03677 GetActiveTabContents(browser)->print_view_manager()->
678 AdvancedPrintNow();
[email protected]a37d4b02012-06-25 21:56:10679}
680
[email protected]5d98294912012-06-27 22:57:40681bool CanAdvancedPrint(const Browser* browser) {
682 // LocalState can be NULL in tests.
683 if (g_browser_process->local_state() &&
684 !g_browser_process->local_state()->GetBoolean(prefs::kPrintingEnabled)) {
685 return false;
686 }
687
688 // It is always possible to advanced print when print preview is visible.
689 return PrintPreviewShowing(browser) || CanPrint(browser);
690}
691
[email protected]d53e4032012-06-29 18:58:34692void PrintToDestination(Browser* browser) {
[email protected]52877dbc62012-06-29 22:22:03693 GetActiveTabContents(browser)->print_view_manager()->PrintToDestination();
[email protected]d53e4032012-06-29 18:58:34694}
695
[email protected]a37d4b02012-06-25 21:56:10696void EmailPageLocation(Browser* browser) {
697 content::RecordAction(UserMetricsAction("EmailPageLocation"));
[email protected]52877dbc62012-06-29 22:22:03698 WebContents* wc = GetActiveWebContents(browser);
[email protected]a37d4b02012-06-25 21:56:10699 DCHECK(wc);
700
701 std::string title = net::EscapeQueryParamValue(
702 UTF16ToUTF8(wc->GetTitle()), false);
703 std::string page_url = net::EscapeQueryParamValue(wc->GetURL().spec(), false);
704 std::string mailto = std::string("mailto:?subject=Fwd:%20") +
705 title + "&body=%0A%0A" + page_url;
706 platform_util::OpenExternal(GURL(mailto));
707}
708
[email protected]5d98294912012-06-27 22:57:40709bool CanEmailPageLocation(const Browser* browser) {
710 return browser->toolbar_model()->ShouldDisplayURL() &&
[email protected]52877dbc62012-06-29 22:22:03711 GetActiveWebContents(browser)->GetURL().is_valid();
[email protected]5d98294912012-06-27 22:57:40712}
713
[email protected]a37d4b02012-06-25 21:56:10714void Cut(Browser* browser) {
715 content::RecordAction(UserMetricsAction("Cut"));
716 browser->window()->Cut();
717}
718
719void Copy(Browser* browser) {
720 content::RecordAction(UserMetricsAction("Copy"));
721 browser->window()->Copy();
722}
723
724void Paste(Browser* browser) {
725 content::RecordAction(UserMetricsAction("Paste"));
726 browser->window()->Paste();
727}
728
729void Find(Browser* browser) {
730 content::RecordAction(UserMetricsAction("Find"));
731 FindInPage(browser, false, false);
732}
733
734void FindNext(Browser* browser) {
735 content::RecordAction(UserMetricsAction("FindNext"));
736 FindInPage(browser, true, true);
737}
738
739void FindPrevious(Browser* browser) {
740 content::RecordAction(UserMetricsAction("FindPrevious"));
741 FindInPage(browser, true, false);
742}
743
744void FindInPage(Browser* browser, bool find_next, bool forward_direction) {
745 ShowFindBar(browser);
746 if (find_next) {
747 string16 find_text;
748#if defined(OS_MACOSX)
749 // We always want to search for the contents of the find pasteboard on OS X.
750 find_text = GetFindPboardText();
751#endif
[email protected]52877dbc62012-06-29 22:22:03752 GetActiveTabContents(browser)->
[email protected]a37d4b02012-06-25 21:56:10753 find_tab_helper()->StartFinding(find_text,
754 forward_direction,
755 false); // Not case sensitive.
756 }
757}
758
759void Zoom(Browser* browser, content::PageZoom zoom) {
760 if (browser->is_devtools())
761 return;
762
763 content::RenderViewHost* host =
[email protected]52877dbc62012-06-29 22:22:03764 GetActiveWebContents(browser)->GetRenderViewHost();
[email protected]a37d4b02012-06-25 21:56:10765 if (zoom == content::PAGE_ZOOM_RESET) {
766 host->SetZoomLevel(0);
767 content::RecordAction(UserMetricsAction("ZoomNormal"));
768 return;
769 }
770
[email protected]52877dbc62012-06-29 22:22:03771 double current_zoom_level = GetActiveWebContents(browser)->GetZoomLevel();
[email protected]a37d4b02012-06-25 21:56:10772 double default_zoom_level =
773 browser->profile()->GetPrefs()->GetDouble(prefs::kDefaultZoomLevel);
774
775 // Generate a vector of zoom levels from an array of known presets along with
776 // the default level added if necessary.
777 std::vector<double> zoom_levels =
778 chrome_page_zoom::PresetZoomLevels(default_zoom_level);
779
780 if (zoom == content::PAGE_ZOOM_OUT) {
781 // Iterate through the zoom levels in reverse order to find the next
782 // lower level based on the current zoom level for this page.
783 for (std::vector<double>::reverse_iterator i = zoom_levels.rbegin();
784 i != zoom_levels.rend(); ++i) {
785 double zoom_level = *i;
786 if (content::ZoomValuesEqual(zoom_level, current_zoom_level))
787 continue;
788 if (zoom_level < current_zoom_level) {
789 host->SetZoomLevel(zoom_level);
790 content::RecordAction(UserMetricsAction("ZoomMinus"));
791 return;
792 }
793 content::RecordAction(UserMetricsAction("ZoomMinus_AtMinimum"));
794 }
795 } else {
796 // Iterate through the zoom levels in normal order to find the next
797 // higher level based on the current zoom level for this page.
798 for (std::vector<double>::const_iterator i = zoom_levels.begin();
799 i != zoom_levels.end(); ++i) {
800 double zoom_level = *i;
801 if (content::ZoomValuesEqual(zoom_level, current_zoom_level))
802 continue;
803 if (zoom_level > current_zoom_level) {
804 host->SetZoomLevel(zoom_level);
805 content::RecordAction(UserMetricsAction("ZoomPlus"));
806 return;
807 }
808 }
809 content::RecordAction(UserMetricsAction("ZoomPlus_AtMaximum"));
810 }
811}
812
813void FocusToolbar(Browser* browser) {
814 content::RecordAction(UserMetricsAction("FocusToolbar"));
815 browser->window()->FocusToolbar();
816}
817
818void FocusLocationBar(Browser* browser) {
819 content::RecordAction(UserMetricsAction("FocusLocation"));
820 browser->window()->SetFocusToLocationBar(true);
821}
822
823void FocusSearch(Browser* browser) {
824 // TODO(beng): replace this with FocusLocationBar
825 content::RecordAction(UserMetricsAction("FocusSearch"));
826 browser->window()->GetLocationBar()->FocusSearch();
827}
828
829void FocusAppMenu(Browser* browser) {
830 content::RecordAction(UserMetricsAction("FocusAppMenu"));
831 browser->window()->FocusAppMenu();
832}
833
834void FocusBookmarksToolbar(Browser* browser) {
835 content::RecordAction(UserMetricsAction("FocusBookmarksToolbar"));
836 browser->window()->FocusBookmarksToolbar();
837}
838
839void FocusNextPane(Browser* browser) {
840 content::RecordAction(UserMetricsAction("FocusNextPane"));
841 browser->window()->RotatePaneFocus(true);
842}
843
844void FocusPreviousPane(Browser* browser) {
845 content::RecordAction(UserMetricsAction("FocusPreviousPane"));
846 browser->window()->RotatePaneFocus(false);
847}
848
849void ToggleDevToolsWindow(Browser* browser, DevToolsToggleAction action) {
850 if (action == DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE)
851 content::RecordAction(UserMetricsAction("DevTools_ToggleConsole"));
852 else
853 content::RecordAction(UserMetricsAction("DevTools_ToggleWindow"));
854
855 DevToolsWindow::ToggleDevToolsWindow(
[email protected]52877dbc62012-06-29 22:22:03856 GetActiveWebContents(browser)->GetRenderViewHost(),
[email protected]a37d4b02012-06-25 21:56:10857 action);
858}
859
860bool CanOpenTaskManager() {
861#if defined(OS_WIN)
862 // In metro we can't display the task manager, as it is a native window.
863 return !base::win::IsMetroProcess();
864#else
865 return true;
866#endif
867}
868
869void OpenTaskManager(Browser* browser, bool highlight_background_resources) {
870 content::RecordAction(UserMetricsAction("TaskManager"));
871 if (highlight_background_resources)
872 browser->window()->ShowBackgroundPages();
873 else
874 browser->window()->ShowTaskManager();
875}
876
877void OpenFeedbackDialog(Browser* browser) {
878 content::RecordAction(UserMetricsAction("Feedback"));
879 browser::ShowWebFeedbackView(browser, std::string(), std::string());
880}
881
882void ToggleBookmarkBar(Browser* browser) {
883 content::RecordAction(UserMetricsAction("ShowBookmarksBar"));
884 browser->window()->ToggleBookmarkBar();
885}
886
887void ShowAppMenu(Browser* browser) {
888 // We record the user metric for this event in WrenchMenu::RunMenu.
889 browser->window()->ShowAppMenu();
890}
891
892void ShowAvatarMenu(Browser* browser) {
893 browser->window()->ShowAvatarBubbleFromAvatarButton();
894}
895
896void OpenUpdateChromeDialog(Browser* browser) {
897 content::RecordAction(UserMetricsAction("UpdateChrome"));
898 browser->window()->ShowUpdateChromeDialog();
899}
900
901void ToggleSpeechInput(Browser* browser) {
[email protected]52877dbc62012-06-29 22:22:03902 GetActiveWebContents(browser)->GetRenderViewHost()->ToggleSpeechInput();
[email protected]a37d4b02012-06-25 21:56:10903}
904
[email protected]3f32b9b2012-07-09 16:59:28905void ToggleFullscreenMode(Browser* browser) {
906 browser->fullscreen_controller()->ToggleFullscreenMode();
907}
908
[email protected]2cd4fde2012-06-26 03:10:26909void ViewSource(Browser* browser, TabContents* contents) {
910 DCHECK(contents);
911
912 NavigationEntry* active_entry =
913 contents->web_contents()->GetController().GetActiveEntry();
914 if (!active_entry)
915 return;
916
917 ViewSource(browser, contents, active_entry->GetURL(),
918 active_entry->GetContentState());
919}
920
921void ViewSource(Browser* browser,
922 TabContents* contents,
923 const GURL& url,
924 const std::string& content_state) {
925 content::RecordAction(UserMetricsAction("ViewSource"));
926 DCHECK(contents);
927
928 TabContents* view_source_contents = contents->Clone();
929 view_source_contents->web_contents()->GetController().PruneAllButActive();
930 NavigationEntry* active_entry =
931 view_source_contents->web_contents()->GetController().GetActiveEntry();
932 if (!active_entry)
933 return;
934
[email protected]52877dbc62012-06-29 22:22:03935 GURL view_source_url = GURL(kViewSourceScheme + std::string(":") +
[email protected]2cd4fde2012-06-26 03:10:26936 url.spec());
937 active_entry->SetVirtualURL(view_source_url);
938
939 // Do not restore scroller position.
940 active_entry->SetContentState(
941 webkit_glue::RemoveScrollOffsetFromHistoryState(content_state));
942
943 // Do not restore title, derive it from the url.
944 active_entry->SetTitle(string16());
945
946 // Now show view-source entry.
947 if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) {
948 // If this is a tabbed browser, just create a duplicate tab inside the same
949 // window next to the tab being duplicated.
950 int index = browser->tab_strip_model()->GetIndexOfTabContents(contents);
951 int add_types = TabStripModel::ADD_ACTIVE |
952 TabStripModel::ADD_INHERIT_GROUP;
953 browser->tab_strip_model()->InsertTabContentsAt(index + 1,
954 view_source_contents,
955 add_types);
956 } else {
957 Browser* b = Browser::CreateWithParams(
958 Browser::CreateParams(Browser::TYPE_TABBED, browser->profile()));
959
960 // Preserve the size of the original window. The new window has already
961 // been given an offset by the OS, so we shouldn't copy the old bounds.
962 BrowserWindow* new_window = b->window();
963 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
964 browser->window()->GetRestoredBounds().size()));
965
966 // We need to show the browser now. Otherwise ContainerWin assumes the
967 // WebContents is invisible and won't size it.
968 b->window()->Show();
969
970 // The page transition below is only for the purpose of inserting the tab.
[email protected]855370052012-07-10 19:30:32971 AddTab(b, view_source_contents, content::PAGE_TRANSITION_LINK);
[email protected]2cd4fde2012-06-26 03:10:26972 }
973
974 SessionService* session_service =
975 SessionServiceFactory::GetForProfileIfExisting(browser->profile());
976 if (session_service)
977 session_service->TabRestored(view_source_contents, false);
978}
979
980void ViewSelectedSource(Browser* browser) {
[email protected]855370052012-07-10 19:30:32981 ViewSource(browser, GetActiveTabContents(browser));
[email protected]2cd4fde2012-06-26 03:10:26982}
983
[email protected]5d98294912012-06-27 22:57:40984bool CanViewSource(const Browser* browser) {
[email protected]855370052012-07-10 19:30:32985 return GetActiveWebContents(browser)->GetController().CanViewSource();
[email protected]5d98294912012-06-27 22:57:40986}
987
[email protected]619f86182012-07-03 21:30:18988void CreateApplicationShortcuts(Browser* browser) {
989 content::RecordAction(UserMetricsAction("CreateShortcut"));
[email protected]855370052012-07-10 19:30:32990 GetActiveTabContents(browser)->extension_tab_helper()->
[email protected]619f86182012-07-03 21:30:18991 CreateApplicationShortcuts();
992}
993
[email protected]5d98294912012-06-27 22:57:40994bool CanCreateApplicationShortcuts(const Browser* browser) {
[email protected]855370052012-07-10 19:30:32995 return GetActiveTabContents(browser)->extension_tab_helper()->
[email protected]619f86182012-07-03 21:30:18996 CanCreateApplicationShortcuts();
[email protected]5d98294912012-06-27 22:57:40997}
998
[email protected]40df6f52012-06-28 17:08:52999void ConvertTabToAppWindow(Browser* browser,
1000 content::WebContents* contents) {
1001 const GURL& url = contents->GetController().GetActiveEntry()->GetURL();
1002 std::string app_name = web_app::GenerateApplicationNameFromURL(url);
1003
1004 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents);
1005 if (index >= 0)
1006 browser->tab_strip_model()->DetachTabContentsAt(index);
1007
1008 Browser* app_browser = Browser::CreateWithParams(
1009 Browser::CreateParams::CreateForApp(
1010 Browser::TYPE_POPUP, app_name, gfx::Rect(), browser->profile()));
1011 TabContents* tab_contents = TabContents::FromWebContents(contents);
1012 if (!tab_contents)
1013 tab_contents = new TabContents(contents);
1014 app_browser->tab_strip_model()->AppendTabContents(tab_contents, true);
1015
1016 contents->GetMutableRendererPrefs()->can_accept_load_drops = false;
1017 contents->GetRenderViewHost()->SyncRendererPrefs();
1018 app_browser->window()->Show();
1019}
1020
[email protected]a37d4b02012-06-25 21:56:101021} // namespace chrome