blob: 248b866ea069cbd5cdeaf644a71b155f4799504f [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"
18#include "chrome/browser/favicon/favicon_tab_helper.h"
19#include "chrome/browser/lifetime/application_lifetime.h"
20#include "chrome/browser/platform_util.h"
21#include "chrome/browser/prefs/incognito_mode_prefs.h"
22#include "chrome/browser/prefs/pref_service.h"
[email protected]5d98294912012-06-27 22:57:4023#include "chrome/browser/printing/print_preview_tab_controller.h"
[email protected]a37d4b02012-06-25 21:56:1024#include "chrome/browser/printing/print_view_manager.h"
25#include "chrome/browser/profiles/profile.h"
26#include "chrome/browser/sessions/session_service_factory.h"
27#include "chrome/browser/sessions/tab_restore_service_factory.h"
28#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]a37d4b02012-06-25 21:56:1030#include "chrome/browser/ui/browser.h"
[email protected]5d98294912012-06-27 22:57:4031#include "chrome/browser/ui/browser_command_controller.h"
[email protected]a37d4b02012-06-25 21:56:1032#include "chrome/browser/ui/browser_finder.h"
[email protected]5d98294912012-06-27 22:57:4033#include "chrome/browser/ui/browser_tab_restore_service_delegate.h"
[email protected]a37d4b02012-06-25 21:56:1034#include "chrome/browser/ui/browser_window.h"
[email protected]5d98294912012-06-27 22:57:4035#include "chrome/browser/ui/constrained_window_tab_helper.h"
[email protected]a37d4b02012-06-25 21:56:1036#include "chrome/browser/ui/find_bar/find_bar_controller.h"
37#include "chrome/browser/ui/find_bar/find_tab_helper.h"
38#include "chrome/browser/ui/omnibox/location_bar.h"
39#include "chrome/browser/ui/status_bubble.h"
40#include "chrome/browser/ui/tab_contents/tab_contents.h"
41#include "chrome/browser/ui/tabs/tab_strip_model.h"
42#include "chrome/browser/ui/webui/feedback_ui.h"
43#include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
[email protected]5d98294912012-06-27 22:57:4044#include "chrome/browser/web_applications/web_app.h"
[email protected]a37d4b02012-06-25 21:56:1045#include "chrome/common/chrome_switches.h"
46#include "chrome/common/net/url_util.h"
47#include "chrome/common/pref_names.h"
[email protected]5d98294912012-06-27 22:57:4048#include "content/public/common/content_restriction.h"
[email protected]40df6f52012-06-28 17:08:5249#include "content/public/common/renderer_preferences.h"
[email protected]a37d4b02012-06-25 21:56:1050#include "content/public/browser/navigation_controller.h"
51#include "content/public/browser/navigation_entry.h"
52#include "content/public/browser/page_navigator.h"
53#include "content/public/browser/render_view_host.h"
54#include "content/public/browser/user_metrics.h"
55#include "content/public/browser/web_contents.h"
56#include "content/public/browser/web_contents_view.h"
[email protected]2cd4fde2012-06-26 03:10:2657#include "content/public/common/url_constants.h"
[email protected]a37d4b02012-06-25 21:56:1058#include "net/base/escape.h"
[email protected]2cd4fde2012-06-26 03:10:2659#include "webkit/glue/webkit_glue.h"
[email protected]a37d4b02012-06-25 21:56:1060
61#if defined(OS_MACOSX)
62#include "ui/base/cocoa/find_pasteboard.h"
63#endif
64
65#if defined(OS_WIN)
66#include "base/win/metro.h"
67#endif
68
69using content::NavigationController;
70using content::NavigationEntry;
71using content::OpenURLParams;
72using content::Referrer;
73using content::SSLStatus;
74using content::UserMetricsAction;
75using content::WebContents;
76
77namespace chrome {
78namespace {
79
80WebContents* GetOrCloneTabForDisposition(Browser* browser,
81 WindowOpenDisposition disposition) {
82 TabContents* current_tab = browser->GetActiveTabContents();
83 switch (disposition) {
84 case NEW_FOREGROUND_TAB:
85 case NEW_BACKGROUND_TAB: {
86 current_tab = current_tab->Clone();
87 browser->tab_strip_model()->AddTabContents(
88 current_tab, -1, content::PAGE_TRANSITION_LINK,
89 disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_ACTIVE :
90 TabStripModel::ADD_NONE);
91 break;
92 }
93 case NEW_WINDOW: {
94 current_tab = current_tab->Clone();
95 Browser* b = Browser::Create(browser->profile());
96 b->tab_strip_model()->AddTabContents(
97 current_tab, -1, content::PAGE_TRANSITION_LINK,
98 TabStripModel::ADD_ACTIVE);
99 b->window()->Show();
100 break;
101 }
102 default:
103 break;
104 }
105 return current_tab->web_contents();
106}
107
108void ReloadInternal(Browser* browser,
109 WindowOpenDisposition disposition,
110 bool ignore_cache) {
111 // If we are showing an interstitial, treat this as an OpenURL.
112 WebContents* current_tab = browser->GetActiveWebContents();
113 if (current_tab && current_tab->ShowingInterstitialPage()) {
114 NavigationEntry* entry = current_tab->GetController().GetActiveEntry();
115 DCHECK(entry); // Should exist if interstitial is showing.
116 browser->OpenURL(OpenURLParams(
117 entry->GetURL(), Referrer(), disposition,
118 content::PAGE_TRANSITION_RELOAD, false));
119 return;
120 }
121
122 // As this is caused by a user action, give the focus to the page.
123 //
124 // Also notify RenderViewHostDelegate of the user gesture; this is
125 // normally done in Browser::Navigate, but a reload bypasses Navigate.
126 WebContents* web_contents = GetOrCloneTabForDisposition(browser, disposition);
127 web_contents->UserGestureDone();
128 if (!web_contents->FocusLocationBarByDefault())
129 web_contents->Focus();
130 if (ignore_cache)
131 web_contents->GetController().ReloadIgnoringCache(true);
132 else
133 web_contents->GetController().Reload(true);
134}
135
[email protected]5d98294912012-06-27 22:57:40136bool HasConstrainedWindow(const Browser* browser) {
137 TabContents* tab_contents = browser->GetActiveTabContents();
138 return tab_contents && tab_contents->constrained_window_tab_helper()->
139 constrained_window_count();
140}
141
142bool PrintPreviewShowing(const Browser* browser) {
143 TabContents* contents = browser->GetActiveTabContents();
144 printing::PrintPreviewTabController* controller =
145 printing::PrintPreviewTabController::GetInstance();
146 return controller && (controller->GetPrintPreviewForTab(contents) ||
147 controller->is_creating_print_preview_tab());
148}
149
[email protected]a37d4b02012-06-25 21:56:10150} // namespace
151
[email protected]5d98294912012-06-27 22:57:40152bool IsCommandEnabled(Browser* browser, int command) {
153 return browser->command_controller()->command_updater()->IsCommandEnabled(
154 command);
155}
156
157bool SupportsCommand(Browser* browser, int command) {
158 return browser->command_controller()->command_updater()->SupportsCommand(
159 command);
160}
161
162bool ExecuteCommand(Browser* browser, int command) {
163 return browser->command_controller()->command_updater()->ExecuteCommand(
164 command);
165}
166
167bool ExecuteCommandWithDisposition(Browser* browser,
168 int command,
169 WindowOpenDisposition disposition) {
170 return browser->command_controller()->command_updater()->
171 ExecuteCommandWithDisposition(command, disposition);
172}
173
174void UpdateCommandEnabled(Browser* browser, int command, bool enabled) {
175 browser->command_controller()->command_updater()->UpdateCommandEnabled(
176 command, enabled);
177}
178
179void AddCommandObserver(Browser* browser,
180 int command,
181 CommandObserver* observer) {
182 browser->command_controller()->command_updater()->AddCommandObserver(
183 command, observer);
184}
185
186void RemoveCommandObserver(Browser* browser,
187 int command,
188 CommandObserver* observer) {
189 browser->command_controller()->command_updater()->RemoveCommandObserver(
190 command, observer);
191}
192
193int GetContentRestrictions(const Browser* browser) {
194 int content_restrictions = 0;
195 WebContents* current_tab = browser->GetActiveWebContents();
196 if (current_tab) {
197 content_restrictions = current_tab->GetContentRestrictions();
198 NavigationEntry* active_entry =
199 current_tab->GetController().GetActiveEntry();
200 // See comment in UpdateCommandsForTabState about why we call url().
201 if (!download_util::IsSavableURL(
202 active_entry ? active_entry->GetURL() : GURL()) ||
203 current_tab->ShowingInterstitialPage())
204 content_restrictions |= content::CONTENT_RESTRICTION_SAVE;
205 if (current_tab->ShowingInterstitialPage())
206 content_restrictions |= content::CONTENT_RESTRICTION_PRINT;
207 }
208 return content_restrictions;
209}
210
[email protected]a37d4b02012-06-25 21:56:10211void NewEmptyWindow(Profile* profile) {
212 bool incognito = profile->IsOffTheRecord();
213 PrefService* prefs = profile->GetPrefs();
214 if (incognito) {
215 if (IncognitoModePrefs::GetAvailability(prefs) ==
216 IncognitoModePrefs::DISABLED) {
217 incognito = false;
218 }
219 } else {
220 if (browser_defaults::kAlwaysOpenIncognitoWindow &&
221 IncognitoModePrefs::ShouldLaunchIncognito(
222 *CommandLine::ForCurrentProcess(), prefs)) {
223 incognito = true;
224 }
225 }
226
227 if (incognito) {
228 content::RecordAction(UserMetricsAction("NewIncognitoWindow"));
229 OpenEmptyWindow(profile->GetOffTheRecordProfile());
230 } else {
231 content::RecordAction(UserMetricsAction("NewWindow"));
232 SessionService* session_service =
233 SessionServiceFactory::GetForProfile(profile->GetOriginalProfile());
234 if (!session_service ||
235 !session_service->RestoreIfNecessary(std::vector<GURL>())) {
236 OpenEmptyWindow(profile->GetOriginalProfile());
237 }
238 }
239}
240
241Browser* OpenEmptyWindow(Profile* profile) {
242 Browser* browser = Browser::Create(profile);
243 browser->AddBlankTab(true);
244 browser->window()->Show();
245 return browser;
246}
247
248void OpenWindowWithRestoredTabs(Profile* profile) {
249 TabRestoreService* service = TabRestoreServiceFactory::GetForProfile(profile);
250 if (service)
251 service->RestoreMostRecentEntry(NULL);
252}
253
254void OpenURLOffTheRecord(Profile* profile, const GURL& url) {
255 Browser* browser = browser::FindOrCreateTabbedBrowser(
256 profile->GetOffTheRecordProfile());
257 browser->AddSelectedTabWithURL(url, content::PAGE_TRANSITION_LINK);
258 browser->window()->Show();
259}
260
[email protected]5d98294912012-06-27 22:57:40261bool CanGoBack(const Browser* browser) {
[email protected]a37d4b02012-06-25 21:56:10262 return browser->GetActiveWebContents()->GetController().CanGoBack();
263}
264
265void GoBack(Browser* browser, WindowOpenDisposition disposition) {
266 content::RecordAction(UserMetricsAction("Back"));
267
268 TabContents* current_tab = browser->GetActiveTabContents();
269 if (CanGoBack(browser)) {
270 WebContents* new_tab = GetOrCloneTabForDisposition(browser, disposition);
271 // If we are on an interstitial page and clone the tab, it won't be copied
272 // to the new tab, so we don't need to go back.
273 if (current_tab->web_contents()->ShowingInterstitialPage() &&
274 (new_tab != current_tab->web_contents()))
275 return;
276 new_tab->GetController().GoBack();
277 }
278}
279
[email protected]5d98294912012-06-27 22:57:40280bool CanGoForward(const Browser* browser) {
[email protected]a37d4b02012-06-25 21:56:10281 return browser->GetActiveWebContents()->GetController().CanGoForward();
282}
283
284void GoForward(Browser* browser, WindowOpenDisposition disposition) {
285 content::RecordAction(UserMetricsAction("Forward"));
286 if (CanGoForward(browser)) {
287 GetOrCloneTabForDisposition(browser, disposition)->
288 GetController().GoForward();
289 }
290}
291
292bool NavigateToIndexWithDisposition(Browser* browser,
293 int index,
294 WindowOpenDisposition disp) {
295 NavigationController& controller =
296 GetOrCloneTabForDisposition(browser, disp)->GetController();
297 if (index < 0 || index >= controller.GetEntryCount())
298 return false;
299 controller.GoToIndex(index);
300 return true;
301}
302
303void Reload(Browser* browser, WindowOpenDisposition disposition) {
304 content::RecordAction(UserMetricsAction("Reload"));
305 ReloadInternal(browser, disposition, false);
306}
307
308void ReloadIgnoringCache(Browser* browser, WindowOpenDisposition disposition) {
309 content::RecordAction(UserMetricsAction("ReloadIgnoringCache"));
310 ReloadInternal(browser, disposition, true);
311}
312
[email protected]5d98294912012-06-27 22:57:40313bool CanReload(const Browser* browser) {
314 return !browser->is_devtools();
315}
316
[email protected]a37d4b02012-06-25 21:56:10317void Home(Browser* browser, WindowOpenDisposition disposition) {
318 content::RecordAction(UserMetricsAction("Home"));
319 browser->OpenURL(OpenURLParams(
320 browser->profile()->GetHomePage(), Referrer(), disposition,
321 content::PageTransitionFromInt(
322 content::PAGE_TRANSITION_AUTO_BOOKMARK |
323 content::PAGE_TRANSITION_HOME_PAGE),
324 false));
325}
326
327void OpenCurrentURL(Browser* browser) {
328 content::RecordAction(UserMetricsAction("LoadURL"));
329 LocationBar* location_bar = browser->window()->GetLocationBar();
330 if (!location_bar)
331 return;
332
333 WindowOpenDisposition open_disposition =
334 location_bar->GetWindowOpenDisposition();
335 if (browser->OpenInstant(open_disposition))
336 return;
337
338 GURL url(location_bar->GetInputString());
339
340 browser::NavigateParams params(browser, url,
341 location_bar->GetPageTransition());
342 params.disposition = open_disposition;
343 // Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least
344 // inherit the opener. In some cases the tabstrip will determine the group
345 // should be inherited, in which case the group is inherited instead of the
346 // opener.
347 params.tabstrip_add_types =
348 TabStripModel::ADD_FORCE_INDEX | TabStripModel::ADD_INHERIT_OPENER;
349 browser::Navigate(&params);
350
351 DCHECK(browser->profile()->GetExtensionService());
352 if (browser->profile()->GetExtensionService()->IsInstalledApp(url)) {
353 AppLauncherHandler::RecordAppLaunchType(
354 extension_misc::APP_LAUNCH_OMNIBOX_LOCATION);
355 }
356}
357
358void Stop(Browser* browser) {
359 content::RecordAction(UserMetricsAction("Stop"));
360 browser->GetActiveWebContents()->Stop();
361}
362
363#if !defined(OS_WIN)
364void NewWindow(Browser* browser) {
365 NewEmptyWindow(browser->profile()->GetOriginalProfile());
366}
367
368void NewIncognitoWindow(Browser* browser) {
369 NewEmptyWindow(browser->profile()->GetOffTheRecordProfile());
370}
371#endif // OS_WIN
372
373void CloseWindow(Browser* browser) {
374 content::RecordAction(UserMetricsAction("CloseWindow"));
375 browser->window()->Close();
376}
377
378void NewTab(Browser* browser) {
379 content::RecordAction(UserMetricsAction("NewTab"));
380 // TODO(asvitkine): This is invoked programmatically from several places.
381 // Audit the code and change it so that the histogram only gets collected for
382 // user-initiated commands.
383 UMA_HISTOGRAM_ENUMERATION("Tab.NewTab", TabStripModel::NEW_TAB_COMMAND,
384 TabStripModel::NEW_TAB_ENUM_COUNT);
385
386 if (browser->is_type_tabbed()) {
387 browser->AddBlankTab(true);
388 browser->GetActiveWebContents()->GetView()->RestoreFocus();
389 } else {
390 Browser* b = browser::FindOrCreateTabbedBrowser(browser->profile());
391 b->AddBlankTab(true);
392 b->window()->Show();
393 // The call to AddBlankTab above did not set the focus to the tab as its
394 // window was not active, so we have to do it explicitly.
395 // See http://crbug.com/6380.
396 b->GetActiveWebContents()->GetView()->RestoreFocus();
397 }
398}
399
400void CloseTab(Browser* browser) {
401 content::RecordAction(UserMetricsAction("CloseTab_Accelerator"));
402 browser->tab_strip_model()->CloseSelectedTabs();
403}
404
[email protected]5d98294912012-06-27 22:57:40405void RestoreTab(Browser* browser) {
406 content::RecordAction(UserMetricsAction("RestoreTab"));
407 TabRestoreService* service =
408 TabRestoreServiceFactory::GetForProfile(browser->profile());
409 if (service)
410 service->RestoreMostRecentEntry(browser->tab_restore_service_delegate());
411}
412
413bool CanRestoreTab(const Browser* browser) {
414 TabRestoreService* service =
415 TabRestoreServiceFactory::GetForProfile(browser->profile());
416 return service && !service->entries().empty();
417}
418
[email protected]a37d4b02012-06-25 21:56:10419void SelectNextTab(Browser* browser) {
420 content::RecordAction(UserMetricsAction("SelectNextTab"));
421 browser->tab_strip_model()->SelectNextTab();
422}
423
424void SelectPreviousTab(Browser* browser) {
425 content::RecordAction(UserMetricsAction("SelectPrevTab"));
426 browser->tab_strip_model()->SelectPreviousTab();
427}
428
429void OpenTabpose(Browser* browser) {
430#if defined(OS_MACOSX)
431 if (!CommandLine::ForCurrentProcess()->HasSwitch(
432 switches::kEnableExposeForTabs)) {
433 return;
434 }
435
436 content::RecordAction(UserMetricsAction("OpenTabpose"));
437 browser->window()->OpenTabpose();
438#else
439 NOTREACHED();
440#endif
441}
442
443void MoveTabNext(Browser* browser) {
444 content::RecordAction(UserMetricsAction("MoveTabNext"));
445 browser->tab_strip_model()->MoveTabNext();
446}
447
448void MoveTabPrevious(Browser* browser) {
449 content::RecordAction(UserMetricsAction("MoveTabPrevious"));
450 browser->tab_strip_model()->MoveTabPrevious();
451}
452
453void SelectNumberedTab(Browser* browser, int index) {
454 if (index < browser->tab_count()) {
455 content::RecordAction(UserMetricsAction("SelectNumberedTab"));
456 browser->ActivateTabAt(index, true);
457 }
458}
459
460void SelectLastTab(Browser* browser) {
461 content::RecordAction(UserMetricsAction("SelectLastTab"));
462 browser->tab_strip_model()->SelectLastTab();
463}
464
465void DuplicateTab(Browser* browser) {
466 content::RecordAction(UserMetricsAction("Duplicate"));
467 browser->DuplicateContentsAt(browser->active_index());
468}
469
[email protected]5d98294912012-06-27 22:57:40470bool CanDuplicateTab(const Browser* browser) {
471 WebContents* contents = browser->GetActiveWebContents();
472 return contents && contents->GetController().GetLastCommittedEntry();
473}
474
[email protected]a37d4b02012-06-25 21:56:10475void WriteCurrentURLToClipboard(Browser* browser) {
476 // TODO(ericu): There isn't currently a metric for this. Should there be?
477 // We don't appear to track the action when it comes from the
478 // RenderContextViewMenu.
479
480 WebContents* contents = browser->GetActiveWebContents();
481 if (!browser->toolbar_model()->ShouldDisplayURL())
482 return;
483
484 chrome_common_net::WriteURLToClipboard(
485 contents->GetURL(),
486 browser->profile()->GetPrefs()->GetString(prefs::kAcceptLanguages),
487 g_browser_process->clipboard());
488}
489
490void ConvertPopupToTabbedBrowser(Browser* browser) {
491 content::RecordAction(UserMetricsAction("ShowAsTab"));
492 TabContents* contents =
493 browser->tab_strip_model()->DetachTabContentsAt(browser->active_index());
494 Browser* b = Browser::Create(browser->profile());
495 b->tab_strip_model()->AppendTabContents(contents, true);
496 b->window()->Show();
497}
498
499void Exit() {
500 content::RecordAction(UserMetricsAction("Exit"));
501 browser::AttemptUserExit();
502}
503
504void BookmarkCurrentPage(Browser* browser) {
505 content::RecordAction(UserMetricsAction("Star"));
506
507 BookmarkModel* model = browser->profile()->GetBookmarkModel();
508 if (!model || !model->IsLoaded())
509 return; // Ignore requests until bookmarks are loaded.
510
511 GURL url;
512 string16 title;
513 TabContents* tab = browser->GetActiveTabContents();
514 bookmark_utils::GetURLAndTitleToBookmark(tab->web_contents(), &url, &title);
515 bool was_bookmarked = model->IsBookmarked(url);
516 if (!was_bookmarked && browser->profile()->IsOffTheRecord()) {
517 // If we're incognito the favicon may not have been saved. Save it now
518 // so that bookmarks have an icon for the page.
519 tab->favicon_tab_helper()->SaveFavicon();
520 }
521 bookmark_utils::AddIfNotBookmarked(model, url, title);
522 // Make sure the model actually added a bookmark before showing the star. A
523 // bookmark isn't created if the url is invalid.
524 if (browser->window()->IsActive() && model->IsBookmarked(url)) {
525 // Only show the bubble if the window is active, otherwise we may get into
526 // weird situations where the bubble is deleted as soon as it is shown.
527 browser->window()->ShowBookmarkBubble(url, was_bookmarked);
528 }
529}
530
[email protected]5d98294912012-06-27 22:57:40531bool CanBookmarkCurrentPage(const Browser* browser) {
532 BookmarkModel* model = browser->profile()->GetBookmarkModel();
533 return browser_defaults::bookmarks_enabled &&
534 browser->profile()->GetPrefs()->GetBoolean(
535 prefs::kEditBookmarksEnabled) &&
536 model && model->IsLoaded() && browser->is_type_tabbed();
537}
538
539void BookmarkAllTabs(Browser* browser) {
540 BookmarkEditor::ShowBookmarkAllTabsDialog(browser);
541}
542
543bool CanBookmarkAllTabs(const Browser* browser) {
544 return browser->tab_count() > 1 && CanBookmarkCurrentPage(browser);
545}
546
[email protected]a37d4b02012-06-25 21:56:10547#if !defined(OS_WIN)
548void PinCurrentPageToStartScreen(Browser* browser) {
549}
550#endif
551
552void SavePage(Browser* browser) {
553 content::RecordAction(UserMetricsAction("SavePage"));
554 WebContents* current_tab = browser->GetActiveWebContents();
555 if (current_tab && current_tab->GetContentsMimeType() == "application/pdf")
556 content::RecordAction(UserMetricsAction("PDF.SavePage"));
557 current_tab->OnSavePage();
558}
559
[email protected]5d98294912012-06-27 22:57:40560bool CanSavePage(const Browser* browser) {
561 // LocalState can be NULL in tests.
562 if (g_browser_process->local_state() &&
563 !g_browser_process->local_state()->GetBoolean(
564 prefs::kAllowFileSelectionDialogs)) {
565 return false;
566 }
567 return !browser->is_devtools() &&
568 !(GetContentRestrictions(browser) & content::CONTENT_RESTRICTION_SAVE);
569}
570
[email protected]a37d4b02012-06-25 21:56:10571void ShowFindBar(Browser* browser) {
572 browser->GetFindBarController()->Show();
573}
574
575void ShowPageInfo(Browser* browser,
576 content::WebContents* web_contents,
577 const GURL& url,
578 const SSLStatus& ssl,
579 bool show_history) {
580 Profile* profile = Profile::FromBrowserContext(
581 web_contents->GetBrowserContext());
582 TabContents* tab_contents = TabContents::FromWebContents(web_contents);
583
584 if (CommandLine::ForCurrentProcess()->HasSwitch(
585 switches::kEnableWebsiteSettings)) {
586 browser->window()->ShowWebsiteSettings(
587 profile, tab_contents, url, ssl, show_history);
588 } else {
589 browser->window()->ShowPageInfo(web_contents, url, ssl, show_history);
590 }
591}
592
593void ShowChromeToMobileBubble(Browser* browser) {
594 // Only show the bubble if the window is active, otherwise we may get into
595 // weird situations where the bubble is deleted as soon as it is shown.
596 if (browser->window()->IsActive())
597 browser->window()->ShowChromeToMobileBubble();
598}
599
600void Print(Browser* browser) {
601 if (g_browser_process->local_state()->GetBoolean(
602 prefs::kPrintPreviewDisabled)) {
603 browser->GetActiveTabContents()->print_view_manager()->PrintNow();
604 } else {
605 browser->GetActiveTabContents()->print_view_manager()->PrintPreviewNow();
606 }
607}
608
[email protected]5d98294912012-06-27 22:57:40609bool CanPrint(const Browser* browser) {
610 // LocalState can be NULL in tests.
611 if (g_browser_process->local_state() &&
612 !g_browser_process->local_state()->GetBoolean(prefs::kPrintingEnabled)) {
613 return false;
614 }
615
616 // Do not print when a constrained window is showing. It's confusing.
617 return !(HasConstrainedWindow(browser) ||
618 GetContentRestrictions(browser) & content::CONTENT_RESTRICTION_PRINT);
619}
620
[email protected]a37d4b02012-06-25 21:56:10621void AdvancedPrint(Browser* browser) {
622 browser->GetActiveTabContents()->print_view_manager()->AdvancedPrintNow();
623}
624
[email protected]5d98294912012-06-27 22:57:40625bool CanAdvancedPrint(const Browser* browser) {
626 // LocalState can be NULL in tests.
627 if (g_browser_process->local_state() &&
628 !g_browser_process->local_state()->GetBoolean(prefs::kPrintingEnabled)) {
629 return false;
630 }
631
632 // It is always possible to advanced print when print preview is visible.
633 return PrintPreviewShowing(browser) || CanPrint(browser);
634}
635
[email protected]a37d4b02012-06-25 21:56:10636void EmailPageLocation(Browser* browser) {
637 content::RecordAction(UserMetricsAction("EmailPageLocation"));
638 WebContents* wc = browser->GetActiveWebContents();
639 DCHECK(wc);
640
641 std::string title = net::EscapeQueryParamValue(
642 UTF16ToUTF8(wc->GetTitle()), false);
643 std::string page_url = net::EscapeQueryParamValue(wc->GetURL().spec(), false);
644 std::string mailto = std::string("mailto:?subject=Fwd:%20") +
645 title + "&body=%0A%0A" + page_url;
646 platform_util::OpenExternal(GURL(mailto));
647}
648
[email protected]5d98294912012-06-27 22:57:40649bool CanEmailPageLocation(const Browser* browser) {
650 return browser->toolbar_model()->ShouldDisplayURL() &&
651 browser->GetActiveWebContents()->GetURL().is_valid();
652}
653
[email protected]a37d4b02012-06-25 21:56:10654void Cut(Browser* browser) {
655 content::RecordAction(UserMetricsAction("Cut"));
656 browser->window()->Cut();
657}
658
659void Copy(Browser* browser) {
660 content::RecordAction(UserMetricsAction("Copy"));
661 browser->window()->Copy();
662}
663
664void Paste(Browser* browser) {
665 content::RecordAction(UserMetricsAction("Paste"));
666 browser->window()->Paste();
667}
668
669void Find(Browser* browser) {
670 content::RecordAction(UserMetricsAction("Find"));
671 FindInPage(browser, false, false);
672}
673
674void FindNext(Browser* browser) {
675 content::RecordAction(UserMetricsAction("FindNext"));
676 FindInPage(browser, true, true);
677}
678
679void FindPrevious(Browser* browser) {
680 content::RecordAction(UserMetricsAction("FindPrevious"));
681 FindInPage(browser, true, false);
682}
683
684void FindInPage(Browser* browser, bool find_next, bool forward_direction) {
685 ShowFindBar(browser);
686 if (find_next) {
687 string16 find_text;
688#if defined(OS_MACOSX)
689 // We always want to search for the contents of the find pasteboard on OS X.
690 find_text = GetFindPboardText();
691#endif
692 browser->GetActiveTabContents()->
693 find_tab_helper()->StartFinding(find_text,
694 forward_direction,
695 false); // Not case sensitive.
696 }
697}
698
699void Zoom(Browser* browser, content::PageZoom zoom) {
700 if (browser->is_devtools())
701 return;
702
703 content::RenderViewHost* host =
704 browser->GetActiveWebContents()->GetRenderViewHost();
705 if (zoom == content::PAGE_ZOOM_RESET) {
706 host->SetZoomLevel(0);
707 content::RecordAction(UserMetricsAction("ZoomNormal"));
708 return;
709 }
710
711 double current_zoom_level = browser->GetActiveWebContents()->GetZoomLevel();
712 double default_zoom_level =
713 browser->profile()->GetPrefs()->GetDouble(prefs::kDefaultZoomLevel);
714
715 // Generate a vector of zoom levels from an array of known presets along with
716 // the default level added if necessary.
717 std::vector<double> zoom_levels =
718 chrome_page_zoom::PresetZoomLevels(default_zoom_level);
719
720 if (zoom == content::PAGE_ZOOM_OUT) {
721 // Iterate through the zoom levels in reverse order to find the next
722 // lower level based on the current zoom level for this page.
723 for (std::vector<double>::reverse_iterator i = zoom_levels.rbegin();
724 i != zoom_levels.rend(); ++i) {
725 double zoom_level = *i;
726 if (content::ZoomValuesEqual(zoom_level, current_zoom_level))
727 continue;
728 if (zoom_level < current_zoom_level) {
729 host->SetZoomLevel(zoom_level);
730 content::RecordAction(UserMetricsAction("ZoomMinus"));
731 return;
732 }
733 content::RecordAction(UserMetricsAction("ZoomMinus_AtMinimum"));
734 }
735 } else {
736 // Iterate through the zoom levels in normal order to find the next
737 // higher level based on the current zoom level for this page.
738 for (std::vector<double>::const_iterator i = zoom_levels.begin();
739 i != zoom_levels.end(); ++i) {
740 double zoom_level = *i;
741 if (content::ZoomValuesEqual(zoom_level, current_zoom_level))
742 continue;
743 if (zoom_level > current_zoom_level) {
744 host->SetZoomLevel(zoom_level);
745 content::RecordAction(UserMetricsAction("ZoomPlus"));
746 return;
747 }
748 }
749 content::RecordAction(UserMetricsAction("ZoomPlus_AtMaximum"));
750 }
751}
752
753void FocusToolbar(Browser* browser) {
754 content::RecordAction(UserMetricsAction("FocusToolbar"));
755 browser->window()->FocusToolbar();
756}
757
758void FocusLocationBar(Browser* browser) {
759 content::RecordAction(UserMetricsAction("FocusLocation"));
760 browser->window()->SetFocusToLocationBar(true);
761}
762
763void FocusSearch(Browser* browser) {
764 // TODO(beng): replace this with FocusLocationBar
765 content::RecordAction(UserMetricsAction("FocusSearch"));
766 browser->window()->GetLocationBar()->FocusSearch();
767}
768
769void FocusAppMenu(Browser* browser) {
770 content::RecordAction(UserMetricsAction("FocusAppMenu"));
771 browser->window()->FocusAppMenu();
772}
773
774void FocusBookmarksToolbar(Browser* browser) {
775 content::RecordAction(UserMetricsAction("FocusBookmarksToolbar"));
776 browser->window()->FocusBookmarksToolbar();
777}
778
779void FocusNextPane(Browser* browser) {
780 content::RecordAction(UserMetricsAction("FocusNextPane"));
781 browser->window()->RotatePaneFocus(true);
782}
783
784void FocusPreviousPane(Browser* browser) {
785 content::RecordAction(UserMetricsAction("FocusPreviousPane"));
786 browser->window()->RotatePaneFocus(false);
787}
788
789void ToggleDevToolsWindow(Browser* browser, DevToolsToggleAction action) {
790 if (action == DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE)
791 content::RecordAction(UserMetricsAction("DevTools_ToggleConsole"));
792 else
793 content::RecordAction(UserMetricsAction("DevTools_ToggleWindow"));
794
795 DevToolsWindow::ToggleDevToolsWindow(
796 browser->GetActiveWebContents()->GetRenderViewHost(),
797 action);
798}
799
800bool CanOpenTaskManager() {
801#if defined(OS_WIN)
802 // In metro we can't display the task manager, as it is a native window.
803 return !base::win::IsMetroProcess();
804#else
805 return true;
806#endif
807}
808
809void OpenTaskManager(Browser* browser, bool highlight_background_resources) {
810 content::RecordAction(UserMetricsAction("TaskManager"));
811 if (highlight_background_resources)
812 browser->window()->ShowBackgroundPages();
813 else
814 browser->window()->ShowTaskManager();
815}
816
817void OpenFeedbackDialog(Browser* browser) {
818 content::RecordAction(UserMetricsAction("Feedback"));
819 browser::ShowWebFeedbackView(browser, std::string(), std::string());
820}
821
822void ToggleBookmarkBar(Browser* browser) {
823 content::RecordAction(UserMetricsAction("ShowBookmarksBar"));
824 browser->window()->ToggleBookmarkBar();
825}
826
827void ShowAppMenu(Browser* browser) {
828 // We record the user metric for this event in WrenchMenu::RunMenu.
829 browser->window()->ShowAppMenu();
830}
831
832void ShowAvatarMenu(Browser* browser) {
833 browser->window()->ShowAvatarBubbleFromAvatarButton();
834}
835
836void OpenUpdateChromeDialog(Browser* browser) {
837 content::RecordAction(UserMetricsAction("UpdateChrome"));
838 browser->window()->ShowUpdateChromeDialog();
839}
840
841void ToggleSpeechInput(Browser* browser) {
842 browser->GetActiveWebContents()->GetRenderViewHost()->ToggleSpeechInput();
843}
844
[email protected]2cd4fde2012-06-26 03:10:26845void ViewSource(Browser* browser, TabContents* contents) {
846 DCHECK(contents);
847
848 NavigationEntry* active_entry =
849 contents->web_contents()->GetController().GetActiveEntry();
850 if (!active_entry)
851 return;
852
853 ViewSource(browser, contents, active_entry->GetURL(),
854 active_entry->GetContentState());
855}
856
857void ViewSource(Browser* browser,
858 TabContents* contents,
859 const GURL& url,
860 const std::string& content_state) {
861 content::RecordAction(UserMetricsAction("ViewSource"));
862 DCHECK(contents);
863
864 TabContents* view_source_contents = contents->Clone();
865 view_source_contents->web_contents()->GetController().PruneAllButActive();
866 NavigationEntry* active_entry =
867 view_source_contents->web_contents()->GetController().GetActiveEntry();
868 if (!active_entry)
869 return;
870
871 GURL view_source_url = GURL(chrome::kViewSourceScheme + std::string(":") +
872 url.spec());
873 active_entry->SetVirtualURL(view_source_url);
874
875 // Do not restore scroller position.
876 active_entry->SetContentState(
877 webkit_glue::RemoveScrollOffsetFromHistoryState(content_state));
878
879 // Do not restore title, derive it from the url.
880 active_entry->SetTitle(string16());
881
882 // Now show view-source entry.
883 if (browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP)) {
884 // If this is a tabbed browser, just create a duplicate tab inside the same
885 // window next to the tab being duplicated.
886 int index = browser->tab_strip_model()->GetIndexOfTabContents(contents);
887 int add_types = TabStripModel::ADD_ACTIVE |
888 TabStripModel::ADD_INHERIT_GROUP;
889 browser->tab_strip_model()->InsertTabContentsAt(index + 1,
890 view_source_contents,
891 add_types);
892 } else {
893 Browser* b = Browser::CreateWithParams(
894 Browser::CreateParams(Browser::TYPE_TABBED, browser->profile()));
895
896 // Preserve the size of the original window. The new window has already
897 // been given an offset by the OS, so we shouldn't copy the old bounds.
898 BrowserWindow* new_window = b->window();
899 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
900 browser->window()->GetRestoredBounds().size()));
901
902 // We need to show the browser now. Otherwise ContainerWin assumes the
903 // WebContents is invisible and won't size it.
904 b->window()->Show();
905
906 // The page transition below is only for the purpose of inserting the tab.
907 b->AddTab(view_source_contents, content::PAGE_TRANSITION_LINK);
908 }
909
910 SessionService* session_service =
911 SessionServiceFactory::GetForProfileIfExisting(browser->profile());
912 if (session_service)
913 session_service->TabRestored(view_source_contents, false);
914}
915
916void ViewSelectedSource(Browser* browser) {
917 ViewSource(browser, browser->GetActiveTabContents());
918}
919
[email protected]5d98294912012-06-27 22:57:40920bool CanViewSource(const Browser* browser) {
921 return browser->GetActiveWebContents()->GetController().CanViewSource();
922}
923
924bool CanCreateApplicationShortcuts(const Browser* browser) {
925 return web_app::IsValidUrl(browser->GetActiveWebContents()->GetURL());
926}
927
[email protected]40df6f52012-06-28 17:08:52928void ConvertTabToAppWindow(Browser* browser,
929 content::WebContents* contents) {
930 const GURL& url = contents->GetController().GetActiveEntry()->GetURL();
931 std::string app_name = web_app::GenerateApplicationNameFromURL(url);
932
933 int index = browser->tab_strip_model()->GetIndexOfWebContents(contents);
934 if (index >= 0)
935 browser->tab_strip_model()->DetachTabContentsAt(index);
936
937 Browser* app_browser = Browser::CreateWithParams(
938 Browser::CreateParams::CreateForApp(
939 Browser::TYPE_POPUP, app_name, gfx::Rect(), browser->profile()));
940 TabContents* tab_contents = TabContents::FromWebContents(contents);
941 if (!tab_contents)
942 tab_contents = new TabContents(contents);
943 app_browser->tab_strip_model()->AppendTabContents(tab_contents, true);
944
945 contents->GetMutableRendererPrefs()->can_accept_load_drops = false;
946 contents->GetRenderViewHost()->SyncRendererPrefs();
947 app_browser->window()->Show();
948}
949
[email protected]a37d4b02012-06-25 21:56:10950} // namespace chrome