From 69b04b9c7e94ab6a088cc5dde0e653223cc5e4e5 Mon Sep 17 00:00:00 2001 From: "ben@chromium.org" Date: Mon, 8 Nov 2010 22:12:18 +0000 Subject: Move browser.cc,h and browser_window.h to browser/ui TBR=brettw BUG=none TEST=none Review URL: http://codereview.chromium.org/4694002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@65438 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/browser.cc | 4089 ------------------------------------ chrome/browser/browser.h | 1087 +--------- chrome/browser/browser_window.h | 377 +--- chrome/browser/ui/browser.cc | 4089 ++++++++++++++++++++++++++++++++++++ chrome/browser/ui/browser.h | 1094 ++++++++++ chrome/browser/ui/browser_window.h | 384 ++++ chrome/chrome_browser.gypi | 6 +- 7 files changed, 5576 insertions(+), 5550 deletions(-) delete mode 100644 chrome/browser/browser.cc create mode 100644 chrome/browser/ui/browser.cc create mode 100644 chrome/browser/ui/browser.h create mode 100644 chrome/browser/ui/browser_window.h diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc deleted file mode 100644 index 52d3e5e..0000000 --- a/chrome/browser/browser.cc +++ /dev/null @@ -1,4089 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/browser.h" - -#if defined(OS_WIN) -#include -#include -#endif // OS_WIN - -#include -#include - -#include "app/animation.h" -#include "app/l10n_util.h" -#include "base/base_paths.h" -#include "base/command_line.h" -#include "base/logging.h" -#include "base/metrics/histogram.h" -#include "base/path_service.h" -#include "base/string_util.h" -#include "base/thread.h" -#include "base/thread_restrictions.h" -#include "base/utf_string_conversions.h" -#include "gfx/point.h" -#include "chrome/app/chrome_dll_resource.h" -#include "chrome/browser/autofill/autofill_manager.h" -#if defined(OS_WIN) -#include "chrome/browser/autofill/autofill_ie_toolbar_import_win.h" -#endif // defined(OS_WIN) -#include "chrome/browser/bookmarks/bookmark_model.h" -#include "chrome/browser/bookmarks/bookmark_utils.h" -#include "chrome/browser/browser_list.h" -#include "chrome/browser/browser_navigator.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/browser_shutdown.h" -#include "chrome/browser/browser_window.h" -#include "chrome/browser/browser_url_handler.h" -#include "chrome/browser/character_encoding.h" -#include "chrome/browser/debugger/devtools_manager.h" -#include "chrome/browser/debugger/devtools_toggle_action.h" -#include "chrome/browser/debugger/devtools_window.h" -#include "chrome/browser/dock_info.h" -#include "chrome/browser/dom_ui/filebrowse_ui.h" -#include "chrome/browser/dom_ui/options/content_settings_handler.h" -#include "chrome/browser/download/download_item.h" -#include "chrome/browser/download/download_item_model.h" -#include "chrome/browser/download/download_manager.h" -#include "chrome/browser/download/download_shelf.h" -#include "chrome/browser/download/download_started_animation.h" -#include "chrome/browser/extensions/crashed_extension_infobar.h" -#include "chrome/browser/extensions/extension_browser_event_router.h" -#include "chrome/browser/extensions/extension_disabled_infobar_delegate.h" -#include "chrome/browser/extensions/extension_host.h" -#include "chrome/browser/extensions/extension_prefs.h" -#include "chrome/browser/extensions/extension_tabs_module.h" -#include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/find_bar.h" -#include "chrome/browser/find_bar_controller.h" -#include "chrome/browser/first_run/first_run.h" -#include "chrome/browser/google/google_url_tracker.h" -#include "chrome/browser/google/google_util.h" -#include "chrome/browser/host_zoom_map.h" -#include "chrome/browser/instant/instant_controller.h" -#include "chrome/browser/location_bar.h" -#include "chrome/browser/metrics/user_metrics.h" -#include "chrome/browser/net/browser_url_util.h" -#include "chrome/browser/net/url_fixer_upper.h" -#include "chrome/browser/options_window.h" -#include "chrome/browser/platform_util.h" -#include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h" -#include "chrome/browser/profile.h" -#include "chrome/browser/renderer_host/render_view_host.h" -#include "chrome/browser/renderer_host/site_instance.h" -#include "chrome/browser/sessions/session_service.h" -#include "chrome/browser/sessions/session_types.h" -#include "chrome/browser/sessions/tab_restore_service.h" -#include "chrome/browser/status_bubble.h" -#include "chrome/browser/sync/profile_sync_service.h" -#include "chrome/browser/sync/sync_ui_util.h" -#include "chrome/browser/tab_closeable_state_watcher.h" -#include "chrome/browser/tab_contents/interstitial_page.h" -#include "chrome/browser/tab_contents/navigation_controller.h" -#include "chrome/browser/tab_contents/navigation_entry.h" -#include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/browser/tab_contents/tab_contents_view.h" -#include "chrome/browser/tab_menu_model.h" -#include "chrome/browser/tabs/tab_strip_model.h" -#include "chrome/browser/upgrade_detector.h" -#include "chrome/browser/web_applications/web_app.h" -#include "chrome/browser/window_sizer.h" -#include "chrome/common/chrome_constants.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/content_restriction.h" -#include "chrome/common/extensions/extension.h" -#include "chrome/common/notification_service.h" -#include "chrome/common/page_transition_types.h" -#include "chrome/common/pref_names.h" -#include "chrome/common/url_constants.h" -#include "grit/chromium_strings.h" -#include "grit/generated_resources.h" -#include "grit/locale_settings.h" -#include "net/base/cookie_monster.h" -#include "net/base/net_util.h" -#include "net/base/registry_controlled_domain.h" -#include "net/base/static_cookie_policy.h" -#include "net/url_request/url_request_context.h" -#include "webkit/glue/window_open_disposition.h" - -#if defined(ENABLE_REMOTING) -#include "chrome/browser/remoting/remoting_setup_flow.h" -#endif - -#if defined(OS_WIN) -#include "app/win_util.h" -#include "chrome/browser/browser_child_process_host.h" -#include "chrome/browser/cert_store.h" -#include "chrome/browser/download/save_package.h" -#include "chrome/browser/ssl/ssl_error_info.h" -#include "chrome/browser/shell_integration.h" -#include "chrome/browser/task_manager/task_manager.h" -#include "chrome/browser/view_ids.h" -#include "chrome/browser/views/location_bar/location_bar_view.h" -#endif // OS_WIN - -#if defined(OS_MACOSX) -#include "chrome/browser/cocoa/find_pasteboard.h" -#endif - -#if defined(OS_CHROMEOS) -#include // For GdkScreen -#include "chrome/browser/chromeos/cros/cros_library.h" -#include "chrome/browser/chromeos/cros/login_library.h" -#include "chrome/browser/chromeos/options/language_config_view.h" -#endif - -using base::TimeDelta; - -// How long we wait before updating the browser chrome while loading a page. -static const int kUIUpdateCoalescingTimeMS = 200; - -// The URL to be loaded to display Help. -#if defined(OS_CHROMEOS) -static const char* const kHelpContentUrl = - "chrome-extension://nifaohjgppdbmalmmgkmfdlodaggnbpe/main.html"; -#else -static const char* const kHelpContentUrl = - "http://www.google.com/support/chrome/"; -#endif - -// The URL to be loaded to display the "Report a broken page" form. -static const std::string kBrokenPageUrl = - "http://www.google.com/support/chrome/bin/request.py?contact_type=" - "broken_website&format=inproduct&p.page_title=$1&p.page_url=$2"; - -static const std::string kHashMark = "#"; - -// The URL for the privacy dashboard. -static const char kPrivacyDashboardUrl[] = "https://www.google.com/dashboard"; - -/////////////////////////////////////////////////////////////////////////////// - -namespace { - -#if defined(OS_CHROMEOS) -// If a popup window is bigger than this fraction of the screen on chrome os, -// turn it into a tab -const float kPopupMaxWidthFactor = 0.5; -const float kPopupMaxHeightFactor = 0.6; -#endif - -// Returns true if the specified TabContents has unload listeners registered. -bool TabHasUnloadListener(TabContents* contents) { - return contents->notify_disconnection() && - !contents->showing_interstitial_page() && - !contents->render_view_host()->SuddenTerminationAllowed(); -} - -} // namespace - -extern bool g_log_bug53991; - -/////////////////////////////////////////////////////////////////////////////// -// Browser, Constructors, Creation, Showing: - -Browser::Browser(Type type, Profile* profile) - : type_(type), - profile_(profile), - window_(NULL), - ALLOW_THIS_IN_INITIALIZER_LIST( - tab_handler_(TabHandler::CreateTabHandler(this))), - command_updater_(this), - toolbar_model_(this), - chrome_updater_factory_(this), - is_attempting_to_close_browser_(false), - cancel_download_confirmation_state_(NOT_PROMPTED), - maximized_state_(MAXIMIZED_STATE_DEFAULT), - method_factory_(this), - block_command_execution_(false), - last_blocked_command_id_(-1), - last_blocked_command_disposition_(CURRENT_TAB), - pending_web_app_action_(NONE), - extension_app_(NULL) { - registrar_.Add(this, NotificationType::SSL_VISIBLE_STATE_CHANGED, - NotificationService::AllSources()); - registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED, - NotificationService::AllSources()); - registrar_.Add(this, NotificationType::EXTENSION_LOADED, - NotificationService::AllSources()); - registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, - NotificationService::AllSources()); - registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED, - NotificationService::AllSources()); - registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED, - NotificationService::AllSources()); - registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, - NotificationService::AllSources()); - registrar_.Add(this, NotificationType::PROFILE_ERROR, - NotificationService::AllSources()); - - // Need to know when to alert the user of theme install delay. - registrar_.Add(this, NotificationType::EXTENSION_READY_FOR_INSTALL, - NotificationService::AllSources()); - - PrefService* local_state = g_browser_process->local_state(); - if (local_state) - printing_enabled_.Init(prefs::kPrintingEnabled, local_state, this); - dev_tools_disabled_.Init(prefs::kDevToolsDisabled, - profile_->GetPrefs(), this); - - InitCommandState(); - BrowserList::AddBrowser(this); - - encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector, - profile_->GetPrefs(), NULL); - use_vertical_tabs_.Init(prefs::kUseVerticalTabs, profile_->GetPrefs(), this); - instant_enabled_.Init(prefs::kInstantEnabled, profile_->GetPrefs(), this); - if (!TabMenuModel::AreVerticalTabsEnabled()) { - // If vertical tabs aren't enabled, explicitly turn them off. Otherwise we - // might show vertical tabs but not show an option to turn them off. - use_vertical_tabs_.SetValue(false); - } - UpdateTabStripModelInsertionPolicy(); - - tab_restore_service_ = profile->GetTabRestoreService(); - if (tab_restore_service_) { - tab_restore_service_->AddObserver(this); - TabRestoreServiceChanged(tab_restore_service_); - } - - if (profile_->GetProfileSyncService()) - profile_->GetProfileSyncService()->AddObserver(this); - - CreateInstantIfNecessary(); -} - -Browser::~Browser() { - VLOG_IF(1, g_log_bug53991) << "~Browser: " << profile_->IsOffTheRecord() - << "; stillActive=" - << BrowserList::IsOffTheRecordSessionActive(); - - if (profile_->GetProfileSyncService()) - profile_->GetProfileSyncService()->RemoveObserver(this); - - BrowserList::RemoveBrowser(this); - -#if defined(OS_WIN) || defined(OS_LINUX) - if (!BrowserList::HasBrowserWithProfile(profile_)) { - // We're the last browser window with this profile. We need to nuke the - // TabRestoreService, which will start the shutdown of the - // NavigationControllers and allow for proper shutdown. If we don't do this - // chrome won't shutdown cleanly, and may end up crashing when some - // thread tries to use the IO thread (or another thread) that is no longer - // valid. - // This isn't a valid assumption for Mac OS, as it stays running after - // the last browser has closed. The Mac equivalent is in its app - // controller. - profile_->ResetTabRestoreService(); - } -#endif - - SessionService* session_service = profile_->GetSessionService(); - if (session_service) - session_service->WindowClosed(session_id_); - - TabRestoreService* tab_restore_service = profile()->GetTabRestoreService(); - if (tab_restore_service) - tab_restore_service->BrowserClosed(this); - - if (profile_->IsOffTheRecord() && - !BrowserList::IsOffTheRecordSessionActive()) { - // An off-the-record profile is no longer needed, this indirectly - // frees its cache and cookies. - profile_->GetOriginalProfile()->DestroyOffTheRecordProfile(); - } - - // There may be pending file dialogs, we need to tell them that we've gone - // away so they don't try and call back to us. - if (select_file_dialog_.get()) - select_file_dialog_->ListenerDestroyed(); - - TabRestoreServiceDestroyed(tab_restore_service_); -} - -// static -Browser* Browser::Create(Profile* profile) { - Browser* browser = new Browser(TYPE_NORMAL, profile); - browser->CreateBrowserWindow(); - return browser; -} - -// static -Browser* Browser::CreateForPopup(Type type, - Profile* profile, - TabContents* new_contents, - const gfx::Rect& initial_bounds) { - DCHECK(type & TYPE_POPUP); - Browser* browser = new Browser(type, profile); - browser->set_override_bounds(initial_bounds); - browser->CreateBrowserWindow(); - browser->tabstrip_model()->AppendTabContents(new_contents, true); - return browser; -} - -// static -Browser* Browser::CreateForType(Type type, Profile* profile) { - Browser* browser = new Browser(type, profile); - browser->CreateBrowserWindow(); - return browser; -} - -// static -Browser* Browser::CreateForApp(const std::string& app_name, - const Extension* extension, - Profile* profile, - bool is_panel) { - Browser::Type type = TYPE_APP; - - if (is_panel) { - // TYPE_APP_PANEL is the logical choice. However, the panel UI - // is not fully implemented. See crbug/55943. - type = TYPE_APP_POPUP; - } else if (extension) { - type = TYPE_EXTENSION_APP; - } - - Browser* browser = new Browser(type, profile); - browser->app_name_ = app_name; - browser->extension_app_ = extension; - - if (extension) { - gfx::Rect initial_pos(extension->launch_width(), - extension->launch_height()); - if (!initial_pos.IsEmpty()) - browser->set_override_bounds(initial_pos); - } - - browser->CreateBrowserWindow(); - - return browser; -} - -// static -Browser* Browser::CreateForDevTools(Profile* profile) { - Browser* browser = new Browser(TYPE_DEVTOOLS, profile); - browser->app_name_ = DevToolsWindow::kDevToolsApp; - browser->CreateBrowserWindow(); - return browser; -} - -void Browser::CreateBrowserWindow() { - DCHECK(!window_); - - window_ = BrowserWindow::CreateBrowserWindow(this); - -#if defined(OS_WIN) - { - // TODO: This might hit the disk - // http://code.google.com/p/chromium/issues/detail?id=61638 - base::ThreadRestrictions::ScopedAllowIO allow_io; - - // Set the app user model id for this application to that of the application - // name. See http://crbug.com/7028. - win_util::SetAppIdForWindow( - type_ & TYPE_APP ? - ShellIntegration::GetAppId(UTF8ToWide(app_name_), profile_->GetPath()) : - ShellIntegration::GetChromiumAppId(profile_->GetPath()), - window()->GetNativeHandle()); - } -#endif - - NotificationService::current()->Notify( - NotificationType::BROWSER_WINDOW_READY, - Source(this), - NotificationService::NoDetails()); - - // Show the First Run information bubble if we've been told to. - PrefService* local_state = g_browser_process->local_state(); - if (!local_state) - return; - if (local_state->FindPreference(prefs::kShouldShowFirstRunBubble) && - local_state->GetBoolean(prefs::kShouldShowFirstRunBubble)) { - FirstRun::BubbleType bubble_type = FirstRun::LARGE_BUBBLE; - if (local_state-> - FindPreference(prefs::kShouldUseOEMFirstRunBubble) && - local_state->GetBoolean(prefs::kShouldUseOEMFirstRunBubble)) { - bubble_type = FirstRun::OEM_BUBBLE; - } else if (local_state-> - FindPreference(prefs::kShouldUseMinimalFirstRunBubble) && - local_state->GetBoolean(prefs::kShouldUseMinimalFirstRunBubble)) { - bubble_type = FirstRun::MINIMAL_BUBBLE; - } - // Reset the preference so we don't show the bubble for subsequent windows. - local_state->ClearPref(prefs::kShouldShowFirstRunBubble); - window_->GetLocationBar()->ShowFirstRunBubble(bubble_type); - } - if (local_state->FindPreference( - prefs::kAutoFillPersonalDataManagerFirstRun) && - local_state->GetBoolean(prefs::kAutoFillPersonalDataManagerFirstRun)) { - // Notify PDM that this is a first run. -#if defined(OS_WIN) - ImportAutofillDataWin(profile_->GetPersonalDataManager()); -#endif // defined(OS_WIN) - // Reset the preference so we don't call it again for subsequent windows. - local_state->ClearPref(prefs::kAutoFillPersonalDataManagerFirstRun); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Getters & Setters - -const std::vector& Browser::user_data_dir_profiles() const { - return g_browser_process->user_data_dir_profiles(); -} - -void Browser::set_user_data_dir_profiles( - const std::vector& profiles) { - g_browser_process->user_data_dir_profiles() = profiles; -} - -FindBarController* Browser::GetFindBarController() { - if (!find_bar_controller_.get()) { - FindBar* find_bar = BrowserWindow::CreateFindBar(this); - find_bar_controller_.reset(new FindBarController(find_bar)); - find_bar->SetFindBarController(find_bar_controller_.get()); - find_bar_controller_->ChangeTabContents(GetSelectedTabContents()); - find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true); - } - return find_bar_controller_.get(); -} - -bool Browser::HasFindBarController() const { - return find_bar_controller_.get() != NULL; -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, Creation Helpers: - -// static -void Browser::OpenEmptyWindow(Profile* profile) { - Browser* browser = Browser::Create(profile); - browser->AddBlankTab(true); - browser->window()->Show(); -} - -// static -void Browser::OpenWindowWithRestoredTabs(Profile* profile) { - TabRestoreService* service = profile->GetTabRestoreService(); - if (service) - service->RestoreMostRecentEntry(NULL); -} - -// static -void Browser::OpenURLOffTheRecord(Profile* profile, const GURL& url) { - Browser* browser = GetOrCreateTabbedBrowser( - profile->GetOffTheRecordProfile()); - browser->AddSelectedTabWithURL(url, PageTransition::LINK); - browser->window()->Show(); -} - -// static -// TODO(erikkay): There are multiple reasons why this could fail. Should -// this function return an error reason as well so that callers can show -// reasonable errors? -TabContents* Browser::OpenApplication(Profile* profile, - const std::string& app_id, - TabContents* existing_tab) { - ExtensionsService* extensions_service = profile->GetExtensionsService(); - if (!extensions_service->is_ready()) - return NULL; - - // If the extension with |app_id| could't be found, most likely because it - // was uninstalled. - const Extension* extension = - extensions_service->GetExtensionById(app_id, false); - if (!extension) - return NULL; - - return OpenApplication(profile, extension, extension->launch_container(), - existing_tab); -} - -// static -TabContents* Browser::OpenApplication( - Profile* profile, - const Extension* extension, - extension_misc::LaunchContainer container, - TabContents* existing_tab) { - TabContents* tab = NULL; - - UMA_HISTOGRAM_ENUMERATION("Extensions.AppLaunchContainer", container, 100); - - // The app is not yet open. Load it. - switch (container) { - case extension_misc::LAUNCH_WINDOW: - case extension_misc::LAUNCH_PANEL: - tab = Browser::OpenApplicationWindow(profile, extension, container, - GURL()); - break; - case extension_misc::LAUNCH_TAB: { - tab = Browser::OpenApplicationTab(profile, extension, existing_tab); - break; - } - default: - NOTREACHED(); - break; - } - return tab; -} - -// static -TabContents* Browser::OpenApplicationWindow( - Profile* profile, - const Extension* extension, - extension_misc::LaunchContainer container, - const GURL& url_input) { - GURL url; - if (!url_input.is_empty()) { - if (extension) - DCHECK(extension->web_extent().ContainsURL(url_input)); - url = url_input; - } else { - DCHECK(extension); - url = extension->GetFullLaunchURL(); - } - - // TODO(erikkay) this can't be correct for extensions - std::string app_name = web_app::GenerateApplicationNameFromURL(url); - RegisterAppPrefs(app_name); - - bool as_panel = extension && (container == extension_misc::LAUNCH_PANEL); - Browser* browser = Browser::CreateForApp(app_name, extension, profile, - as_panel); - TabContents* contents = - browser->AddSelectedTabWithURL(url, PageTransition::START_PAGE); - contents->GetMutableRendererPrefs()->can_accept_load_drops = false; - contents->render_view_host()->SyncRendererPrefs(); - browser->window()->Show(); - - // TODO(jcampan): http://crbug.com/8123 we should not need to set the initial - // focus explicitly. - contents->view()->SetInitialFocus(); - - if (!as_panel) { - // Set UPDATE_SHORTCUT as the pending web app action. This action is picked - // up in LoadingStateChanged to schedule a GetApplicationInfo. And when - // the web app info is available, TabContents notifies Browser via - // OnDidGetApplicationInfo, which calls - // web_app::UpdateShortcutForTabContents when it sees UPDATE_SHORTCUT as - // pending web app action. - browser->pending_web_app_action_ = UPDATE_SHORTCUT; - } - - return contents; -} - -// static -TabContents* Browser::OpenApplicationWindow(Profile* profile, GURL& url) { - return OpenApplicationWindow(profile, NULL, extension_misc::LAUNCH_WINDOW, - url); -} - -// static -TabContents* Browser::OpenApplicationTab(Profile* profile, - const Extension* extension, - TabContents* existing_tab) { - Browser* browser = BrowserList::GetLastActiveWithProfile(profile); - TabContents* contents = NULL; - if (!browser || browser->type() != Browser::TYPE_NORMAL) - return contents; - - // Check the prefs for overridden mode. - ExtensionsService* extensions_service = profile->GetExtensionsService(); - DCHECK(extensions_service); - - ExtensionPrefs::LaunchType launch_type = - extensions_service->extension_prefs()->GetLaunchType(extension->id()); - UMA_HISTOGRAM_ENUMERATION("Extensions.AppTabLaunchType", launch_type, 100); - int add_type = TabStripModel::ADD_SELECTED; - if (launch_type == ExtensionPrefs::LAUNCH_PINNED) - add_type |= TabStripModel::ADD_PINNED; - - // TODO(erikkay): START_PAGE doesn't seem like the right transition in all - // cases. - browser::NavigateParams params(browser, extension->GetFullLaunchURL(), - PageTransition::START_PAGE); - params.tabstrip_add_types = add_type; - - // Launch the application in the existing TabContents, if it was supplied. - if (existing_tab) { - TabStripModel* model = browser->tabstrip_model(); - int tab_index = model->GetIndexOfTabContents(existing_tab); - - existing_tab->OpenURL(extension->GetFullLaunchURL(), existing_tab->GetURL(), - CURRENT_TAB, PageTransition::LINK); - if (params.tabstrip_add_types & TabStripModel::ADD_PINNED) { - model->SetTabPinned(tab_index, true); - tab_index = model->GetIndexOfTabContents(existing_tab); - } - if (params.tabstrip_add_types & TabStripModel::ADD_SELECTED) - model->SelectTabContentsAt(tab_index, true); - - contents = existing_tab; - } else { - params.disposition = NEW_FOREGROUND_TAB; - browser::Navigate(¶ms); - contents = params.target_contents; - } - - if (launch_type == ExtensionPrefs::LAUNCH_FULLSCREEN) - browser->window()->SetFullscreen(true); - - return contents; -} - -// static -void Browser::OpenBookmarkManagerWindow(Profile* profile) { - Browser* browser = Browser::Create(profile); - browser->ShowBookmarkManagerTab(); - browser->window()->Show(); -} - -#if defined(OS_MACOSX) -// static -void Browser::OpenHistoryWindow(Profile* profile) { - Browser* browser = Browser::Create(profile); - browser->ShowHistoryTab(); - browser->window()->Show(); -} - -// static -void Browser::OpenDownloadsWindow(Profile* profile) { - Browser* browser = Browser::Create(profile); - browser->ShowDownloadsTab(); - browser->window()->Show(); -} - -// static -void Browser::OpenHelpWindow(Profile* profile) { - Browser* browser = Browser::Create(profile); - browser->OpenHelpTab(); - browser->window()->Show(); -} - -void Browser::OpenOptionsWindow(Profile* profile) { - Browser* browser = Browser::Create(profile); - browser->ShowOptionsTab(chrome::kDefaultOptionsSubPage); - browser->window()->Show(); -} -#endif - -// static -void Browser::OpenExtensionsWindow(Profile* profile) { - Browser* browser = Browser::Create(profile); - browser->ShowExtensionsTab(); - browser->window()->Show(); -} - - -/////////////////////////////////////////////////////////////////////////////// -// Browser, State Storage and Retrieval for UI: - -std::string Browser::GetWindowPlacementKey() const { - std::string name(prefs::kBrowserWindowPlacement); - if (!app_name_.empty()) { - name.append("_"); - name.append(app_name_); - } - return name; -} - -bool Browser::ShouldSaveWindowPlacement() const { - // Only save the window placement of popups if they are restored. - return (type() & TYPE_POPUP) == 0 || browser_defaults::kRestorePopups; -} - -void Browser::SaveWindowPlacement(const gfx::Rect& bounds, bool maximized) { - // Save to the session storage service, used when reloading a past session. - // Note that we don't want to be the ones who cause lazy initialization of - // the session service. This function gets called during initial window - // showing, and we don't want to bring in the session service this early. - if (profile()->HasSessionService()) { - SessionService* session_service = profile()->GetSessionService(); - if (session_service) - session_service->SetWindowBounds(session_id_, bounds, maximized); - } -} - -gfx::Rect Browser::GetSavedWindowBounds() const { - const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); - bool record_mode = parsed_command_line.HasSwitch(switches::kRecordMode); - bool playback_mode = parsed_command_line.HasSwitch(switches::kPlaybackMode); - if (record_mode || playback_mode) { - // In playback/record mode we always fix the size of the browser and - // move it to (0,0). The reason for this is two reasons: First we want - // resize/moves in the playback to still work, and Second we want - // playbacks to work (as much as possible) on machines w/ different - // screen sizes. - return gfx::Rect(0, 0, 800, 600); - } - - gfx::Rect restored_bounds = override_bounds_; - bool maximized; - WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, NULL, - &restored_bounds, &maximized); - return restored_bounds; -} - -// TODO(beng): obtain maximized state some other way so we don't need to go -// through all this hassle. -bool Browser::GetSavedMaximizedState() const { - if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStartMaximized)) - return true; - - if (maximized_state_ == MAXIMIZED_STATE_MAXIMIZED) - return true; - if (maximized_state_ == MAXIMIZED_STATE_UNMAXIMIZED) - return false; - - // An explicit maximized state was not set. Query the window sizer. - gfx::Rect restored_bounds; - bool maximized = false; - WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, NULL, - &restored_bounds, &maximized); - return maximized; -} - -SkBitmap Browser::GetCurrentPageIcon() const { - TabContents* contents = GetSelectedTabContents(); - // |contents| can be NULL since GetCurrentPageIcon() is called by the window - // during the window's creation (before tabs have been added). - return contents ? contents->GetFavIcon() : SkBitmap(); -} - -string16 Browser::GetWindowTitleForCurrentTab() const { - TabContents* contents = - tab_handler_->GetTabStripModel()->GetSelectedTabContents(); - string16 title; - - // |contents| can be NULL because GetWindowTitleForCurrentTab is called by the - // window during the window's creation (before tabs have been added). - if (contents) { - title = contents->GetTitle(); - FormatTitleForDisplay(&title); - } - if (title.empty()) - title = TabContents::GetDefaultTitle(); - -#if defined(OS_MACOSX) || defined(OS_CHROMEOS) - // On Mac or ChromeOS, we don't want to suffix the page title with - // the application name. - return title; -#elif defined(OS_WIN) || defined(OS_LINUX) - int string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT; - // Don't append the app name to window titles on app frames and app popups - if (type_ & TYPE_APP) - string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT_NO_LOGO; - return l10n_util::GetStringFUTF16(string_id, title); -#endif -} - -// static -void Browser::FormatTitleForDisplay(string16* title) { - size_t current_index = 0; - size_t match_index; - while ((match_index = title->find(L'\n', current_index)) != string16::npos) { - title->replace(match_index, 1, string16()); - current_index = match_index; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, OnBeforeUnload handling: - -bool Browser::ShouldCloseWindow() { - if (!CanCloseWithInProgressDownloads()) - return false; - - if (HasCompletedUnloadProcessing()) - return IsClosingPermitted(); - - is_attempting_to_close_browser_ = true; - - for (int i = 0; i < tab_count(); ++i) { - TabContents* contents = GetTabContentsAt(i); - if (TabHasUnloadListener(contents)) - tabs_needing_before_unload_fired_.insert(contents); - } - - if (tabs_needing_before_unload_fired_.empty()) - return IsClosingPermitted(); - - ProcessPendingTabs(); - return false; -} - -void Browser::OnWindowClosing() { - if (!ShouldCloseWindow()) - return; - - bool exiting = false; - - // Application should shutdown on last window close if the user is explicitly - // trying to quit, or if there is nothing keeping the browser alive (such as - // AppController on the Mac, or BackgroundContentsService for background - // pages). - bool should_quit_if_last_browser = - browser_shutdown::IsTryingToQuit() || !BrowserList::WillKeepAlive(); - - if (should_quit_if_last_browser && BrowserList::size() == 1) { - browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE); - exiting = true; - } - - // Don't use HasSessionService here, we want to force creation of the - // session service so that user can restore what was open. - SessionService* session_service = profile()->GetSessionService(); - if (session_service) - session_service->WindowClosing(session_id()); - - TabRestoreService* tab_restore_service = profile()->GetTabRestoreService(); - if (tab_restore_service) - tab_restore_service->BrowserClosing(this); - - // TODO(sky): convert session/tab restore to use notification. - NotificationService::current()->Notify( - NotificationType::BROWSER_CLOSING, - Source(this), - Details(&exiting)); - - CloseAllTabs(); -} - -//////////////////////////////////////////////////////////////////////////////// -// In-progress download termination handling: - -void Browser::InProgressDownloadResponse(bool cancel_downloads) { - if (cancel_downloads) { - cancel_download_confirmation_state_ = RESPONSE_RECEIVED; - CloseWindow(); - return; - } - - // Sets the confirmation state to NOT_PROMPTED so that if the user tries to - // close again we'll show the warning again. - cancel_download_confirmation_state_ = NOT_PROMPTED; - - // Show the download page so the user can figure-out what downloads are still - // in-progress. - ShowDownloadsTab(); -} - -//////////////////////////////////////////////////////////////////////////////// -// Browser, TabStripModel pass-thrus: - -int Browser::tab_count() const { - return tab_handler_->GetTabStripModel()->count(); -} - -int Browser::selected_index() const { - return tab_handler_->GetTabStripModel()->selected_index(); -} - -int Browser::GetIndexOfController( - const NavigationController* controller) const { - return tab_handler_->GetTabStripModel()->GetIndexOfController(controller); -} - -TabContents* Browser::GetTabContentsAt(int index) const { - return tab_handler_->GetTabStripModel()->GetTabContentsAt(index); -} - -TabContents* Browser::GetSelectedTabContents() const { - return tab_handler_->GetTabStripModel()->GetSelectedTabContents(); -} - -void Browser::SelectTabContentsAt(int index, bool user_gesture) { - tab_handler_->GetTabStripModel()->SelectTabContentsAt(index, user_gesture); -} - -void Browser::CloseAllTabs() { - tab_handler_->GetTabStripModel()->CloseAllTabs(); -} - -//////////////////////////////////////////////////////////////////////////////// -// Browser, Tab adding/showing functions: - -int Browser::GetIndexForInsertionDuringRestore(int relative_index) { - return (tab_handler_->GetTabStripModel()->insertion_policy() == - TabStripModel::INSERT_AFTER) ? tab_count() : relative_index; -} - -TabContents* Browser::AddSelectedTabWithURL(const GURL& url, - PageTransition::Type transition) { - browser::NavigateParams params(this, url, transition); - params.disposition = NEW_FOREGROUND_TAB; - browser::Navigate(¶ms); - return params.target_contents; -} - -TabContents* Browser::AddTab(TabContents* tab_contents, - PageTransition::Type type) { - tab_handler_->GetTabStripModel()->AddTabContents( - tab_contents, -1, type, TabStripModel::ADD_SELECTED); - return tab_contents; -} - -void Browser::AddTabContents(TabContents* new_contents, - WindowOpenDisposition disposition, - const gfx::Rect& initial_pos, - bool user_gesture) { - AddNewContents(NULL, new_contents, disposition, initial_pos, user_gesture); -} - -void Browser::CloseTabContents(TabContents* contents) { - CloseContents(contents); -} - -void Browser::BrowserShowHtmlDialog(HtmlDialogUIDelegate* delegate, - gfx::NativeWindow parent_window) { - ShowHtmlDialog(delegate, parent_window); -} - -void Browser::BrowserRenderWidgetShowing() { - RenderWidgetShowing(); -} - -void Browser::ToolbarSizeChanged(bool is_animating) { - ToolbarSizeChanged(NULL, is_animating); -} - -TabContents* Browser::AddRestoredTab( - const std::vector& navigations, - int tab_index, - int selected_navigation, - const std::string& extension_app_id, - bool select, - bool pin, - bool from_last_session, - SessionStorageNamespace* session_storage_namespace) { - TabContents* new_tab = new TabContents( - profile(), NULL, MSG_ROUTING_NONE, - tab_handler_->GetTabStripModel()->GetSelectedTabContents(), - session_storage_namespace); - new_tab->SetExtensionAppById(extension_app_id); - new_tab->controller().RestoreFromState(navigations, selected_navigation, - from_last_session); - - bool really_pin = - (pin && tab_index == tabstrip_model()->IndexOfFirstNonMiniTab()); - tab_handler_->GetTabStripModel()->InsertTabContentsAt( - tab_index, new_tab, - select ? TabStripModel::ADD_SELECTED : TabStripModel::ADD_NONE); - if (really_pin) - tab_handler_->GetTabStripModel()->SetTabPinned(tab_index, true); - if (select) { - window_->Activate(); - } else { - // We set the size of the view here, before WebKit does its initial - // layout. If we don't, the initial layout of background tabs will be - // performed with a view width of 0, which may cause script outputs and - // anchor link location calculations to be incorrect even after a new - // layout with proper view dimensions. TabStripModel::AddTabContents() - // contains similar logic. - new_tab->view()->SizeContents(window_->GetRestoredBounds().size()); - new_tab->HideContents(); - } - if (profile_->HasSessionService()) { - SessionService* session_service = profile_->GetSessionService(); - if (session_service) - session_service->TabRestored(&new_tab->controller(), really_pin); - } - return new_tab; -} - -void Browser::ReplaceRestoredTab( - const std::vector& navigations, - int selected_navigation, - bool from_last_session, - const std::string& extension_app_id, - SessionStorageNamespace* session_storage_namespace) { - TabContents* replacement = new TabContents(profile(), NULL, - MSG_ROUTING_NONE, - tab_handler_->GetTabStripModel()->GetSelectedTabContents(), - session_storage_namespace); - replacement->SetExtensionAppById(extension_app_id); - replacement->controller().RestoreFromState(navigations, selected_navigation, - from_last_session); - - tab_handler_->GetTabStripModel()->ReplaceNavigationControllerAt( - tab_handler_->GetTabStripModel()->selected_index(), - &replacement->controller()); -} - -bool Browser::CanRestoreTab() { - return command_updater_.IsCommandEnabled(IDC_RESTORE_TAB); -} - -bool Browser::NavigateToIndexWithDisposition(int index, - WindowOpenDisposition disp) { - NavigationController& controller = - GetOrCloneTabForDisposition(disp)->controller(); - if (index < 0 || index >= controller.entry_count()) - return false; - controller.GoToIndex(index); - return true; -} - -void Browser::ShowSingletonTab(const GURL& url) { - browser::NavigateParams params(this, url, PageTransition::AUTO_BOOKMARK); - params.disposition = SINGLETON_TAB; - params.show_window = true; - browser::Navigate(¶ms); -} - -void Browser::UpdateCommandsForFullscreenMode(bool is_fullscreen) { -#if !defined(OS_MACOSX) - const bool show_main_ui = (type() == TYPE_NORMAL) && !is_fullscreen; -#else - const bool show_main_ui = (type() == TYPE_NORMAL); -#endif - - bool main_not_fullscreen_or_popup = - show_main_ui && !is_fullscreen && (type() & TYPE_POPUP) == 0; - - // Navigation commands - command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, show_main_ui); - - // Window management commands - command_updater_.UpdateCommandEnabled(IDC_SHOW_AS_TAB, - (type() & TYPE_POPUP) && !is_fullscreen); - - // Focus various bits of UI - command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, show_main_ui); - command_updater_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, show_main_ui); - command_updater_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, show_main_ui); - command_updater_.UpdateCommandEnabled( - IDC_FOCUS_MENU_BAR, main_not_fullscreen_or_popup); - command_updater_.UpdateCommandEnabled( - IDC_FOCUS_NEXT_PANE, main_not_fullscreen_or_popup); - command_updater_.UpdateCommandEnabled( - IDC_FOCUS_PREVIOUS_PANE, main_not_fullscreen_or_popup); - command_updater_.UpdateCommandEnabled( - IDC_FOCUS_BOOKMARKS, main_not_fullscreen_or_popup); - command_updater_.UpdateCommandEnabled( - IDC_FOCUS_CHROMEOS_STATUS, main_not_fullscreen_or_popup); - - // Show various bits of UI - command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, show_main_ui); - command_updater_.UpdateCommandEnabled(IDC_REPORT_BUG, show_main_ui); - command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR, - browser_defaults::bookmarks_enabled && show_main_ui); - command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, show_main_ui); - command_updater_.UpdateCommandEnabled(IDC_SYNC_BOOKMARKS, - show_main_ui && profile_->IsSyncAccessible()); - -#if defined(ENABLE_REMOTING) - if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableRemoting)) { - command_updater_.UpdateCommandEnabled(IDC_REMOTING_SETUP, show_main_ui); - } -#endif - - command_updater_.UpdateCommandEnabled(IDC_OPTIONS, show_main_ui); - command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui); - command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui); - command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui); - command_updater_.UpdateCommandEnabled(IDC_SHOW_APP_MENU, show_main_ui); - command_updater_.UpdateCommandEnabled(IDC_TOGGLE_VERTICAL_TABS, show_main_ui); -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, Assorted browser commands: - -bool Browser::ShouldOpenNewTabForWindowDisposition( - WindowOpenDisposition disposition) { - return (disposition == NEW_FOREGROUND_TAB || - disposition == NEW_BACKGROUND_TAB); -} - -TabContents* Browser::GetOrCloneTabForDisposition( - WindowOpenDisposition disposition) { - TabContents* current_tab = GetSelectedTabContents(); - if (ShouldOpenNewTabForWindowDisposition(disposition)) { - current_tab = current_tab->Clone(); - tab_handler_->GetTabStripModel()->AddTabContents( - current_tab, -1, PageTransition::LINK, - disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_SELECTED : - TabStripModel::ADD_NONE); - } - return current_tab; -} - -void Browser::UpdateTabStripModelInsertionPolicy() { - tab_handler_->GetTabStripModel()->SetInsertionPolicy(UseVerticalTabs() ? - TabStripModel::INSERT_BEFORE : TabStripModel::INSERT_AFTER); -} - -void Browser::UseVerticalTabsChanged() { - UpdateTabStripModelInsertionPolicy(); - window()->ToggleTabStripMode(); -} - -bool Browser::SupportsWindowFeatureImpl(WindowFeature feature, - bool check_fullscreen) const { - // On Mac, fullscreen mode has most normal things (in a slide-down panel). On - // other platforms, we hide some controls when in fullscreen mode. - bool hide_ui_for_fullscreen = false; -#if !defined(OS_MACOSX) - hide_ui_for_fullscreen = check_fullscreen && window_ && - window_->IsFullscreen(); -#endif - - unsigned int features = FEATURE_INFOBAR | FEATURE_SIDEBAR; - -#if !defined(OS_CHROMEOS) - // Chrome OS opens a FileBrowse pop up instead of using download shelf. - // So FEATURE_DOWNLOADSHELF is only added for non-chromeos platforms. - features |= FEATURE_DOWNLOADSHELF; -#endif // !defined(OS_CHROMEOS) - - if (type() == TYPE_NORMAL) { - features |= FEATURE_BOOKMARKBAR; - } - - if (!hide_ui_for_fullscreen) { - if (type() != TYPE_NORMAL && type() != TYPE_EXTENSION_APP) - features |= FEATURE_TITLEBAR; - - if (type() == TYPE_NORMAL || type() == TYPE_EXTENSION_APP) - features |= FEATURE_TABSTRIP; - - if (type() == TYPE_NORMAL || type() == TYPE_EXTENSION_APP) - features |= FEATURE_TOOLBAR; - - if (type() != TYPE_EXTENSION_APP && (type() & Browser::TYPE_APP) == 0) - features |= FEATURE_LOCATIONBAR; - } - return !!(features & feature); -} - -bool Browser::IsClosingPermitted() { - TabCloseableStateWatcher* watcher = - g_browser_process->tab_closeable_state_watcher(); - bool can_close = !watcher || watcher->CanCloseBrowser(this); - if (!can_close && is_attempting_to_close_browser_) - CancelWindowClose(); - return can_close; -} - -void Browser::GoBack(WindowOpenDisposition disposition) { - UserMetrics::RecordAction(UserMetricsAction("Back"), profile_); - - TabContents* current_tab = GetSelectedTabContents(); - if (current_tab->controller().CanGoBack()) { - TabContents* new_tab = GetOrCloneTabForDisposition(disposition); - // If we are on an interstitial page and clone the tab, it won't be copied - // to the new tab, so we don't need to go back. - if (current_tab->showing_interstitial_page() && (new_tab != current_tab)) - return; - new_tab->controller().GoBack(); - } -} - -void Browser::GoForward(WindowOpenDisposition disposition) { - UserMetrics::RecordAction(UserMetricsAction("Forward"), profile_); - if (GetSelectedTabContents()->controller().CanGoForward()) - GetOrCloneTabForDisposition(disposition)->controller().GoForward(); -} - -void Browser::Reload(WindowOpenDisposition disposition) { - UserMetrics::RecordAction(UserMetricsAction("Reload"), profile_); - ReloadInternal(disposition, false); -} - -void Browser::ReloadIgnoringCache(WindowOpenDisposition disposition) { - UserMetrics::RecordAction(UserMetricsAction("ReloadIgnoringCache"), profile_); - ReloadInternal(disposition, true); -} - -void Browser::ReloadInternal(WindowOpenDisposition disposition, - bool ignore_cache) { - // If we are showing an interstitial, treat this as an OpenURL. - TabContents* current_tab = GetSelectedTabContents(); - if (current_tab && current_tab->showing_interstitial_page()) { - NavigationEntry* entry = current_tab->controller().GetActiveEntry(); - DCHECK(entry); // Should exist if interstitial is showing. - OpenURL(entry->url(), GURL(), disposition, PageTransition::RELOAD); - return; - } - - // As this is caused by a user action, give the focus to the page. - current_tab = GetOrCloneTabForDisposition(disposition); - if (!current_tab->FocusLocationBarByDefault()) - current_tab->Focus(); - if (ignore_cache) - current_tab->controller().ReloadIgnoringCache(true); - else - current_tab->controller().Reload(true); -} - -void Browser::Home(WindowOpenDisposition disposition) { - UserMetrics::RecordAction(UserMetricsAction("Home"), profile_); - OpenURL(GetHomePage(), GURL(), disposition, PageTransition::AUTO_BOOKMARK); -} - -void Browser::OpenCurrentURL() { - UserMetrics::RecordAction(UserMetricsAction("LoadURL"), profile_); - LocationBar* location_bar = window_->GetLocationBar(); - WindowOpenDisposition open_disposition = - location_bar->GetWindowOpenDisposition(); - if (OpenInstant(open_disposition)) - return; - - GURL url(WideToUTF8(location_bar->GetInputString())); - browser::NavigateParams params(this, url, location_bar->GetPageTransition()); - params.disposition = open_disposition; - // Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least - // inherit the opener. In some cases the tabstrip will determine the group - // should be inherited, in which case the group is inherited instead of the - // opener. - params.tabstrip_add_types = - TabStripModel::ADD_FORCE_INDEX | TabStripModel::ADD_INHERIT_OPENER; - browser::Navigate(¶ms); -} - -void Browser::Stop() { - UserMetrics::RecordAction(UserMetricsAction("Stop"), profile_); - GetSelectedTabContents()->Stop(); -} - -void Browser::NewWindow() { - if (browser_defaults::kAlwaysOpenIncognitoWindow && - CommandLine::ForCurrentProcess()->HasSwitch(switches::kIncognito)) { - NewIncognitoWindow(); - return; - } - UserMetrics::RecordAction(UserMetricsAction("NewWindow"), profile_); - SessionService* session_service = - profile_->GetOriginalProfile()->GetSessionService(); - if (!session_service || - !session_service->RestoreIfNecessary(std::vector())) { - Browser::OpenEmptyWindow(profile_->GetOriginalProfile()); - } -} - -void Browser::NewIncognitoWindow() { - UserMetrics::RecordAction(UserMetricsAction("NewIncognitoWindow"), profile_); - Browser::OpenEmptyWindow(profile_->GetOffTheRecordProfile()); -} - -void Browser::CloseWindow() { - UserMetrics::RecordAction(UserMetricsAction("CloseWindow"), profile_); - window_->Close(); -} - -void Browser::NewTab() { - UserMetrics::RecordAction(UserMetricsAction("NewTab"), profile_); - - if (type() == TYPE_NORMAL) { - AddBlankTab(true); - } else { - Browser* b = GetOrCreateTabbedBrowser(profile_); - b->AddBlankTab(true); - b->window()->Show(); - // The call to AddBlankTab above did not set the focus to the tab as its - // window was not active, so we have to do it explicitly. - // See http://crbug.com/6380. - b->GetSelectedTabContents()->view()->RestoreFocus(); - } -} - -void Browser::CloseTab() { - UserMetrics::RecordAction(UserMetricsAction("CloseTab_Accelerator"), - profile_); - if (CanCloseTab()) { - tab_handler_->GetTabStripModel()->CloseTabContentsAt( - tab_handler_->GetTabStripModel()->selected_index(), - TabStripModel::CLOSE_USER_GESTURE | - TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); - } -} - -void Browser::SelectNextTab() { - UserMetrics::RecordAction(UserMetricsAction("SelectNextTab"), profile_); - tab_handler_->GetTabStripModel()->SelectNextTab(); -} - -void Browser::SelectPreviousTab() { - UserMetrics::RecordAction(UserMetricsAction("SelectPrevTab"), profile_); - tab_handler_->GetTabStripModel()->SelectPreviousTab(); -} - -void Browser::OpenTabpose() { -#if defined(OS_MACOSX) - if (!CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableExposeForTabs)) { - return; - } - - UserMetrics::RecordAction(UserMetricsAction("OpenTabpose"), profile_); - window()->OpenTabpose(); -#else - NOTREACHED(); -#endif -} - -void Browser::MoveTabNext() { - UserMetrics::RecordAction(UserMetricsAction("MoveTabNext"), profile_); - tab_handler_->GetTabStripModel()->MoveTabNext(); -} - -void Browser::MoveTabPrevious() { - UserMetrics::RecordAction(UserMetricsAction("MoveTabPrevious"), profile_); - tab_handler_->GetTabStripModel()->MoveTabPrevious(); -} - -void Browser::SelectNumberedTab(int index) { - if (index < tab_count()) { - UserMetrics::RecordAction(UserMetricsAction("SelectNumberedTab"), - profile_); - tab_handler_->GetTabStripModel()->SelectTabContentsAt(index, true); - } -} - -void Browser::SelectLastTab() { - UserMetrics::RecordAction(UserMetricsAction("SelectLastTab"), profile_); - tab_handler_->GetTabStripModel()->SelectLastTab(); -} - -void Browser::DuplicateTab() { - UserMetrics::RecordAction(UserMetricsAction("Duplicate"), profile_); - DuplicateContentsAt(selected_index()); -} - -void Browser::RestoreTab() { - UserMetrics::RecordAction(UserMetricsAction("RestoreTab"), profile_); - TabRestoreService* service = profile_->GetTabRestoreService(); - if (!service) - return; - - service->RestoreMostRecentEntry(this); -} - -void Browser::WriteCurrentURLToClipboard() { - // TODO(ericu): There isn't currently a metric for this. Should there be? - // We don't appear to track the action when it comes from the - // RenderContextViewMenu. - - TabContents* contents = GetSelectedTabContents(); - if (!contents->ShouldDisplayURL()) - return; - - chrome_browser_net::WriteURLToClipboard( - contents->GetURL(), - profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), - g_browser_process->clipboard()); -} - -void Browser::ConvertPopupToTabbedBrowser() { - UserMetrics::RecordAction(UserMetricsAction("ShowAsTab"), profile_); - int tab_strip_index = tab_handler_->GetTabStripModel()->selected_index(); - TabContents* contents = - tab_handler_->GetTabStripModel()->DetachTabContentsAt(tab_strip_index); - Browser* browser = Browser::Create(profile_); - browser->tabstrip_model()->AppendTabContents(contents, true); - browser->window()->Show(); -} - -void Browser::ToggleFullscreenMode() { -#if !defined(OS_MACOSX) - // In kiosk mode, we always want to be fullscreen. When the browser first - // starts we're not yet fullscreen, so let the initial toggle go through. - if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode) && - window_->IsFullscreen()) - return; -#endif - - UserMetrics::RecordAction(UserMetricsAction("ToggleFullscreen"), profile_); - window_->SetFullscreen(!window_->IsFullscreen()); - // On Linux, setting fullscreen mode is an async call to the X server, which - // may or may not support fullscreen mode. -#if !defined(OS_LINUX) - UpdateCommandsForFullscreenMode(window_->IsFullscreen()); -#endif -} - -#if defined(OS_CHROMEOS) -void Browser::Search() { - // If the NTP is showing, close it. - if (StartsWithASCII(GetSelectedTabContents()->GetURL().spec(), - chrome::kChromeUINewTabURL, true)) { - CloseTab(); - return; - } - - // Exit fullscreen to show omnibox. - if (window_->IsFullscreen()) { - ToggleFullscreenMode(); - // ToggleFullscreenMode is asynchronous, so we don't have omnibox - // visible at this point. Wait for next event cycle which toggles - // the visibility of omnibox before creating new tab. - MessageLoop::current()->PostTask( - FROM_HERE, method_factory_.NewRunnableMethod(&Browser::Search)); - return; - } - - // Otherwise just open it. - NewTab(); -} -#endif - -void Browser::Exit() { - UserMetrics::RecordAction(UserMetricsAction("Exit"), profile_); -#if defined(OS_CHROMEOS) - if (chromeos::CrosLibrary::Get()->EnsureLoaded()) { - chromeos::CrosLibrary::Get()->GetLoginLibrary()->StopSession(""); - return; - } - // If running the Chrome OS build, but we're not on the device, fall through -#endif - BrowserList::CloseAllBrowsersAndExit(); -} - -void Browser::BookmarkCurrentPage() { - UserMetrics::RecordAction(UserMetricsAction("Star"), profile_); - - BookmarkModel* model = profile()->GetBookmarkModel(); - if (!model || !model->IsLoaded()) - return; // Ignore requests until bookmarks are loaded. - - GURL url; - string16 title; - bookmark_utils::GetURLAndTitleToBookmark(GetSelectedTabContents(), &url, - &title); - bool was_bookmarked = model->IsBookmarked(url); - model->SetURLStarred(url, title, true); - // Make sure the model actually added a bookmark before showing the star. A - // bookmark isn't created if the url is invalid. - if (window_->IsActive() && model->IsBookmarked(url)) { - // Only show the bubble if the window is active, otherwise we may get into - // weird situations were the bubble is deleted as soon as it is shown. - window_->ShowBookmarkBubble(url, was_bookmarked); - } -} - -void Browser::SavePage() { - UserMetrics::RecordAction(UserMetricsAction("SavePage"), profile_); - TabContents* current_tab = GetSelectedTabContents(); - if (current_tab && current_tab->contents_mime_type() == "application/pdf") - UserMetrics::RecordAction(UserMetricsAction("PDF.SavePage"), profile_); - GetSelectedTabContents()->OnSavePage(); -} - -void Browser::ViewSource() { - UserMetrics::RecordAction(UserMetricsAction("ViewSource"), profile_); - - TabContents* current_tab = GetSelectedTabContents(); - NavigationEntry* entry = current_tab->controller().GetLastCommittedEntry(); - if (entry) { - OpenURL(GURL(chrome::kViewSourceScheme + std::string(":") + - entry->url().spec()), GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); - } -} - -void Browser::ShowFindBar() { - GetFindBarController()->Show(); -} - -bool Browser::SupportsWindowFeature(WindowFeature feature) const { - return SupportsWindowFeatureImpl(feature, true); -} - -bool Browser::CanSupportWindowFeature(WindowFeature feature) const { - return SupportsWindowFeatureImpl(feature, false); -} - -void Browser::EmailPageLocation() { - UserMetrics::RecordAction(UserMetricsAction("EmailPageLocation"), profile_); - GetSelectedTabContents()->EmailPageLocation(); -} - -void Browser::Print() { - UserMetrics::RecordAction(UserMetricsAction("PrintPreview"), profile_); - GetSelectedTabContents()->PrintPreview(); -} - -void Browser::ToggleEncodingAutoDetect() { - UserMetrics::RecordAction(UserMetricsAction("AutoDetectChange"), profile_); - encoding_auto_detect_.SetValue(!encoding_auto_detect_.GetValue()); - // If "auto detect" is turned on, then any current override encoding - // is cleared. This also implicitly performs a reload. - // OTOH, if "auto detect" is turned off, we don't change the currently - // active encoding. - if (encoding_auto_detect_.GetValue()) { - TabContents* contents = GetSelectedTabContents(); - if (contents) - contents->ResetOverrideEncoding(); - } -} - -void Browser::OverrideEncoding(int encoding_id) { - UserMetrics::RecordAction(UserMetricsAction("OverrideEncoding"), profile_); - const std::string selected_encoding = - CharacterEncoding::GetCanonicalEncodingNameByCommandId(encoding_id); - TabContents* contents = GetSelectedTabContents(); - if (!selected_encoding.empty() && contents) - contents->SetOverrideEncoding(selected_encoding); - // Update the list of recently selected encodings. - std::string new_selected_encoding_list; - if (CharacterEncoding::UpdateRecentlySelectedEncoding( - profile_->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding), - encoding_id, - &new_selected_encoding_list)) { - profile_->GetPrefs()->SetString(prefs::kRecentlySelectedEncoding, - new_selected_encoding_list); - } -} - -void Browser::Cut() { - UserMetrics::RecordAction(UserMetricsAction("Cut"), profile_); - window()->Cut(); -} - -void Browser::Copy() { - UserMetrics::RecordAction(UserMetricsAction("Copy"), profile_); - window()->Copy(); -} - -void Browser::Paste() { - UserMetrics::RecordAction(UserMetricsAction("Paste"), profile_); - window()->Paste(); -} - -void Browser::Find() { - UserMetrics::RecordAction(UserMetricsAction("Find"), profile_); - FindInPage(false, false); -} - -void Browser::FindNext() { - UserMetrics::RecordAction(UserMetricsAction("FindNext"), profile_); - FindInPage(true, true); -} - -void Browser::FindPrevious() { - UserMetrics::RecordAction(UserMetricsAction("FindPrevious"), profile_); - FindInPage(true, false); -} - -void Browser::Zoom(PageZoom::Function zoom_function) { - static const UserMetricsAction kActions[] = { - UserMetricsAction("ZoomMinus"), - UserMetricsAction("ZoomNormal"), - UserMetricsAction("ZoomPlus") - }; - - UserMetrics::RecordAction(kActions[zoom_function - PageZoom::ZOOM_OUT], - profile_); - TabContents* tab_contents = GetSelectedTabContents(); - tab_contents->render_view_host()->Zoom(zoom_function); -} - -void Browser::FocusToolbar() { - UserMetrics::RecordAction(UserMetricsAction("FocusToolbar"), profile_); - window_->FocusToolbar(); -} - -void Browser::FocusAppMenu() { - UserMetrics::RecordAction(UserMetricsAction("FocusAppMenu"), profile_); - window_->FocusAppMenu(); -} - -void Browser::FocusLocationBar() { - UserMetrics::RecordAction(UserMetricsAction("FocusLocation"), profile_); - window_->SetFocusToLocationBar(true); -} - -void Browser::FocusBookmarksToolbar() { - UserMetrics::RecordAction(UserMetricsAction("FocusBookmarksToolbar"), - profile_); - window_->FocusBookmarksToolbar(); -} - -void Browser::FocusChromeOSStatus() { - UserMetrics::RecordAction(UserMetricsAction("FocusChromeOSStatus"), profile_); - window_->FocusChromeOSStatus(); -} - -void Browser::FocusNextPane() { - UserMetrics::RecordAction(UserMetricsAction("FocusNextPane"), profile_); - window_->RotatePaneFocus(true); -} - -void Browser::FocusPreviousPane() { - UserMetrics::RecordAction(UserMetricsAction("FocusPreviousPane"), profile_); - window_->RotatePaneFocus(false); -} - -void Browser::FocusSearch() { - // TODO(beng): replace this with FocusLocationBar - UserMetrics::RecordAction(UserMetricsAction("FocusSearch"), profile_); - window_->GetLocationBar()->FocusSearch(); -} - -void Browser::OpenFile() { - UserMetrics::RecordAction(UserMetricsAction("OpenFile"), profile_); -#if defined(OS_CHROMEOS) - FileBrowseUI::OpenPopup(profile_, - "", - FileBrowseUI::kPopupWidth, - FileBrowseUI::kPopupHeight); -#else - if (!select_file_dialog_.get()) - select_file_dialog_ = SelectFileDialog::Create(this); - - const FilePath directory = profile_->last_selected_directory(); - - // TODO(beng): figure out how to juggle this. - gfx::NativeWindow parent_window = window_->GetNativeHandle(); - select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE, - string16(), directory, - NULL, 0, FILE_PATH_LITERAL(""), - parent_window, NULL); -#endif -} - -void Browser::OpenCreateShortcutsDialog() { - UserMetrics::RecordAction(UserMetricsAction("CreateShortcut"), profile_); -#if defined(OS_WIN) || defined(OS_LINUX) - TabContents* current_tab = GetSelectedTabContents(); - DCHECK(current_tab && web_app::IsValidUrl(current_tab->GetURL())) << - "Menu item should be disabled."; - - NavigationEntry* entry = current_tab->controller().GetLastCommittedEntry(); - if (!entry) - return; - - // RVH's GetApplicationInfo should not be called before it returns. - DCHECK(pending_web_app_action_ == NONE); - pending_web_app_action_ = CREATE_SHORTCUT; - - // Start fetching web app info for CreateApplicationShortcut dialog and show - // the dialog when the data is available in OnDidGetApplicationInfo. - current_tab->render_view_host()->GetApplicationInfo(entry->page_id()); -#else - NOTIMPLEMENTED(); -#endif -} - -void Browser::ToggleDevToolsWindow(DevToolsToggleAction action) { - std::string uma_string; - switch (action) { - case DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE: - uma_string = "DevTools_ToggleConsole"; - break; - case DEVTOOLS_TOGGLE_ACTION_NONE: - case DEVTOOLS_TOGGLE_ACTION_INSPECT: - default: - uma_string = "DevTools_ToggleWindow"; - break; - } - UserMetrics::RecordAction(UserMetricsAction(uma_string.c_str()), profile_); - DevToolsManager::GetInstance()->ToggleDevToolsWindow( - GetSelectedTabContents()->render_view_host(), action); -} - -void Browser::OpenTaskManager() { - UserMetrics::RecordAction(UserMetricsAction("TaskManager"), profile_); - window_->ShowTaskManager(); -} - -void Browser::OpenBugReportDialog() { - UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_); - window_->ShowReportBugDialog(); -} - -void Browser::ToggleBookmarkBar() { - UserMetrics::RecordAction(UserMetricsAction("ShowBookmarksBar"), profile_); - window_->ToggleBookmarkBar(); -} - -void Browser::OpenBookmarkManager() { - UserMetrics::RecordAction(UserMetricsAction("ShowBookmarkManager"), profile_); - ShowBookmarkManagerTab(); -} - -void Browser::ShowAppMenu() { - UserMetrics::RecordAction(UserMetricsAction("ShowAppMenu"), profile_); - window_->ShowAppMenu(); -} - -void Browser::ShowBookmarkManagerTab() { - UserMetrics::RecordAction(UserMetricsAction("ShowBookmarks"), profile_); - ShowSingletonTab(GURL(chrome::kChromeUIBookmarksURL)); -} - -void Browser::ShowHistoryTab() { - UserMetrics::RecordAction(UserMetricsAction("ShowHistory"), profile_); - ShowSingletonTab(GURL(chrome::kChromeUIHistoryURL)); -} - -void Browser::ShowDownloadsTab() { - UserMetrics::RecordAction(UserMetricsAction("ShowDownloads"), profile_); - ShowSingletonTab(GURL(chrome::kChromeUIDownloadsURL)); -} - -void Browser::ShowExtensionsTab() { - UserMetrics::RecordAction(UserMetricsAction("ShowExtensions"), profile_); - ShowSingletonTab(GURL(chrome::kChromeUIExtensionsURL)); -} - -void Browser::ShowAboutConflictsTab() { - UserMetrics::RecordAction(UserMetricsAction("AboutConflicts"), profile_); - ShowSingletonTab(GURL(chrome::kChromeUIConflictsURL)); -} - -void Browser::ShowBrokenPageTab(TabContents* contents) { - UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_); - string16 page_title = contents->GetTitle(); - NavigationEntry* entry = contents->controller().GetActiveEntry(); - if (!entry) - return; - std::string page_url = entry->url().spec(); - std::vector subst; - subst.push_back(UTF16ToASCII(page_title)); - subst.push_back(page_url); - std::string report_page_url = - ReplaceStringPlaceholders(kBrokenPageUrl, subst, NULL); - ShowSingletonTab(GURL(report_page_url)); -} - -void Browser::ShowOptionsTab(const std::string& sub_page) { - GURL url(chrome::kChromeUISettingsURL + sub_page); - - // See if there is already an options tab open that we can use. - TabStripModel* model = tab_handler_->GetTabStripModel(); - for (int i = 0; i < model->count(); i++) { - TabContents* tc = model->GetTabContentsAt(i); - const GURL& tab_url = tc->GetURL(); - - if (tab_url.scheme() == url.scheme() && tab_url.host() == url.host()) { - // We found an existing options tab, load the URL in this tab. (Note: - // this may cause us to unnecessarily reload the same page. We can't - // really detect that unless the options page is permitted to change the - // URL in the address bar, but security policy doesn't allow that. - browser::NavigateParams params(this, url, PageTransition::GENERATED); - params.source_contents = tc; - browser::Navigate(¶ms); - model->SelectTabContentsAt(i, false); - return; - } - } - - // No options tab found, so create a new one. - AddSelectedTabWithURL(url, PageTransition::AUTO_BOOKMARK); -} - -void Browser::OpenClearBrowsingDataDialog() { - UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_ShowDlg"), - profile_); - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableTabbedOptions)) { - ShowOptionsTab( - chrome::kAdvancedOptionsSubPage + kHashMark + - chrome::kClearBrowserDataSubPage); - } else { - window_->ShowClearBrowsingDataDialog(); - } -} - -void Browser::OpenOptionsDialog() { - UserMetrics::RecordAction(UserMetricsAction("ShowOptions"), profile_); - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableTabbedOptions)) { - ShowOptionsTab(chrome::kDefaultOptionsSubPage); - } else { - ShowOptionsWindow(OPTIONS_PAGE_DEFAULT, OPTIONS_GROUP_NONE, profile_); - } -} - -void Browser::OpenKeywordEditor() { - UserMetrics::RecordAction(UserMetricsAction("EditSearchEngines"), profile_); - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableTabbedOptions)) { - ShowOptionsTab(chrome::kSearchEnginesSubPage); - } else { - window_->ShowSearchEnginesDialog(); - } -} - -void Browser::OpenPasswordManager() { - window_->ShowPasswordManager(); -} - -void Browser::OpenImportSettingsDialog() { - UserMetrics::RecordAction(UserMetricsAction("Import_ShowDlg"), profile_); - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableTabbedOptions)) { - ShowOptionsTab( - chrome::kPersonalOptionsSubPage + kHashMark + - chrome::kImportDataSubPage); - } else { - window_->ShowImportDialog(); - } -} - -void Browser::OpenSyncMyBookmarksDialog() { - sync_ui_util::OpenSyncMyBookmarksDialog( - profile_, ProfileSyncService::START_FROM_WRENCH); -} - -#if defined(ENABLE_REMOTING) -void Browser::OpenRemotingSetupDialog() { - RemotingSetupFlow::OpenDialog(profile_); -} -#endif - -void Browser::OpenAboutChromeDialog() { - UserMetrics::RecordAction(UserMetricsAction("AboutChrome"), profile_); -#if defined(OS_CHROMEOS) - ShowSingletonTab(GURL(chrome::kChromeUIAboutURL)); -#else - window_->ShowAboutChromeDialog(); -#endif -} - -void Browser::OpenUpdateChromeDialog() { - UserMetrics::RecordAction(UserMetricsAction("UpdateChrome"), profile_); - window_->ShowUpdateChromeDialog(); -} - -void Browser::OpenHelpTab() { - GURL help_url = google_util::AppendGoogleLocaleParam(GURL(kHelpContentUrl)); - AddSelectedTabWithURL(help_url, PageTransition::AUTO_BOOKMARK); -} - -void Browser::OpenThemeGalleryTabAndActivate() { - AddSelectedTabWithURL(GURL(l10n_util::GetStringUTF8(IDS_THEMES_GALLERY_URL)), - PageTransition::LINK); -} - -void Browser::OpenPrivacyDashboardTabAndActivate() { - OpenURL(GURL(kPrivacyDashboardUrl), GURL(), - NEW_FOREGROUND_TAB, PageTransition::LINK); - window_->Activate(); -} - -void Browser::OpenAutoFillHelpTabAndActivate() { - AddSelectedTabWithURL(GURL(l10n_util::GetStringUTF8(IDS_AUTOFILL_HELP_URL)), - PageTransition::LINK); -} - -void Browser::OpenSearchEngineOptionsDialog() { - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableTabbedOptions)) { - OpenKeywordEditor(); - } else { - ShowOptionsWindow(OPTIONS_PAGE_GENERAL, OPTIONS_GROUP_DEFAULT_SEARCH, - profile_); - } -} - -#if defined(OS_CHROMEOS) -void Browser::OpenSystemOptionsDialog() { - UserMetrics::RecordAction(UserMetricsAction("OpenSystemOptionsDialog"), - profile_); - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableTabbedOptions)) { - ShowOptionsTab(chrome::kSystemOptionsSubPage); - } else { - ShowOptionsWindow(OPTIONS_PAGE_SYSTEM, OPTIONS_GROUP_NONE, - profile_); - } -} - -void Browser::OpenInternetOptionsDialog() { - UserMetrics::RecordAction(UserMetricsAction("OpenInternetOptionsDialog"), - profile_); - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableTabbedOptions)) { - ShowOptionsTab(chrome::kInternetOptionsSubPage); - } else { - ShowOptionsWindow(OPTIONS_PAGE_INTERNET, OPTIONS_GROUP_DEFAULT_SEARCH, - profile_); - } -} - -void Browser::OpenLanguageOptionsDialog() { - UserMetrics::RecordAction(UserMetricsAction("OpenLanguageOptionsDialog"), - profile_); - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableTabbedOptions)) { - ShowOptionsTab(chrome::kLanguageOptionsSubPage); - } else { - chromeos::LanguageConfigView::Show(profile_, NULL); - } -} - -void Browser::OpenSystemTabAndActivate() { - OpenURL(GURL(chrome::kChromeUISystemInfoURL), GURL(), - NEW_FOREGROUND_TAB, PageTransition::LINK); - window_->Activate(); -} - -void Browser::OpenMobilePlanTabAndActivate() { - OpenURL(GURL(chrome::kChromeUIMobileSetupURL), GURL(), - NEW_FOREGROUND_TAB, PageTransition::LINK); - window_->Activate(); -} -#endif - -void Browser::OpenPluginsTabAndActivate() { - OpenURL(GURL(chrome::kAboutPluginsURL), GURL(), - NEW_FOREGROUND_TAB, PageTransition::LINK); - window_->Activate(); -} - -/////////////////////////////////////////////////////////////////////////////// - -// static -void Browser::SetNewHomePagePrefs(PrefService* prefs) { - const PrefService::Preference* home_page_pref = - prefs->FindPreference(prefs::kHomePage); - if (home_page_pref && - !home_page_pref->IsManaged() && - !prefs->HasPrefPath(prefs::kHomePage)) { - prefs->SetString(prefs::kHomePage, - GoogleURLTracker::kDefaultGoogleHomepage); - } - const PrefService::Preference* home_page_is_new_tab_page_pref = - prefs->FindPreference(prefs::kHomePageIsNewTabPage); - if (home_page_is_new_tab_page_pref && - !home_page_is_new_tab_page_pref->IsManaged() && - !prefs->HasPrefPath(prefs::kHomePageIsNewTabPage)) - prefs->SetBoolean(prefs::kHomePageIsNewTabPage, false); -} - -// static -void Browser::RegisterPrefs(PrefService* prefs) { - prefs->RegisterDictionaryPref(prefs::kBrowserWindowPlacement); - prefs->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex, 0); - prefs->RegisterIntegerPref(prefs::kDevToolsSplitLocation, -1); - prefs->RegisterDictionaryPref(prefs::kPreferencesWindowPlacement); - prefs->RegisterIntegerPref(prefs::kExtensionSidebarWidth, -1); -} - -// static -void Browser::RegisterUserPrefs(PrefService* prefs) { - prefs->RegisterStringPref(prefs::kHomePage, - chrome::kChromeUINewTabURL); - prefs->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true); - prefs->RegisterBooleanPref(prefs::kClearSiteDataOnExit, false); - prefs->RegisterBooleanPref(prefs::kShowHomeButton, false); -#if defined(OS_MACOSX) - // This really belongs in platform code, but there's no good place to - // initialize it between the time when the AppController is created - // (where there's no profile) and the time the controller gets another - // crack at the start of the main event loop. By that time, BrowserInit - // has already created the browser window, and it's too late: we need the - // pref to be already initialized. Doing it here also saves us from having - // to hard-code pref registration in the several unit tests that use - // this preference. - prefs->RegisterBooleanPref(prefs::kShowPageOptionsButtons, false); - prefs->RegisterBooleanPref(prefs::kShowUpdatePromotionInfoBar, true); -#endif - prefs->RegisterStringPref(prefs::kRecentlySelectedEncoding, ""); - prefs->RegisterBooleanPref(prefs::kDeleteBrowsingHistory, true); - prefs->RegisterBooleanPref(prefs::kDeleteDownloadHistory, true); - prefs->RegisterBooleanPref(prefs::kDeleteCache, true); - prefs->RegisterBooleanPref(prefs::kDeleteCookies, true); - prefs->RegisterBooleanPref(prefs::kDeletePasswords, false); - prefs->RegisterBooleanPref(prefs::kDeleteFormData, false); - prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0); - prefs->RegisterBooleanPref(prefs::kCheckDefaultBrowser, true); - prefs->RegisterBooleanPref(prefs::kShowOmniboxSearchHint, true); - prefs->RegisterBooleanPref(prefs::kWebAppCreateOnDesktop, true); - prefs->RegisterBooleanPref(prefs::kWebAppCreateInAppsMenu, true); - prefs->RegisterBooleanPref(prefs::kWebAppCreateInQuickLaunchBar, true); - prefs->RegisterBooleanPref(prefs::kUseVerticalTabs, false); - prefs->RegisterBooleanPref(prefs::kEnableTranslate, true); - prefs->RegisterBooleanPref(prefs::kRemotingHasSetupCompleted, false); - prefs->RegisterStringPref(prefs::kCloudPrintEmail, std::string()); - prefs->RegisterBooleanPref(prefs::kDevToolsDisabled, false); - prefs->RegisterRealPref(prefs::kDefaultZoomLevel, 0.0); -} - -// static -bool Browser::RunUnloadEventsHelper(TabContents* contents) { - // If the TabContents is not connected yet, then there's no unload - // handler we can fire even if the TabContents has an unload listener. - // One case where we hit this is in a tab that has an infinite loop - // before load. - if (TabHasUnloadListener(contents)) { - // If the page has unload listeners, then we tell the renderer to fire - // them. Once they have fired, we'll get a message back saying whether - // to proceed closing the page or not, which sends us back to this method - // with the HasUnloadListener bit cleared. - contents->render_view_host()->FirePageBeforeUnload(false); - return true; - } - return false; -} - -// static -Browser* Browser::GetBrowserForController( - const NavigationController* controller, int* index_result) { - BrowserList::const_iterator it; - for (it = BrowserList::begin(); it != BrowserList::end(); ++it) { - int index = (*it)->tab_handler_->GetTabStripModel()->GetIndexOfController( - controller); - if (index != TabStripModel::kNoTab) { - if (index_result) - *index_result = index; - return *it; - } - } - - return NULL; -} - -void Browser::ExecuteCommandWithDisposition( - int id, WindowOpenDisposition disposition) { - // No commands are enabled if there is not yet any selected tab. - // TODO(pkasting): It seems like we should not need this, because either - // most/all commands should not have been enabled yet anyway or the ones that - // are enabled should be global, or safe themselves against having no selected - // tab. However, Ben says he tried removing this before and got lots of - // crashes, e.g. from Windows sending WM_COMMANDs at random times during - // window construction. This probably could use closer examination someday. - if (!GetSelectedTabContents()) - return; - - DCHECK(command_updater_.IsCommandEnabled(id)) << "Invalid/disabled command"; - - // If command execution is blocked then just record the command and return. - if (block_command_execution_) { - // We actually only allow no more than one blocked command, otherwise some - // commands maybe lost. - DCHECK_EQ(last_blocked_command_id_, -1); - last_blocked_command_id_ = id; - last_blocked_command_disposition_ = disposition; - return; - } - - // The order of commands in this switch statement must match the function - // declaration order in browser.h! - switch (id) { - // Navigation commands - case IDC_BACK: GoBack(disposition); break; - case IDC_FORWARD: GoForward(disposition); break; - case IDC_RELOAD: Reload(disposition); break; - case IDC_RELOAD_IGNORING_CACHE: ReloadIgnoringCache(disposition); break; - case IDC_HOME: Home(disposition); break; - case IDC_OPEN_CURRENT_URL: OpenCurrentURL(); break; - case IDC_STOP: Stop(); break; - - // Window management commands - case IDC_NEW_WINDOW: NewWindow(); break; - case IDC_NEW_INCOGNITO_WINDOW: NewIncognitoWindow(); break; - case IDC_CLOSE_WINDOW: CloseWindow(); break; - case IDC_NEW_TAB: NewTab(); break; - case IDC_CLOSE_TAB: CloseTab(); break; - case IDC_SELECT_NEXT_TAB: SelectNextTab(); break; - case IDC_SELECT_PREVIOUS_TAB: SelectPreviousTab(); break; - case IDC_TABPOSE: OpenTabpose(); break; - case IDC_MOVE_TAB_NEXT: MoveTabNext(); break; - case IDC_MOVE_TAB_PREVIOUS: MoveTabPrevious(); break; - case IDC_SELECT_TAB_0: - case IDC_SELECT_TAB_1: - case IDC_SELECT_TAB_2: - case IDC_SELECT_TAB_3: - case IDC_SELECT_TAB_4: - case IDC_SELECT_TAB_5: - case IDC_SELECT_TAB_6: - case IDC_SELECT_TAB_7: SelectNumberedTab(id - IDC_SELECT_TAB_0); - break; - case IDC_SELECT_LAST_TAB: SelectLastTab(); break; - case IDC_DUPLICATE_TAB: DuplicateTab(); break; - case IDC_RESTORE_TAB: RestoreTab(); break; - case IDC_COPY_URL: WriteCurrentURLToClipboard(); break; - case IDC_SHOW_AS_TAB: ConvertPopupToTabbedBrowser(); break; - case IDC_FULLSCREEN: ToggleFullscreenMode(); break; - case IDC_EXIT: Exit(); break; - case IDC_TOGGLE_VERTICAL_TABS: ToggleUseVerticalTabs(); break; -#if defined(OS_CHROMEOS) - case IDC_SEARCH: Search(); break; -#endif - - // Page-related commands - case IDC_SAVE_PAGE: SavePage(); break; - case IDC_BOOKMARK_PAGE: BookmarkCurrentPage(); break; - case IDC_BOOKMARK_ALL_TABS: BookmarkAllTabs(); break; - case IDC_VIEW_SOURCE: ViewSource(); break; - case IDC_EMAIL_PAGE_LOCATION: EmailPageLocation(); break; - case IDC_PRINT: Print(); break; - case IDC_ENCODING_AUTO_DETECT: ToggleEncodingAutoDetect(); break; - case IDC_ENCODING_UTF8: - case IDC_ENCODING_UTF16LE: - case IDC_ENCODING_ISO88591: - case IDC_ENCODING_WINDOWS1252: - case IDC_ENCODING_GBK: - case IDC_ENCODING_GB18030: - case IDC_ENCODING_BIG5HKSCS: - case IDC_ENCODING_BIG5: - case IDC_ENCODING_KOREAN: - case IDC_ENCODING_SHIFTJIS: - case IDC_ENCODING_ISO2022JP: - case IDC_ENCODING_EUCJP: - case IDC_ENCODING_THAI: - case IDC_ENCODING_ISO885915: - case IDC_ENCODING_MACINTOSH: - case IDC_ENCODING_ISO88592: - case IDC_ENCODING_WINDOWS1250: - case IDC_ENCODING_ISO88595: - case IDC_ENCODING_WINDOWS1251: - case IDC_ENCODING_KOI8R: - case IDC_ENCODING_KOI8U: - case IDC_ENCODING_ISO88597: - case IDC_ENCODING_WINDOWS1253: - case IDC_ENCODING_ISO88594: - case IDC_ENCODING_ISO885913: - case IDC_ENCODING_WINDOWS1257: - case IDC_ENCODING_ISO88593: - case IDC_ENCODING_ISO885910: - case IDC_ENCODING_ISO885914: - case IDC_ENCODING_ISO885916: - case IDC_ENCODING_WINDOWS1254: - case IDC_ENCODING_ISO88596: - case IDC_ENCODING_WINDOWS1256: - case IDC_ENCODING_ISO88598: - case IDC_ENCODING_ISO88598I: - case IDC_ENCODING_WINDOWS1255: - case IDC_ENCODING_WINDOWS1258: OverrideEncoding(id); break; - - // Clipboard commands - case IDC_CUT: Cut(); break; - case IDC_COPY: Copy(); break; - case IDC_PASTE: Paste(); break; - - // Find-in-page - case IDC_FIND: Find(); break; - case IDC_FIND_NEXT: FindNext(); break; - case IDC_FIND_PREVIOUS: FindPrevious(); break; - - // Zoom - case IDC_ZOOM_PLUS: Zoom(PageZoom::ZOOM_IN); break; - case IDC_ZOOM_NORMAL: Zoom(PageZoom::RESET); break; - case IDC_ZOOM_MINUS: Zoom(PageZoom::ZOOM_OUT); break; - - // Focus various bits of UI - case IDC_FOCUS_TOOLBAR: FocusToolbar(); break; - case IDC_FOCUS_LOCATION: FocusLocationBar(); break; - case IDC_FOCUS_SEARCH: FocusSearch(); break; - case IDC_FOCUS_MENU_BAR: FocusAppMenu(); break; - case IDC_FOCUS_BOOKMARKS: FocusBookmarksToolbar(); break; - case IDC_FOCUS_CHROMEOS_STATUS: FocusChromeOSStatus(); break; - case IDC_FOCUS_NEXT_PANE: FocusNextPane(); break; - case IDC_FOCUS_PREVIOUS_PANE: FocusPreviousPane(); break; - - // Show various bits of UI - case IDC_OPEN_FILE: OpenFile(); break; - case IDC_CREATE_SHORTCUTS: OpenCreateShortcutsDialog(); break; - case IDC_DEV_TOOLS: ToggleDevToolsWindow( - DEVTOOLS_TOGGLE_ACTION_NONE); - break; - case IDC_DEV_TOOLS_CONSOLE: ToggleDevToolsWindow( - DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE); - break; - case IDC_DEV_TOOLS_INSPECT: ToggleDevToolsWindow( - DEVTOOLS_TOGGLE_ACTION_INSPECT); - break; - case IDC_TASK_MANAGER: OpenTaskManager(); break; - case IDC_REPORT_BUG: OpenBugReportDialog(); break; - - case IDC_SHOW_BOOKMARK_BAR: ToggleBookmarkBar(); break; - - case IDC_SHOW_BOOKMARK_MANAGER: OpenBookmarkManager(); break; - case IDC_SHOW_APP_MENU: ShowAppMenu(); break; - case IDC_SHOW_HISTORY: ShowHistoryTab(); break; - case IDC_SHOW_DOWNLOADS: ShowDownloadsTab(); break; - case IDC_MANAGE_EXTENSIONS: ShowExtensionsTab(); break; - case IDC_SYNC_BOOKMARKS: OpenSyncMyBookmarksDialog(); break; -#if defined(ENABLE_REMOTING) - case IDC_REMOTING_SETUP: OpenRemotingSetupDialog(); break; -#endif - case IDC_OPTIONS: OpenOptionsDialog(); break; - case IDC_EDIT_SEARCH_ENGINES: OpenKeywordEditor(); break; - case IDC_VIEW_PASSWORDS: OpenPasswordManager(); break; - case IDC_CLEAR_BROWSING_DATA: OpenClearBrowsingDataDialog(); break; - case IDC_IMPORT_SETTINGS: OpenImportSettingsDialog(); break; - case IDC_ABOUT: OpenAboutChromeDialog(); break; - case IDC_UPGRADE_DIALOG: OpenUpdateChromeDialog(); break; - case IDC_VIEW_INCOMPATIBILITIES: ShowAboutConflictsTab(); break; - case IDC_HELP_PAGE: OpenHelpTab(); break; -#if defined(OS_CHROMEOS) - case IDC_SYSTEM_OPTIONS: OpenSystemOptionsDialog(); break; - case IDC_INTERNET_OPTIONS: OpenInternetOptionsDialog(); break; - case IDC_LANGUAGE_OPTIONS: OpenLanguageOptionsDialog(); break; -#endif - - default: - LOG(WARNING) << "Received Unimplemented Command: " << id; - break; - } -} - -bool Browser::IsReservedCommand(int command_id) { - return command_id == IDC_CLOSE_TAB || - command_id == IDC_CLOSE_WINDOW || - command_id == IDC_NEW_INCOGNITO_WINDOW || - command_id == IDC_NEW_TAB || - command_id == IDC_NEW_WINDOW || - command_id == IDC_RESTORE_TAB || - command_id == IDC_SELECT_NEXT_TAB || - command_id == IDC_SELECT_PREVIOUS_TAB || - command_id == IDC_TABPOSE || - command_id == IDC_EXIT || - command_id == IDC_SEARCH; -} - -void Browser::SetBlockCommandExecution(bool block) { - block_command_execution_ = block; - if (block) { - last_blocked_command_id_ = -1; - last_blocked_command_disposition_ = CURRENT_TAB; - } -} - -int Browser::GetLastBlockedCommand(WindowOpenDisposition* disposition) { - if (disposition) - *disposition = last_blocked_command_disposition_; - return last_blocked_command_id_; -} - -void Browser::UpdateUIForNavigationInTab(TabContents* contents, - PageTransition::Type transition, - bool user_initiated) { - tabstrip_model()->TabNavigating(contents, transition); - - bool contents_is_selected = contents == GetSelectedTabContents(); - if (user_initiated && contents_is_selected && window()->GetLocationBar()) { - // Forcibly reset the location bar if the url is going to change in the - // current tab, since otherwise it won't discard any ongoing user edits, - // since it doesn't realize this is a user-initiated action. - window()->GetLocationBar()->Revert(); - } - - if (GetStatusBubble()) - GetStatusBubble()->Hide(); - - // Update the location bar. This is synchronous. We specifically don't - // update the load state since the load hasn't started yet and updating it - // will put it out of sync with the actual state like whether we're - // displaying a favicon, which controls the throbber. If we updated it here, - // the throbber will show the default favicon for a split second when - // navigating away from the new tab page. - ScheduleUIUpdate(contents, TabContents::INVALIDATE_URL); - - if (contents_is_selected) - contents->Focus(); -} - -GURL Browser::GetHomePage() const { - // --homepage overrides any preferences. - const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - if (command_line.HasSwitch(switches::kHomePage)) { - // TODO(evanm): clean up usage of DIR_CURRENT. - // http://code.google.com/p/chromium/issues/detail?id=60630 - // For now, allow this code to call getcwd(). - base::ThreadRestrictions::ScopedAllowIO allow_io; - - FilePath browser_directory; - PathService::Get(base::DIR_CURRENT, &browser_directory); - GURL home_page(URLFixerUpper::FixupRelativeFile(browser_directory, - command_line.GetSwitchValuePath(switches::kHomePage))); - if (home_page.is_valid()) - return home_page; - } - - if (profile_->GetPrefs()->GetBoolean(prefs::kHomePageIsNewTabPage)) - return GURL(chrome::kChromeUINewTabURL); - GURL home_page(URLFixerUpper::FixupURL( - profile_->GetPrefs()->GetString(prefs::kHomePage), - std::string())); - if (!home_page.is_valid()) - return GURL(chrome::kChromeUINewTabURL); - return home_page; -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, PageNavigator implementation: - -void Browser::OpenURL(const GURL& url, const GURL& referrer, - WindowOpenDisposition disposition, - PageTransition::Type transition) { - OpenURLFromTab(NULL, url, referrer, disposition, transition); -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, CommandUpdater::CommandUpdaterDelegate implementation: - -void Browser::ExecuteCommand(int id) { - ExecuteCommandWithDisposition(id, CURRENT_TAB); -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, TabHandlerDelegate implementation: - -Profile* Browser::GetProfile() const { - return profile(); -} - -Browser* Browser::AsBrowser() { - return this; -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, TabStripModelDelegate implementation: - -TabContents* Browser::AddBlankTab(bool foreground) { - return AddBlankTabAt(-1, foreground); -} - -TabContents* Browser::AddBlankTabAt(int index, bool foreground) { - // Time new tab page creation time. We keep track of the timing data in - // TabContents, but we want to include the time it takes to create the - // TabContents object too. - base::TimeTicks new_tab_start_time = base::TimeTicks::Now(); - browser::NavigateParams params(this, GURL(chrome::kChromeUINewTabURL), - PageTransition::TYPED); - params.tabstrip_add_types = - foreground ? TabStripModel::ADD_SELECTED : TabStripModel::ADD_NONE; - params.disposition = foreground ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB; - params.tabstrip_index = index; - browser::Navigate(¶ms); - params.target_contents->set_new_tab_start_time(new_tab_start_time); - return params.target_contents; -} - -Browser* Browser::CreateNewStripWithContents(TabContents* detached_contents, - const gfx::Rect& window_bounds, - const DockInfo& dock_info, - bool maximize) { - DCHECK(CanSupportWindowFeature(FEATURE_TABSTRIP)); - - gfx::Rect new_window_bounds = window_bounds; - if (dock_info.GetNewWindowBounds(&new_window_bounds, &maximize)) - dock_info.AdjustOtherWindowBounds(); - - // Create an empty new browser window the same size as the old one. - Browser* browser = new Browser(TYPE_NORMAL, profile_); - browser->set_override_bounds(new_window_bounds); - browser->set_maximized_state( - maximize ? MAXIMIZED_STATE_MAXIMIZED : MAXIMIZED_STATE_UNMAXIMIZED); - browser->CreateBrowserWindow(); - browser->tabstrip_model()->AppendTabContents(detached_contents, true); - // Make sure the loading state is updated correctly, otherwise the throbber - // won't start if the page is loading. - browser->LoadingStateChanged(detached_contents); - return browser; -} - -void Browser::ContinueDraggingDetachedTab(TabContents* contents, - const gfx::Rect& window_bounds, - const gfx::Rect& tab_bounds) { - Browser* browser = new Browser(TYPE_NORMAL, profile_); - browser->set_override_bounds(window_bounds); - browser->CreateBrowserWindow(); - browser->tabstrip_model()->AppendTabContents(contents, true); - browser->LoadingStateChanged(contents); - browser->window()->Show(); - browser->window()->ContinueDraggingDetachedTab(tab_bounds); -} - -int Browser::GetDragActions() const { - return TabStripModelDelegate::TAB_TEAROFF_ACTION | (tab_count() > 1 ? - TabStripModelDelegate::TAB_MOVE_ACTION : 0); -} - -TabContents* Browser::CreateTabContentsForURL( - const GURL& url, const GURL& referrer, Profile* profile, - PageTransition::Type transition, bool defer_load, - SiteInstance* instance) const { - TabContents* contents = new TabContents(profile, instance, - MSG_ROUTING_NONE, - tab_handler_->GetTabStripModel()->GetSelectedTabContents(), NULL); - - if (!defer_load) { - // Load the initial URL before adding the new tab contents to the tab strip - // so that the tab contents has navigation state. - contents->controller().LoadURL(url, referrer, transition); - } - - return contents; -} - -bool Browser::CanDuplicateContentsAt(int index) { - NavigationController& nc = GetTabContentsAt(index)->controller(); - return nc.tab_contents() && nc.GetLastCommittedEntry(); -} - -void Browser::DuplicateContentsAt(int index) { - TabContents* contents = GetTabContentsAt(index); - TabContents* new_contents = NULL; - DCHECK(contents); - bool pinned = false; - - if (CanSupportWindowFeature(FEATURE_TABSTRIP)) { - // If this is a tabbed browser, just create a duplicate tab inside the same - // window next to the tab being duplicated. - new_contents = contents->Clone(); - pinned = tab_handler_->GetTabStripModel()->IsTabPinned(index); - int add_types = TabStripModel::ADD_SELECTED | - TabStripModel::ADD_INHERIT_GROUP | - (pinned ? TabStripModel::ADD_PINNED : 0); - tab_handler_->GetTabStripModel()->InsertTabContentsAt(index + 1, - new_contents, - add_types); - } else { - Browser* browser = NULL; - if (type_ & TYPE_APP) { - DCHECK((type_ & TYPE_POPUP) == 0); - DCHECK(type_ != TYPE_APP_PANEL); - browser = Browser::CreateForApp(app_name_, extension_app_, profile_, - false); - } else if (type_ == TYPE_POPUP) { - browser = Browser::CreateForType(TYPE_POPUP, profile_); - } - - // Preserve the size of the original window. The new window has already - // been given an offset by the OS, so we shouldn't copy the old bounds. - BrowserWindow* new_window = browser->window(); - new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(), - window()->GetRestoredBounds().size())); - - // We need to show the browser now. Otherwise ContainerWin assumes the - // TabContents is invisible and won't size it. - browser->window()->Show(); - - // The page transition below is only for the purpose of inserting the tab. - new_contents = browser->AddTab( - contents->Clone()->controller().tab_contents(), - PageTransition::LINK); - } - - if (profile_->HasSessionService()) { - SessionService* session_service = profile_->GetSessionService(); - if (session_service) - session_service->TabRestored(&new_contents->controller(), pinned); - } -} - -void Browser::CloseFrameAfterDragSession() { -#if defined(OS_WIN) || defined(OS_LINUX) - // This is scheduled to run after we return to the message loop because - // otherwise the frame will think the drag session is still active and ignore - // the request. - // TODO(port): figure out what is required here in a cross-platform world - MessageLoop::current()->PostTask( - FROM_HERE, method_factory_.NewRunnableMethod(&Browser::CloseFrame)); -#endif -} - -void Browser::CreateHistoricalTab(TabContents* contents) { - // We don't create historical tabs for incognito windows or windows without - // profiles. - if (!profile() || profile()->IsOffTheRecord() || - !profile()->GetTabRestoreService()) { - return; - } - - // We only create historical tab entries for tabbed browser windows. - if (CanSupportWindowFeature(FEATURE_TABSTRIP)) { - profile()->GetTabRestoreService()->CreateHistoricalTab( - &contents->controller()); - } -} - -bool Browser::RunUnloadListenerBeforeClosing(TabContents* contents) { - return Browser::RunUnloadEventsHelper(contents); -} - -bool Browser::CanReloadContents(TabContents* source) const { - return type() != TYPE_DEVTOOLS; -} - -bool Browser::CanCloseContentsAt(int index) { - if (!CanCloseTab()) - return false; - if (tab_handler_->GetTabStripModel()->count() > 1) - return true; - // We are closing the last tab for this browser. Make sure to check for - // in-progress downloads. - // Note that the next call when it returns false will ask the user for - // confirmation before closing the browser if the user decides so. - return CanCloseWithInProgressDownloads(); -} - -bool Browser::CanBookmarkAllTabs() const { - BookmarkModel* model = profile()->GetBookmarkModel(); - return (model && model->IsLoaded() && (tab_count() > 1)); -} - -void Browser::BookmarkAllTabs() { - BookmarkModel* model = profile()->GetBookmarkModel(); - DCHECK(model && model->IsLoaded()); - - BookmarkEditor::EditDetails details; - details.type = BookmarkEditor::EditDetails::NEW_FOLDER; - bookmark_utils::GetURLsForOpenTabs(this, &(details.urls)); - DCHECK(!details.urls.empty()); - - BookmarkEditor::Show(window()->GetNativeHandle(), profile_, - model->GetParentForNewNodes(), details, - BookmarkEditor::SHOW_TREE); -} - -bool Browser::CanCloseTab() const { - TabCloseableStateWatcher* watcher = - g_browser_process->tab_closeable_state_watcher(); - return !watcher || watcher->CanCloseTab(this); -} - -void Browser::ToggleUseVerticalTabs() { - use_vertical_tabs_.SetValue(!UseVerticalTabs()); - UseVerticalTabsChanged(); -} - -bool Browser::LargeIconsPermitted() const { - // We don't show the big icons in tabs for TYPE_EXTENSION_APP windows because - // for those windows, we already have a big icon in the top-left outside any - // tab. Having big tab icons too looks kinda redonk. - return TYPE_EXTENSION_APP != type(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, TabStripModelObserver implementation: - -void Browser::TabInsertedAt(TabContents* contents, - int index, - bool foreground) { - contents->set_delegate(this); - contents->controller().SetWindowID(session_id()); - - SyncHistoryWithTabs(index); - - // Make sure the loading state is updated correctly, otherwise the throbber - // won't start if the page is loading. - LoadingStateChanged(contents); - - // If the tab crashes in the beforeunload or unload handler, it won't be - // able to ack. But we know we can close it. - registrar_.Add(this, NotificationType::TAB_CONTENTS_DISCONNECTED, - Source(contents)); -} - -void Browser::TabClosingAt(TabStripModel* tab_strip_model, - TabContents* contents, - int index) { - NotificationService::current()->Notify( - NotificationType::TAB_CLOSING, - Source(&contents->controller()), - NotificationService::NoDetails()); - - // Sever the TabContents' connection back to us. - contents->set_delegate(NULL); -} - -void Browser::TabDetachedAt(TabContents* contents, int index) { - TabDetachedAtImpl(contents, index, DETACH_TYPE_DETACH); -} - -void Browser::TabDeselectedAt(TabContents* contents, int index) { - if (instant()) - instant()->DestroyPreviewContents(); - - // Save what the user's currently typing, so it can be restored when we - // switch back to this tab. - window_->GetLocationBar()->SaveStateToContents(contents); -} - -void Browser::TabSelectedAt(TabContents* old_contents, - TabContents* new_contents, - int index, - bool user_gesture) { - DCHECK(old_contents != new_contents); - - // If we have any update pending, do it now. - if (!chrome_updater_factory_.empty() && old_contents) - ProcessPendingUIUpdates(); - - // Propagate the profile to the location bar. - UpdateToolbar(true); - - // Update reload/stop state. - UpdateReloadStopState(new_contents->is_loading(), true); - - // Update commands to reflect current state. - UpdateCommandsForTabState(); - - // Reset the status bubble. - StatusBubble* status_bubble = GetStatusBubble(); - if (status_bubble) { - status_bubble->Hide(); - - // Show the loading state (if any). - status_bubble->SetStatus(WideToUTF16Hack( - GetSelectedTabContents()->GetStatusText())); - } - - if (HasFindBarController()) { - find_bar_controller_->ChangeTabContents(new_contents); - find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true); - } - - // Update sessions. Don't force creation of sessions. If sessions doesn't - // exist, the change will be picked up by sessions when created. - if (profile_->HasSessionService()) { - SessionService* session_service = profile_->GetSessionService(); - if (session_service && !tab_handler_->GetTabStripModel()->closing_all()) { - session_service->SetSelectedTabInWindow( - session_id(), tab_handler_->GetTabStripModel()->selected_index()); - } - } -} - -void Browser::TabMoved(TabContents* contents, - int from_index, - int to_index) { - DCHECK(from_index >= 0 && to_index >= 0); - // Notify the history service. - SyncHistoryWithTabs(std::min(from_index, to_index)); -} - -void Browser::TabReplacedAt(TabContents* old_contents, - TabContents* new_contents, - int index) { - TabDetachedAtImpl(old_contents, index, DETACH_TYPE_REPLACE); - TabInsertedAt(new_contents, index, - (index == tab_handler_->GetTabStripModel()->selected_index())); - - int entry_count = new_contents->controller().entry_count(); - if (entry_count > 0) { - // Send out notification so that observers are updated appropriately. - new_contents->controller().NotifyEntryChanged( - new_contents->controller().GetEntryAtIndex(entry_count - 1), - entry_count - 1); - } - - SessionService* session_service = profile()->GetSessionService(); - if (session_service) { - // The new_contents may end up with a different navigation stack. Force - // the session service to update itself. - session_service->TabRestored( - &new_contents->controller(), - tab_handler_->GetTabStripModel()->IsTabPinned(index)); - } -} - -void Browser::TabPinnedStateChanged(TabContents* contents, int index) { - if (!profile()->HasSessionService()) - return; - SessionService* session_service = profile()->GetSessionService(); - if (session_service) { - session_service->SetPinnedState( - session_id(), - GetTabContentsAt(index)->controller().session_id(), - tab_handler_->GetTabStripModel()->IsTabPinned(index)); - } -} - -void Browser::TabStripEmpty() { - // Close the frame after we return to the message loop (not immediately, - // otherwise it will destroy this object before the stack has a chance to - // cleanly unwind.) - // Note: This will be called several times if TabStripEmpty is called several - // times. This is because it does not close the window if tabs are - // still present. - // NOTE: If you change to be immediate (no invokeLater) then you'll need to - // update BrowserList::CloseAllBrowsers. - MessageLoop::current()->PostTask( - FROM_HERE, method_factory_.NewRunnableMethod(&Browser::CloseFrame)); -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, TabContentsDelegate implementation: - -void Browser::OpenURLFromTab(TabContents* source, - const GURL& url, - const GURL& referrer, - WindowOpenDisposition disposition, - PageTransition::Type transition) { - browser::NavigateParams params(this, url, transition); - params.source_contents = source; - params.referrer = referrer; - params.disposition = disposition; - params.tabstrip_add_types = TabStripModel::ADD_NONE; - browser::Navigate(¶ms); -} - -void Browser::NavigationStateChanged(const TabContents* source, - unsigned changed_flags) { - // Only update the UI when something visible has changed. - if (changed_flags) - ScheduleUIUpdate(source, changed_flags); - - // We don't schedule updates to commands since they will only change once per - // navigation, so we don't have to worry about flickering. - if (changed_flags & TabContents::INVALIDATE_URL) - UpdateCommandsForTabState(); -} - -void Browser::AddNewContents(TabContents* source, - TabContents* new_contents, - WindowOpenDisposition disposition, - const gfx::Rect& initial_pos, - bool user_gesture) { - // No code for this yet - DCHECK(disposition != SAVE_TO_DISK); - // Can't create a new contents for the current tab - invalid case. - DCHECK(disposition != CURRENT_TAB); - - // TODO(beng): This belongs behind the platform-specific View interface. - // That's why it's there. -#if defined(OS_CHROMEOS) - if (disposition == NEW_POPUP) { - // If the popup is bigger than a given factor of the screen, then - // turn it into a foreground tab (on chrome os only) - // Also check for width or height == 0, which would otherwise indicate - // a tab sized popup window. - GdkScreen* screen = gdk_screen_get_default(); - int max_width = gdk_screen_get_width(screen) * kPopupMaxWidthFactor; - int max_height = gdk_screen_get_height(screen) * kPopupMaxHeightFactor; - if (initial_pos.width() > max_width || initial_pos.width() == 0 || - initial_pos.height() > max_height || initial_pos.height() == 0) { - disposition = NEW_FOREGROUND_TAB; - } - } -#endif - - browser::NavigateParams params(this, new_contents); - params.source_contents = source; - params.disposition = disposition; - params.window_bounds = initial_pos; - browser::Navigate(¶ms); -} - -void Browser::ActivateContents(TabContents* contents) { - tab_handler_->GetTabStripModel()->SelectTabContentsAt( - tab_handler_->GetTabStripModel()->GetIndexOfTabContents(contents), false); - window_->Activate(); -} - -void Browser::DeactivateContents(TabContents* contents) { - window_->Deactivate(); -} - -void Browser::LoadingStateChanged(TabContents* source) { - window_->UpdateLoadingAnimations( - tab_handler_->GetTabStripModel()->TabsAreLoading()); - window_->UpdateTitleBar(); - - if (source == GetSelectedTabContents()) { - UpdateReloadStopState(source->is_loading(), false); - if (GetStatusBubble()) { - GetStatusBubble()->SetStatus(WideToUTF16( - GetSelectedTabContents()->GetStatusText())); - } - - if (!source->is_loading() && - pending_web_app_action_ == UPDATE_SHORTCUT) { - // Schedule a shortcut update when web application info is available if - // last committed entry is not NULL. Last committed entry could be NULL - // when an interstitial page is injected (e.g. bad https certificate, - // malware site etc). When this happens, we abort the shortcut update. - NavigationEntry* entry = source->controller().GetLastCommittedEntry(); - if (entry) { - source->render_view_host()->GetApplicationInfo(entry->page_id()); - } else { - pending_web_app_action_ = NONE; - } - } - } -} - -void Browser::CloseContents(TabContents* source) { - if (is_attempting_to_close_browser_) { - // If we're trying to close the browser, just clear the state related to - // waiting for unload to fire. Don't actually try to close the tab as it - // will go down the slow shutdown path instead of the fast path of killing - // all the renderer processes. - ClearUnloadState(source); - return; - } - - int index = tab_handler_->GetTabStripModel()->GetIndexOfTabContents(source); - if (index == TabStripModel::kNoTab) { - NOTREACHED() << "CloseContents called for tab not in our strip"; - return; - } - tab_handler_->GetTabStripModel()->CloseTabContentsAt( - index, - TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); -} - -void Browser::MoveContents(TabContents* source, const gfx::Rect& pos) { - if ((type() & TYPE_POPUP) == 0) { - NOTREACHED() << "moving invalid browser type"; - return; - } - window_->SetBounds(pos); -} - -void Browser::DetachContents(TabContents* source) { - int index = tab_handler_->GetTabStripModel()->GetIndexOfTabContents(source); - if (index >= 0) - tab_handler_->GetTabStripModel()->DetachTabContentsAt(index); -} - -bool Browser::IsPopup(const TabContents* source) const { - // A non-tabbed BROWSER is an unconstrained popup. - return !!(type() & TYPE_POPUP); -} - -void Browser::ToolbarSizeChanged(TabContents* source, bool is_animating) { - if (source == GetSelectedTabContents() || source == NULL) { - // This will refresh the shelf if needed. - window_->SelectedTabToolbarSizeChanged(is_animating); - } -} - -void Browser::URLStarredChanged(TabContents* source, bool starred) { - if (source == GetSelectedTabContents()) - window_->SetStarredState(starred); -} - -void Browser::ContentsMouseEvent( - TabContents* source, const gfx::Point& location, bool motion) { - if (!GetStatusBubble()) - return; - - if (source == GetSelectedTabContents()) { - GetStatusBubble()->MouseMoved(location, !motion); - if (!motion) - GetStatusBubble()->SetURL(GURL(), string16()); - } -} - -void Browser::UpdateTargetURL(TabContents* source, const GURL& url) { - if (!GetStatusBubble()) - return; - - if (source == GetSelectedTabContents()) { - PrefService* prefs = profile_->GetPrefs(); - GetStatusBubble()->SetURL( - url, UTF8ToUTF16(prefs->GetString(prefs::kAcceptLanguages))); - } -} - -void Browser::UpdateDownloadShelfVisibility(bool visible) { - if (GetStatusBubble()) - GetStatusBubble()->UpdateDownloadShelfVisibility(visible); -} - -bool Browser::UseVerticalTabs() const { - return use_vertical_tabs_.GetValue(); -} - -void Browser::ContentsZoomChange(bool zoom_in) { - ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS); -} - -void Browser::OnContentSettingsChange(TabContents* source) { - if (source == GetSelectedTabContents()) - window_->GetLocationBar()->UpdateContentSettingsIcons(); -} - -void Browser::SetTabContentBlocked(TabContents* contents, bool blocked) { - int index = tabstrip_model()->GetIndexOfTabContents(contents); - if (index == TabStripModel::kNoTab) { - NOTREACHED(); - return; - } - tabstrip_model()->SetTabBlocked(index, blocked); -} - -void Browser::TabContentsFocused(TabContents* tab_content) { - window_->TabContentsFocused(tab_content); -} - -bool Browser::TakeFocus(bool reverse) { - NotificationService::current()->Notify( - NotificationType::FOCUS_RETURNED_TO_BROWSER, - Source(this), - NotificationService::NoDetails()); - return false; -} - -bool Browser::IsApplication() const { - return (type_ & TYPE_APP) != 0; -} - -void Browser::ConvertContentsToApplication(TabContents* contents) { - const GURL& url = contents->controller().GetActiveEntry()->url(); - std::string app_name = web_app::GenerateApplicationNameFromURL(url); - RegisterAppPrefs(app_name); - - DetachContents(contents); - Browser* browser = Browser::CreateForApp(app_name, NULL, profile_, false); - browser->tabstrip_model()->AppendTabContents(contents, true); - TabContents* tab_contents = browser->GetSelectedTabContents(); - tab_contents->GetMutableRendererPrefs()->can_accept_load_drops = false; - tab_contents->render_view_host()->SyncRendererPrefs(); - browser->window()->Show(); -} - -bool Browser::ShouldDisplayURLField() { - return !IsApplication(); -} - -void Browser::BeforeUnloadFired(TabContents* tab, - bool proceed, - bool* proceed_to_fire_unload) { - if (!is_attempting_to_close_browser_) { - *proceed_to_fire_unload = proceed; - if (!proceed) - tab->set_closed_by_user_gesture(false); - return; - } - - if (!proceed) { - CancelWindowClose(); - *proceed_to_fire_unload = false; - tab->set_closed_by_user_gesture(false); - return; - } - - if (RemoveFromSet(&tabs_needing_before_unload_fired_, tab)) { - // Now that beforeunload has fired, put the tab on the queue to fire - // unload. - tabs_needing_unload_fired_.insert(tab); - ProcessPendingTabs(); - // We want to handle firing the unload event ourselves since we want to - // fire all the beforeunload events before attempting to fire the unload - // events should the user cancel closing the browser. - *proceed_to_fire_unload = false; - return; - } - - *proceed_to_fire_unload = true; -} - -gfx::Rect Browser::GetRootWindowResizerRect() const { - return window_->GetRootWindowResizerRect(); -} - -void Browser::ShowHtmlDialog(HtmlDialogUIDelegate* delegate, - gfx::NativeWindow parent_window) { - window_->ShowHTMLDialog(delegate, parent_window); -} - -void Browser::SetFocusToLocationBar(bool select_all) { - // Two differences between this and FocusLocationBar(): - // (1) This doesn't get recorded in user metrics, since it's called - // internally. - // (2) This checks whether the location bar can be focused, and if not, clears - // the focus. FocusLocationBar() is only reached when the location bar is - // focusable, but this may be reached at other times, e.g. while in - // fullscreen mode, where we need to leave focus in a consistent state. - window_->SetFocusToLocationBar(select_all); -} - -void Browser::RenderWidgetShowing() { - window_->DisableInactiveFrame(); -} - -int Browser::GetExtraRenderViewHeight() const { - return window_->GetExtraRenderViewHeight(); -} - -void Browser::OnStartDownload(DownloadItem* download, TabContents* tab) { - if (!window()) - return; - -#if defined(OS_CHROMEOS) - // Don't show content browser for extension/theme downloads from gallery. - if (download->is_extension_install()) { - ExtensionsService* service = profile_->GetExtensionsService(); - if (service && service->IsDownloadFromGallery(download->url(), - download->referrer_url())) { - return; - } - } - - // skip the download shelf and just open the file browser in chromeos - std::string arg = download->full_path().DirName().value(); - FileBrowseUI::OpenPopup(profile_, - arg, - FileBrowseUI::kPopupWidth, - FileBrowseUI::kPopupHeight); - -#else - // GetDownloadShelf creates the download shelf if it was not yet created. - window()->GetDownloadShelf()->AddDownload(new DownloadItemModel(download)); - - // Don't show the animation for "Save file" downloads. - if (download->total_bytes() <= 0) - return; - - // For non-theme extensions, we don't show the download animation. - if (download->is_extension_install() && - !ExtensionsService::IsDownloadFromMiniGallery(download->url())) - return; - - TabContents* current_tab = GetSelectedTabContents(); - // We make this check for the case of minimized windows, unit tests, etc. - if (platform_util::IsVisible(current_tab->GetNativeView()) && - Animation::ShouldRenderRichAnimation()) { - DownloadStartedAnimation::Show(current_tab); - } -#endif - - // If the download occurs in a new tab, close it - if (tab->controller().IsInitialNavigation() && - GetConstrainingContents(tab) == tab && tab_count() > 1) { - CloseContents(tab); - } -} - -void Browser::ConfirmSetDefaultSearchProvider( - TabContents* tab_contents, - TemplateURL* template_url, - TemplateURLModel* template_url_model) { - window()->ConfirmSetDefaultSearchProvider(tab_contents, template_url, - template_url_model); -} -void Browser::ConfirmAddSearchProvider(const TemplateURL* template_url, - Profile* profile) { - window()->ConfirmAddSearchProvider(template_url, profile); -} - -void Browser::ShowPageInfo(Profile* profile, - const GURL& url, - const NavigationEntry::SSLStatus& ssl, - bool show_history) { - window()->ShowPageInfo(profile, url, ssl, show_history); -} - -bool Browser::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, - bool* is_keyboard_shortcut) { - return window()->PreHandleKeyboardEvent(event, is_keyboard_shortcut); -} - -void Browser::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) { - window()->HandleKeyboardEvent(event); -} - -void Browser::ShowRepostFormWarningDialog(TabContents *tab_contents) { - window()->ShowRepostFormWarningDialog(tab_contents); -} - -void Browser::ShowContentSettingsWindow(ContentSettingsType content_type) { - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableTabbedOptions)) { - ShowOptionsTab( - chrome::kContentSettingsSubPage + kHashMark + - ContentSettingsHandler::ContentSettingsTypeToGroupName(content_type)); - } else { - window()->ShowContentSettingsWindow(content_type, - profile_->GetOriginalProfile()); - } -} - -void Browser::ShowCollectedCookiesDialog(TabContents *tab_contents) { - window()->ShowCollectedCookiesDialog(tab_contents); -} - -bool Browser::ShouldAddNavigationToHistory( - const history::HistoryAddPageArgs& add_page_args, - NavigationType::Type navigation_type) { - // Don't update history if running as app. - return !IsApplication(); -} - -void Browser::OnDidGetApplicationInfo(TabContents* tab_contents, - int32 page_id) { - TabContents* current_tab = GetSelectedTabContents(); - if (current_tab != tab_contents) - return; - - NavigationEntry* entry = current_tab->controller().GetLastCommittedEntry(); - if (!entry || (entry->page_id() != page_id)) - return; - - switch (pending_web_app_action_) { - case CREATE_SHORTCUT: { - window()->ShowCreateShortcutsDialog(current_tab); - break; - } - case UPDATE_SHORTCUT: { - web_app::UpdateShortcutForTabContents(current_tab); - break; - } - default: - NOTREACHED(); - break; - } - - pending_web_app_action_ = NONE; -} - -void Browser::ContentRestrictionsChanged(TabContents* source) { - UpdateCommandsForContentRestrictionState(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, SelectFileDialog::Listener implementation: - -void Browser::FileSelected(const FilePath& path, int index, void* params) { - profile_->set_last_selected_directory(path.DirName()); - GURL file_url = net::FilePathToFileURL(path); - if (!file_url.is_empty()) - OpenURL(file_url, GURL(), CURRENT_TAB, PageTransition::TYPED); -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, NotificationObserver implementation: - -void Browser::Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - switch (type.value) { - case NotificationType::TAB_CONTENTS_DISCONNECTED: - if (is_attempting_to_close_browser_) { - // Need to do this asynchronously as it will close the tab, which is - // currently on the call stack above us. - MessageLoop::current()->PostTask( - FROM_HERE, - method_factory_.NewRunnableMethod(&Browser::ClearUnloadState, - Source(source).ptr())); - } - break; - - case NotificationType::SSL_VISIBLE_STATE_CHANGED: - // When the current tab's SSL state changes, we need to update the URL - // bar to reflect the new state. Note that it's possible for the selected - // tab contents to be NULL. This is because we listen for all sources - // (NavigationControllers) for convenience, so the notification could - // actually be for a different window while we're doing asynchronous - // closing of this one. - if (GetSelectedTabContents() && - &GetSelectedTabContents()->controller() == - Source(source).ptr()) - UpdateToolbar(false); - break; - - case NotificationType::EXTENSION_UPDATE_DISABLED: { - // Show the UI if the extension was disabled for escalated permissions. - Profile* profile = Source(source).ptr(); - if (profile_->IsSameProfile(profile)) { - ExtensionsService* service = profile->GetExtensionsService(); - DCHECK(service); - const Extension* extension = Details(details).ptr(); - if (service->extension_prefs()->DidExtensionEscalatePermissions( - extension->id())) - ShowExtensionDisabledUI(service, profile_, extension); - } - break; - } - - case NotificationType::EXTENSION_UNLOADED: - case NotificationType::EXTENSION_UNLOADED_DISABLED: { - window()->GetLocationBar()->UpdatePageActions(); - - // Close any tabs from the unloaded extension. - const Extension* extension = Details(details).ptr(); - TabStripModel* model = tab_handler_->GetTabStripModel(); - for (int i = model->count() - 1; i >= 0; --i) { - TabContents* tc = model->GetTabContentsAt(i); - if (tc->GetURL().SchemeIs(chrome::kExtensionScheme) && - tc->GetURL().host() == extension->id()) { - CloseTabContents(tc); - } - } - - break; - } - - case NotificationType::EXTENSION_PROCESS_TERMINATED: { - window()->GetLocationBar()->InvalidatePageActions(); - - TabContents* tab_contents = GetSelectedTabContents(); - if (!tab_contents) - break; - ExtensionsService* extensions_service = - Source(source).ptr()->GetExtensionsService(); - ExtensionHost* extension_host = Details(details).ptr(); - tab_contents->AddInfoBar(new CrashedExtensionInfoBarDelegate( - tab_contents, extensions_service, extension_host->extension())); - break; - } - - case NotificationType::EXTENSION_LOADED: { - window()->GetLocationBar()->UpdatePageActions(); - - // If any "This extension has crashed" InfoBarDelegates are around for - // this extension, it means that it has been reloaded in another window - // so just remove the remaining CrashedExtensionInfoBarDelegate objects. - TabContents* tab_contents = GetSelectedTabContents(); - if (!tab_contents) - break; - const Extension* extension = Details(details).ptr(); - CrashedExtensionInfoBarDelegate* delegate = NULL; - for (int i = 0; i < tab_contents->infobar_delegate_count();) { - delegate = tab_contents->GetInfoBarDelegateAt(i)-> - AsCrashedExtensionInfoBarDelegate(); - if (delegate && delegate->extension_id() == extension->id()) { - tab_contents->RemoveInfoBar(delegate); - continue; - } - // Only increment |i| if we didn't remove an entry. - ++i; - } - break; - } - - case NotificationType::BROWSER_THEME_CHANGED: - window()->UserChangedTheme(); - break; - - case NotificationType::EXTENSION_READY_FOR_INSTALL: { - // Handle EXTENSION_READY_FOR_INSTALL for last active normal browser. - if (BrowserList::FindBrowserWithType(profile(), - Browser::TYPE_NORMAL, - true) != this) - break; - - // We only want to show the loading dialog for themes, but we don't want - // to wait until unpack to find out an extension is a theme, so we test - // the download_url GURL instead. This means that themes in the extensions - // gallery won't get the loading dialog. - GURL download_url = *(Details(details).ptr()); - if (ExtensionsService::IsDownloadFromMiniGallery(download_url)) - window()->ShowThemeInstallBubble(); - break; - } - - case NotificationType::PROFILE_ERROR: { - if (BrowserList::GetLastActive() != this) - break; - int* message_id = Details(details).ptr(); - window()->ShowProfileErrorDialog(*message_id); - break; - } - - case NotificationType::PREF_CHANGED: { - const std::string& pref_name = *Details(details).ptr(); - if (pref_name == prefs::kUseVerticalTabs) { - UseVerticalTabsChanged(); - } else if (pref_name == prefs::kPrintingEnabled) { - UpdatePrintingState(0); - } else if (pref_name == prefs::kInstantEnabled) { - if (!InstantController::IsEnabled(profile())) { - if (instant()) { - instant()->DestroyPreviewContents(); - instant_.reset(NULL); - } - } else { - CreateInstantIfNecessary(); - } - } else if (pref_name == prefs::kDevToolsDisabled) { - UpdateCommandsForDevTools(); - if (dev_tools_disabled_.GetValue()) - g_browser_process->devtools_manager()->CloseAllClientHosts(); - } else { - NOTREACHED(); - } - break; - } - - default: - NOTREACHED() << "Got a notification we didn't register for."; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, ProfileSyncServiceObserver implementation: - -void Browser::OnStateChanged() { - DCHECK(profile_->GetProfileSyncService()); - -#if !defined(OS_MACOSX) - const bool show_main_ui = (type() == TYPE_NORMAL) && !window_->IsFullscreen(); -#else - const bool show_main_ui = (type() == TYPE_NORMAL); -#endif - - command_updater_.UpdateCommandEnabled(IDC_SYNC_BOOKMARKS, - show_main_ui && profile_->IsSyncAccessible()); -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, InstantDelegate implementation: - -void Browser::ShowInstant(TabContents* preview_contents) { - DCHECK(instant_->tab_contents() == GetSelectedTabContents()); - window_->ShowInstant(preview_contents); -} - -void Browser::HideInstant() { - window_->HideInstant(); -} - -void Browser::CommitInstant(TabContents* preview_contents) { - TabContents* tab_contents = instant_->tab_contents(); - int index = tab_handler_->GetTabStripModel()->GetIndexOfTabContents( - tab_contents); - DCHECK_NE(-1, index); - preview_contents->controller().CopyStateFromAndPrune( - &tab_contents->controller()); - // TabStripModel takes ownership of preview_contents. - tab_handler_->GetTabStripModel()->ReplaceTabContentsAt( - index, preview_contents); -} - -void Browser::SetSuggestedText(const string16& text) { - window()->GetLocationBar()->SetSuggestedText(text); -} - -gfx::Rect Browser::GetInstantBounds() { - return window()->GetInstantBounds(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, Command and state updating (private): - -void Browser::InitCommandState() { - // All browser commands whose state isn't set automagically some other way - // (like Back & Forward with initial page load) must have their state - // initialized here, otherwise they will be forever disabled. - - // Navigation commands - command_updater_.UpdateCommandEnabled(IDC_RELOAD, true); - command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE, true); - - // Window management commands - command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW, true); - command_updater_.UpdateCommandEnabled(IDC_NEW_INCOGNITO_WINDOW, true); - command_updater_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true); - command_updater_.UpdateCommandEnabled(IDC_NEW_TAB, true); - command_updater_.UpdateCommandEnabled(IDC_CLOSE_TAB, true); - command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true); - command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB, false); - command_updater_.UpdateCommandEnabled(IDC_EXIT, true); - command_updater_.UpdateCommandEnabled(IDC_TOGGLE_VERTICAL_TABS, true); - - // Page-related commands - command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_AUTO_DETECT, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF8, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF16LE, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88591, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1252, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_GBK, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_GB18030, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5HKSCS, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_THAI, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOREAN, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_SHIFTJIS, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO2022JP, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_EUCJP, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885915, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_MACINTOSH, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88592, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1250, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88595, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1251, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8R, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8U, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88597, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1253, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88594, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885913, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1257, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88593, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885910, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885914, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885916, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1254, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88596, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1256, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598I, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1255, true); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1258, true); - - // Zoom - command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, true); - command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true); - command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, true); - command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true); - - // Show various bits of UI - command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, true); - command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false); - UpdateCommandsForDevTools(); - command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, true); - command_updater_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true); - command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER, - browser_defaults::bookmarks_enabled); - command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true); - command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE, true); - command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, true); - -#if defined(OS_CHROMEOS) - command_updater_.UpdateCommandEnabled(IDC_SEARCH, true); - command_updater_.UpdateCommandEnabled(IDC_SYSTEM_OPTIONS, true); - command_updater_.UpdateCommandEnabled(IDC_INTERNET_OPTIONS, true); -#endif - - ExtensionsService* extensions_service = profile()->GetExtensionsService(); - bool enable_extensions = - extensions_service && extensions_service->extensions_enabled(); - command_updater_.UpdateCommandEnabled(IDC_MANAGE_EXTENSIONS, - enable_extensions); - - // Initialize other commands based on the window type. - bool normal_window = type() == TYPE_NORMAL; - bool non_devtools_window = type() != TYPE_DEVTOOLS; - - // Navigation commands - command_updater_.UpdateCommandEnabled(IDC_HOME, normal_window); - - // Window management commands - command_updater_.UpdateCommandEnabled(IDC_FULLSCREEN, - type() != TYPE_APP_PANEL); - command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window); - command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB, - normal_window); - command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_NEXT, normal_window); - command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_PREVIOUS, normal_window); - command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_0, normal_window); - command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_1, normal_window); - command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_2, normal_window); - command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_3, normal_window); - command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_4, normal_window); - command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_5, normal_window); - command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window); - command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window); - command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window); -#if defined(OS_MACOSX) - command_updater_.UpdateCommandEnabled(IDC_TABPOSE, normal_window); -#endif - - // Page-related commands - command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_PAGE, - browser_defaults::bookmarks_enabled && normal_window); - - // Clipboard commands - command_updater_.UpdateCommandEnabled(IDC_COPY_URL, non_devtools_window); - - // Find-in-page - command_updater_.UpdateCommandEnabled(IDC_FIND, non_devtools_window); - command_updater_.UpdateCommandEnabled(IDC_FIND_NEXT, non_devtools_window); - command_updater_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, non_devtools_window); - - // AutoFill - command_updater_.UpdateCommandEnabled(IDC_AUTOFILL_DEFAULT, - non_devtools_window); - - // Show various bits of UI - command_updater_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA, normal_window); - - // The upgrade entry and the view incompatibility entry should always be - // enabled. Whether they are visible is a separate matter determined on menu - // show. - command_updater_.UpdateCommandEnabled(IDC_UPGRADE_DIALOG, true); - command_updater_.UpdateCommandEnabled(IDC_VIEW_INCOMPATIBILITIES, true); - - // Initialize other commands whose state changes based on fullscreen mode. - UpdateCommandsForFullscreenMode(false); - - UpdateCommandsForContentRestrictionState(); -} - -void Browser::UpdateCommandsForTabState() { - TabContents* current_tab = GetSelectedTabContents(); - if (!current_tab) // May be NULL during tab restore. - return; - - // Navigation commands - NavigationController& nc = current_tab->controller(); - command_updater_.UpdateCommandEnabled(IDC_BACK, nc.CanGoBack()); - command_updater_.UpdateCommandEnabled(IDC_FORWARD, nc.CanGoForward()); - command_updater_.UpdateCommandEnabled(IDC_RELOAD, - CanReloadContents(current_tab)); - command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE, - CanReloadContents(current_tab)); - - // Window management commands - bool non_app_window = !(type() & TYPE_APP); - command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, - non_app_window && CanDuplicateContentsAt(selected_index())); - command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, - non_app_window && tab_count() > 1); - command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB, - non_app_window && tab_count() > 1); - - // Page-related commands - window_->SetStarredState(current_tab->is_starred()); - command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_ALL_TABS, - browser_defaults::bookmarks_enabled && CanBookmarkAllTabs()); - command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE, - current_tab->controller().CanViewSource()); - command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION, - current_tab->ShouldDisplayURL() && current_tab->GetURL().is_valid()); - - // Changing the encoding is not possible on Chrome-internal webpages. - // Instead of using GetURL here, we use url() (which is the "real" url of the - // page) from the NavigationEntry because its reflects their origin rather - // than the display one (returned by GetURL) which may be different (like - // having "view-source:" on the front). - NavigationEntry* active_entry = nc.GetActiveEntry(); - bool is_chrome_internal = (active_entry ? - active_entry->url().SchemeIs(chrome::kChromeUIScheme) : false); - command_updater_.UpdateCommandEnabled(IDC_ENCODING_MENU, - !is_chrome_internal && SavePackage::IsSavableContents( - current_tab->contents_mime_type())); - - // Show various bits of UI - // TODO(pinkerton): Disable app-mode in the model until we implement it - // on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148 -#if !defined(OS_MACOSX) - command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, - web_app::IsValidUrl(current_tab->GetURL())); -#endif - - UpdateCommandsForContentRestrictionState(); -} - -void Browser::UpdateCommandsForContentRestrictionState() { - int restrictions = 0; - TabContents* current_tab = GetSelectedTabContents(); - if (current_tab) { - restrictions = current_tab->content_restrictions(); - NavigationEntry* active_entry = current_tab->controller().GetActiveEntry(); - // See comment in UpdateCommandsForTabState about why we call url(). - if (!SavePackage::IsSavableURL(active_entry ? active_entry->url() : GURL())) - restrictions |= CONTENT_RESTRICTION_SAVE; - } - - command_updater_.UpdateCommandEnabled( - IDC_COPY, !(restrictions & CONTENT_RESTRICTION_COPY)); - command_updater_.UpdateCommandEnabled( - IDC_CUT, !(restrictions & CONTENT_RESTRICTION_CUT)); - command_updater_.UpdateCommandEnabled( - IDC_PASTE, !(restrictions & CONTENT_RESTRICTION_PASTE)); - command_updater_.UpdateCommandEnabled( - IDC_SAVE_PAGE, !(restrictions & CONTENT_RESTRICTION_SAVE)); - UpdatePrintingState(restrictions); -} - -void Browser::UpdatePrintingState(int content_restrictions) { - bool enabled = true; - if (content_restrictions & CONTENT_RESTRICTION_PRINT) { - enabled = false; - } else if (g_browser_process->local_state()) { - enabled = printing_enabled_.GetValue(); - } - command_updater_.UpdateCommandEnabled(IDC_PRINT, enabled); -} - -void Browser::UpdateReloadStopState(bool is_loading, bool force) { - window_->UpdateReloadStopState(is_loading, force); - command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading); -} - -void Browser::UpdateCommandsForDevTools() { - bool dev_tools_enabled = !dev_tools_disabled_.GetValue(); - command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS, - dev_tools_enabled); - command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_CONSOLE, - dev_tools_enabled); - command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_INSPECT, - dev_tools_enabled); -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, UI update coalescing and handling (private): - -void Browser::UpdateToolbar(bool should_restore_state) { - window_->UpdateToolbar(GetSelectedTabContents(), should_restore_state); -} - -void Browser::ScheduleUIUpdate(const TabContents* source, - unsigned changed_flags) { - if (!source) - return; - - // Do some synchronous updates. - if (changed_flags & TabContents::INVALIDATE_URL && - source == GetSelectedTabContents()) { - // Only update the URL for the current tab. Note that we do not update - // the navigation commands since those would have already been updated - // synchronously by NavigationStateChanged. - UpdateToolbar(false); - changed_flags &= ~TabContents::INVALIDATE_URL; - } - if (changed_flags & TabContents::INVALIDATE_LOAD) { - // Update the loading state synchronously. This is so the throbber will - // immediately start/stop, which gives a more snappy feel. We want to do - // this for any tab so they start & stop quickly. - tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt( - tab_handler_->GetTabStripModel()->GetIndexOfController( - &source->controller()), - TabStripModelObserver::LOADING_ONLY); - // The status bubble needs to be updated during INVALIDATE_LOAD too, but - // we do that asynchronously by not stripping INVALIDATE_LOAD from - // changed_flags. - } - - if (changed_flags & TabContents::INVALIDATE_TITLE && !source->is_loading()) { - // To correctly calculate whether the title changed while not loading - // we need to process the update synchronously. This state only matters for - // the TabStripModel, so we notify the TabStripModel now and notify others - // asynchronously. - tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt( - tab_handler_->GetTabStripModel()->GetIndexOfController( - &source->controller()), - TabStripModelObserver::TITLE_NOT_LOADING); - } - - if (changed_flags & TabContents::INVALIDATE_BOOKMARK_BAR) { - window()->ShelfVisibilityChanged(); - changed_flags &= ~TabContents::INVALIDATE_BOOKMARK_BAR; - } - - // If the only updates were synchronously handled above, we're done. - if (changed_flags == 0) - return; - - // Save the dirty bits. - scheduled_updates_[source] |= changed_flags; - - if (chrome_updater_factory_.empty()) { - // No task currently scheduled, start another. - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - chrome_updater_factory_.NewRunnableMethod( - &Browser::ProcessPendingUIUpdates), - kUIUpdateCoalescingTimeMS); - } -} - -void Browser::ProcessPendingUIUpdates() { -#ifndef NDEBUG - // Validate that all tabs we have pending updates for exist. This is scary - // because the pending list must be kept in sync with any detached or - // deleted tabs. - for (UpdateMap::const_iterator i = scheduled_updates_.begin(); - i != scheduled_updates_.end(); ++i) { - bool found = false; - for (int tab = 0; tab < tab_count(); tab++) { - if (GetTabContentsAt(tab) == i->first) { - found = true; - break; - } - } - DCHECK(found); - } -#endif - - chrome_updater_factory_.RevokeAll(); - - for (UpdateMap::const_iterator i = scheduled_updates_.begin(); - i != scheduled_updates_.end(); ++i) { - // Do not dereference |contents|, it may be out-of-date! - const TabContents* contents = i->first; - unsigned flags = i->second; - - if (contents == GetSelectedTabContents()) { - // Updates that only matter when the tab is selected go here. - - if (flags & TabContents::INVALIDATE_PAGE_ACTIONS) - window()->GetLocationBar()->UpdatePageActions(); - - // Updating the URL happens synchronously in ScheduleUIUpdate. - if (flags & TabContents::INVALIDATE_LOAD && GetStatusBubble()) - GetStatusBubble()->SetStatus(WideToUTF16(contents->GetStatusText())); - - if (flags & (TabContents::INVALIDATE_TAB | - TabContents::INVALIDATE_TITLE)) { -// TODO(pinkerton): Disable app-mode in the model until we implement it -// on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148 -#if !defined(OS_MACOSX) - command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, - web_app::IsValidUrl(contents->GetURL())); -#endif - window_->UpdateTitleBar(); - } - } - - // Updates that don't depend upon the selected state go here. - if (flags & (TabContents::INVALIDATE_TAB | TabContents::INVALIDATE_TITLE)) { - tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt( - tab_handler_->GetTabStripModel()->GetIndexOfTabContents(contents), - TabStripModelObserver::ALL); - } - - // We don't need to process INVALIDATE_STATE, since that's not visible. - } - - scheduled_updates_.clear(); -} - -void Browser::RemoveScheduledUpdatesFor(TabContents* contents) { - if (!contents) - return; - - UpdateMap::iterator i = scheduled_updates_.find(contents); - if (i != scheduled_updates_.end()) - scheduled_updates_.erase(i); -} - - -/////////////////////////////////////////////////////////////////////////////// -// Browser, Getters for UI (private): - -StatusBubble* Browser::GetStatusBubble() { -#if !defined(OS_MACOSX) - // In kiosk mode, we want to always hide the status bubble. - if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode)) - return NULL; -#endif - return window_ ? window_->GetStatusBubble() : NULL; -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, Session restore functions (private): - -void Browser::SyncHistoryWithTabs(int index) { - if (!profile()->HasSessionService()) - return; - SessionService* session_service = profile()->GetSessionService(); - if (session_service) { - for (int i = index; i < tab_count(); ++i) { - TabContents* contents = GetTabContentsAt(i); - if (contents) { - session_service->SetTabIndexInWindow( - session_id(), contents->controller().session_id(), i); - session_service->SetPinnedState( - session_id(), - contents->controller().session_id(), - tab_handler_->GetTabStripModel()->IsTabPinned(i)); - } - } - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, OnBeforeUnload handling (private): - -void Browser::ProcessPendingTabs() { - DCHECK(is_attempting_to_close_browser_); - - if (HasCompletedUnloadProcessing()) { - // We've finished all the unload events and can proceed to close the - // browser. - OnWindowClosing(); - return; - } - - // Process beforeunload tabs first. When that queue is empty, process - // unload tabs. - if (!tabs_needing_before_unload_fired_.empty()) { - TabContents* tab = *(tabs_needing_before_unload_fired_.begin()); - // Null check render_view_host here as this gets called on a PostTask and - // the tab's render_view_host may have been nulled out. - if (tab->render_view_host()) { - tab->render_view_host()->FirePageBeforeUnload(false); - } else { - ClearUnloadState(tab); - } - } else if (!tabs_needing_unload_fired_.empty()) { - // We've finished firing all beforeunload events and can proceed with unload - // events. - // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting - // somewhere around here so that we have accurate measurements of shutdown - // time. - // TODO(ojan): We can probably fire all the unload events in parallel and - // get a perf benefit from that in the cases where the tab hangs in it's - // unload handler or takes a long time to page in. - TabContents* tab = *(tabs_needing_unload_fired_.begin()); - // Null check render_view_host here as this gets called on a PostTask and - // the tab's render_view_host may have been nulled out. - if (tab->render_view_host()) { - tab->render_view_host()->ClosePage(false, -1, -1); - } else { - ClearUnloadState(tab); - } - } else { - NOTREACHED(); - } -} - -bool Browser::HasCompletedUnloadProcessing() const { - return is_attempting_to_close_browser_ && - tabs_needing_before_unload_fired_.empty() && - tabs_needing_unload_fired_.empty(); -} - -void Browser::CancelWindowClose() { - // Closing of window can be canceled from: - // - canceling beforeunload - // - disallowing closing from IsClosingPermitted. - DCHECK(is_attempting_to_close_browser_); - tabs_needing_before_unload_fired_.clear(); - tabs_needing_unload_fired_.clear(); - is_attempting_to_close_browser_ = false; - - // Inform TabCloseableStateWatcher that closing of window has been canceled. - TabCloseableStateWatcher* watcher = - g_browser_process->tab_closeable_state_watcher(); - if (watcher) - watcher->OnWindowCloseCanceled(this); -} - -bool Browser::RemoveFromSet(UnloadListenerSet* set, TabContents* tab) { - DCHECK(is_attempting_to_close_browser_); - - UnloadListenerSet::iterator iter = std::find(set->begin(), set->end(), tab); - if (iter != set->end()) { - set->erase(iter); - return true; - } - return false; -} - -void Browser::ClearUnloadState(TabContents* tab) { - // Closing of browser could be canceled (via IsClosingPermitted) between the - // time when request was initiated and when this method is called, so check - // for is_attempting_to_close_browser_ flag before proceeding. - if (is_attempting_to_close_browser_) { - RemoveFromSet(&tabs_needing_before_unload_fired_, tab); - RemoveFromSet(&tabs_needing_unload_fired_, tab); - ProcessPendingTabs(); - } -} - - -/////////////////////////////////////////////////////////////////////////////// -// Browser, In-progress download termination handling (private): - -bool Browser::CanCloseWithInProgressDownloads() { - if (cancel_download_confirmation_state_ != NOT_PROMPTED) { - if (cancel_download_confirmation_state_ == WAITING_FOR_RESPONSE) { - // We need to hear from the user before we can close. - return false; - } - // RESPONSE_RECEIVED case, the user decided to go along with the closing. - return true; - } - // Indicated that normal (non-incognito) downloads are pending. - bool normal_downloads_are_present = false; - bool incognito_downloads_are_present = false; - // If there are no download in-progress, our job is done. - DownloadManager* download_manager = NULL; - // But first we need to check for the existance of the download manager, as - // GetDownloadManager() will unnecessarily try to create one if it does not - // exist. - if (profile_->HasCreatedDownloadManager()) - download_manager = profile_->GetDownloadManager(); - if (profile_->IsOffTheRecord()) { - // Browser is incognito and so download_manager if present is for incognito - // downloads. - incognito_downloads_are_present = - (download_manager && download_manager->in_progress_count() != 0); - // Check original profile. - if (profile_->GetOriginalProfile()->HasCreatedDownloadManager()) - download_manager = profile_->GetOriginalProfile()->GetDownloadManager(); - } - - normal_downloads_are_present = - (download_manager && download_manager->in_progress_count() != 0); - if (!normal_downloads_are_present && !incognito_downloads_are_present) - return true; - - if (is_attempting_to_close_browser_) - return true; - - if ((!normal_downloads_are_present && !profile()->IsOffTheRecord()) || - (!incognito_downloads_are_present && profile()->IsOffTheRecord())) - return true; - - // Let's figure out if we are the last window for our profile. - // Note that we cannot just use BrowserList::GetBrowserCount as browser - // windows closing is delayed and the returned count might include windows - // that are being closed. - // The browser allowed to be closed only if: - // 1. It is a regular browser and there are no regular downloads present or - // this is not the last regular browser window. - // 2. It is an incognito browser and there are no incognito downloads present - // or this is not the last incognito browser window. - int count = 0; - for (BrowserList::const_iterator iter = BrowserList::begin(); - iter != BrowserList::end(); ++iter) { - // Don't count this browser window or any other in the process of closing. - if (*iter == this || (*iter)->is_attempting_to_close_browser_) - continue; - - // Verify that this is not the last non-incognito or incognito browser, - // depending on the pending downloads. - if (normal_downloads_are_present && !profile()->IsOffTheRecord() && - (*iter)->profile()->IsOffTheRecord()) - continue; - if (incognito_downloads_are_present && profile()->IsOffTheRecord() && - !(*iter)->profile()->IsOffTheRecord()) - continue; - - // We test the original profile, because an incognito browser window keeps - // the original profile alive (and its DownloadManager). - // We also need to test explicitly the profile directly so that 2 incognito - // profiles count as a match. - if ((*iter)->profile() == profile() || - (*iter)->profile()->GetOriginalProfile() == profile()) - count++; - } - if (count > 0) - return true; - - cancel_download_confirmation_state_ = WAITING_FOR_RESPONSE; - window_->ConfirmBrowserCloseWithPendingDownloads(); - - // Return false so the browser does not close. We'll close if the user - // confirms in the dialog. - return false; -} - -/////////////////////////////////////////////////////////////////////////////// -// Browser, Assorted utility functions (private): - -// static -Browser* Browser::GetTabbedBrowser(Profile* profile, bool match_incognito) { - return BrowserList::FindBrowserWithType(profile, TYPE_NORMAL, - match_incognito); -} - -// static -Browser* Browser::GetOrCreateTabbedBrowser(Profile* profile) { - Browser* browser = GetTabbedBrowser(profile, false); - if (!browser) - browser = Browser::Create(profile); - return browser; -} - -void Browser::FindInPage(bool find_next, bool forward_direction) { - ShowFindBar(); - if (find_next) { - string16 find_text; -#if defined(OS_MACOSX) - // We always want to search for the contents of the find pasteboard on OS X. - find_text = GetFindPboardText(); -#endif - GetSelectedTabContents()->StartFinding(find_text, - forward_direction, - false); // Not case sensitive. - } -} - -void Browser::CloseFrame() { - window_->Close(); -} - -void Browser::TabDetachedAtImpl(TabContents* contents, int index, - DetachType type) { - if (type == DETACH_TYPE_DETACH) { - // Save what the user's currently typed. - window_->GetLocationBar()->SaveStateToContents(contents); - - if (!tab_handler_->GetTabStripModel()->closing_all()) - SyncHistoryWithTabs(0); - } - - contents->set_delegate(NULL); - RemoveScheduledUpdatesFor(contents); - - if (find_bar_controller_.get() && - index == tab_handler_->GetTabStripModel()->selected_index()) { - find_bar_controller_->ChangeTabContents(NULL); - } - - registrar_.Remove(this, NotificationType::TAB_CONTENTS_DISCONNECTED, - Source(contents)); -} - -// static -void Browser::RegisterAppPrefs(const std::string& app_name) { - // A set of apps that we've already started. - static std::set* g_app_names = NULL; - - if (!g_app_names) - g_app_names = new std::set; - - // Only register once for each app name. - if (g_app_names->find(app_name) != g_app_names->end()) - return; - g_app_names->insert(app_name); - - // We need to register the window position pref. - std::string window_pref(prefs::kBrowserWindowPlacement); - window_pref.append("_"); - window_pref.append(app_name); - PrefService* prefs = g_browser_process->local_state(); - DCHECK(prefs); - - prefs->RegisterDictionaryPref(window_pref.c_str()); -} - -void Browser::TabRestoreServiceChanged(TabRestoreService* service) { - command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB, - !service->entries().empty()); -} - -void Browser::TabRestoreServiceDestroyed(TabRestoreService* service) { - if (!tab_restore_service_) - return; - - DCHECK_EQ(tab_restore_service_, service); - tab_restore_service_->RemoveObserver(this); - tab_restore_service_ = NULL; -} - -bool Browser::OpenInstant(WindowOpenDisposition disposition) { - if (!instant() || !instant()->is_active() || !instant()->IsCurrent()) - return false; - - if (disposition == CURRENT_TAB) { - instant()->CommitCurrentPreview(INSTANT_COMMIT_PRESSED_ENTER); - return true; - } - if (disposition == NEW_FOREGROUND_TAB || disposition == NEW_BACKGROUND_TAB) { - HideInstant(); - TabContents* preview_contents = instant()->ReleasePreviewContents( - INSTANT_COMMIT_PRESSED_ENTER); - preview_contents->controller().PruneAllButActive(); - tab_handler_->GetTabStripModel()->AddTabContents( - preview_contents, - -1, - instant()->last_transition_type(), - disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_SELECTED : - TabStripModel::ADD_NONE); - instant()->CompleteRelease(preview_contents); - return true; - } - // The omnibox currently doesn't use other dispositions, so we don't attempt - // to handle them. If you hit this NOTREACHED file a bug and I'll (sky) add - // support for the new disposition. - NOTREACHED(); - return false; -} - -void Browser::CreateInstantIfNecessary() { - if (type() == TYPE_NORMAL && InstantController::IsEnabled(profile()) && - !profile()->IsOffTheRecord()) { - instant_.reset(new InstantController(profile_, this)); - } -} diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h index 885c568..a08661d 100644 --- a/chrome/browser/browser.h +++ b/chrome/browser/browser.h @@ -6,1089 +6,8 @@ #define CHROME_BROWSER_BROWSER_H_ #pragma once -#include -#include -#include -#include - -#include "base/basictypes.h" -#include "base/gtest_prod_util.h" -#include "base/scoped_ptr.h" -#include "base/string16.h" -#include "base/task.h" -#include "chrome/browser/command_updater.h" -#include "chrome/browser/debugger/devtools_toggle_action.h" -#include "chrome/browser/instant/instant_delegate.h" -#include "chrome/browser/prefs/pref_member.h" -#include "chrome/browser/sessions/session_id.h" -#include "chrome/browser/sessions/tab_restore_service_observer.h" -#include "chrome/browser/shell_dialogs.h" -#include "chrome/browser/sync/profile_sync_service_observer.h" -#include "chrome/browser/tabs/tab_handler.h" -#include "chrome/browser/tabs/tab_strip_model_delegate.h" // TODO(beng): remove -#include "chrome/browser/tabs/tab_strip_model_observer.h" // TODO(beng): remove -#include "chrome/browser/tab_contents/page_navigator.h" -#include "chrome/browser/tab_contents/tab_contents_delegate.h" -#include "chrome/browser/toolbar_model.h" -#include "chrome/common/extensions/extension_constants.h" -#include "chrome/common/notification_registrar.h" -#include "chrome/common/page_transition_types.h" -#include "chrome/common/page_zoom.h" -#include "gfx/rect.h" - -class BrowserWindow; -class Extension; -class FindBarController; -class InstantController; -class PrefService; -class Profile; -class SessionStorageNamespace; -class SkBitmap; -class StatusBubble; -class TabNavigation; -class TabStripModel; -namespace gfx { -class Point; -} - -class Browser : public TabHandlerDelegate, - public TabContentsDelegate, - public PageNavigator, - public CommandUpdater::CommandUpdaterDelegate, - public NotificationObserver, - public SelectFileDialog::Listener, - public TabRestoreServiceObserver, - public ProfileSyncServiceObserver, - public InstantDelegate { - public: - // If you change the values in this enum you'll need to update browser_proxy. - // TODO(sky): move into a common place that is referenced by both ui_tests - // and chrome. - enum Type { - TYPE_NORMAL = 1, - TYPE_POPUP = 2, - // The old-style app created via "Create application shortcuts". - TYPE_APP = 4, - // The new-style app created by installing a crx. This kinda needs to be - // separate because we require larger icons and an application name that - // are found in the crx. If we ever decide to create this kind of app - // using some other system (eg some web standard), maybe we should - // generalize this name to TYPE_MULTITAB or something. - TYPE_EXTENSION_APP = 8, - TYPE_APP_POPUP = TYPE_APP | TYPE_POPUP, - TYPE_DEVTOOLS = TYPE_APP | 16, - - // TODO(skerner): crbug/56776: Until the panel UI is complete on all - // platforms, apps that set app.launch.container = "panel" have type - // APP_POPUP. (see Browser::CreateForApp) - // NOTE: TYPE_APP_PANEL is a superset of TYPE_APP_POPUP. - TYPE_APP_PANEL = TYPE_APP | TYPE_POPUP | 32, - TYPE_ANY = TYPE_NORMAL | - TYPE_POPUP | - TYPE_APP | - TYPE_EXTENSION_APP | - TYPE_DEVTOOLS | - TYPE_APP_PANEL - }; - - // Possible elements of the Browser window. - enum WindowFeature { - FEATURE_NONE = 0, - FEATURE_TITLEBAR = 1, - FEATURE_TABSTRIP = 2, - FEATURE_TOOLBAR = 4, - FEATURE_LOCATIONBAR = 8, - FEATURE_BOOKMARKBAR = 16, - FEATURE_INFOBAR = 32, - FEATURE_SIDEBAR = 64, - FEATURE_DOWNLOADSHELF = 128 - }; - - // Maximized state on creation. - enum MaximizedState { - // The maximized state is set to the default, which varies depending upon - // what the user has done. - MAXIMIZED_STATE_DEFAULT, - - // Maximized state is explicitly maximized. - MAXIMIZED_STATE_MAXIMIZED, - - // Maximized state is explicitly not maximized (normal). - MAXIMIZED_STATE_UNMAXIMIZED - }; - - // Constructors, Creation, Showing ////////////////////////////////////////// - - // Creates a new browser of the given |type| and for the given |profile|. The - // Browser has a NULL window after its construction, CreateBrowserWindow must - // be called after configuration for window() to be valid. - // Avoid using this constructor directly if you can use one of the Create*() - // methods below. This applies to almost all non-testing code. - Browser(Type type, Profile* profile); - virtual ~Browser(); - - // Creates a normal tabbed browser with the specified profile. The Browser's - // window is created by this function call. - static Browser* Create(Profile* profile); - - // Like Create, but creates a browser of the specified (popup) type, with the - // specified contents, in a popup window of the specified size/position. - static Browser* CreateForPopup(Type type, Profile* profile, - TabContents* new_contents, - const gfx::Rect& initial_bounds); - - // Like Create, but creates a browser of the specified type. - static Browser* CreateForType(Type type, Profile* profile); - - // Like Create, but creates a toolbar-less "app" window for the specified - // app. |app_name| is required and is used to identify the window to the - // shell. |extension| is optional. If supplied, we create a window with - // a bigger icon and title text, that supports tabs. - static Browser* CreateForApp(const std::string& app_name, - const Extension* extension, - Profile* profile, - bool is_panel); - - // Like Create, but creates a tabstrip-less and toolbar-less - // DevTools "app" window. - static Browser* CreateForDevTools(Profile* profile); - - // Returns the extension app associated with this window, if any. - const Extension* extension_app() { return extension_app_; } - - // Set overrides for the initial window bounds and maximized state. - void set_override_bounds(const gfx::Rect& bounds) { - override_bounds_ = bounds; - } - void set_maximized_state(MaximizedState state) { - maximized_state_ = state; - } - // Return true if the initial window bounds have been overridden. - bool bounds_overridden() const { - return !override_bounds_.IsEmpty(); - } - - // Creates the Browser Window. Prefer to use the static helpers above where - // possible. This does not show the window. You need to call window()->Show() - // to show it. - void CreateBrowserWindow(); - - // Accessors //////////////////////////////////////////////////////////////// - - Type type() const { return type_; } - Profile* profile() const { return profile_; } - const std::vector& user_data_dir_profiles() const; - - // Returns the InstantController or NULL if there is no InstantController for - // this Browser. - InstantController* instant() const { return instant_.get(); } - -#if defined(UNIT_TEST) - // Sets the BrowserWindow. This is intended for testing and generally not - // useful outside of testing. Use CreateBrowserWindow outside of testing, or - // the static convenience methods that create a BrowserWindow for you. - void set_window(BrowserWindow* window) { - DCHECK(!window_); - window_ = window; - } -#endif - - BrowserWindow* window() const { return window_; } - ToolbarModel* toolbar_model() { return &toolbar_model_; } - const SessionID& session_id() const { return session_id_; } - CommandUpdater* command_updater() { return &command_updater_; } - - // Get the FindBarController for this browser, creating it if it does not - // yet exist. - FindBarController* GetFindBarController(); - - // Returns true if a FindBarController exists for this browser. - bool HasFindBarController() const; - - // Setters ///////////////////////////////////////////////////////////////// - - void set_user_data_dir_profiles(const std::vector& profiles); - - // Browser Creation Helpers ///////////////////////////////////////////////// - - // Opens a new window with the default blank tab. - static void OpenEmptyWindow(Profile* profile); - - // Opens a new window with the tabs from |profile|'s TabRestoreService. - static void OpenWindowWithRestoredTabs(Profile* profile); - - // Opens the specified URL in a new browser window in an incognito session. - // If there is already an existing active incognito session for the specified - // |profile|, that session is re-used. - static void OpenURLOffTheRecord(Profile* profile, const GURL& url); - - // Open an application specified by |app_id| in the appropriate launch - // container. |existing_tab| is reused if it is not NULL and the launch - // container is a tab. Returns NULL if the app_id is invalid or if - // ExtensionsService isn't ready/available. - static TabContents* OpenApplication(Profile* profile, - const std::string& app_id, - TabContents* existing_tab); - - // Open |extension| in |container|, using |existing_tab| if not NULL and if - // the correct container type. Returns the TabContents* that was created or - // NULL. - static TabContents* OpenApplication( - Profile* profile, - const Extension* extension, - extension_misc::LaunchContainer container, - TabContents* existing_tab); - - // Opens a new application window for the specified url. If |as_panel| - // is true, the application will be opened as a Browser::Type::APP_PANEL in - // app panel window, otherwise it will be opened as as either - // Browser::Type::APP a.k.a. "thin frame" (if |extension| is NULL) or - // Browser::Type::EXTENSION_APP (if |extension| is non-NULL). - static TabContents* OpenApplicationWindow( - Profile* profile, - const Extension* extension, - extension_misc::LaunchContainer container, - const GURL& url); - - // Open an application for |extension| in a new application window or panel. - static TabContents* OpenApplicationWindow(Profile* profile, GURL& url); - - // Open an application for |extension| in a new application tab, or - // |existing_tab| if not NULL. Returns NULL if there are no appropriate - // existing browser windows for |profile|. - static TabContents* OpenApplicationTab(Profile* profile, - const Extension* extension, - TabContents* existing_tab); - - // Opens a new window and opens the bookmark manager. - static void OpenBookmarkManagerWindow(Profile* profile); - -#if defined(OS_MACOSX) - // Open a new window with history/downloads/help/options (needed on Mac when - // there are no windows). - static void OpenHistoryWindow(Profile* profile); - static void OpenDownloadsWindow(Profile* profile); - static void OpenHelpWindow(Profile* profile); - static void OpenOptionsWindow(Profile* profile); -#endif - - // Opens a window with the extensions tab in it - needed by long-lived - // extensions which may run with no windows open. - static void OpenExtensionsWindow(Profile* profile); - - // State Storage and Retrieval for UI /////////////////////////////////////// - - // Save and restore the window position. - std::string GetWindowPlacementKey() const; - bool ShouldSaveWindowPlacement() const; - void SaveWindowPlacement(const gfx::Rect& bounds, bool maximized); - gfx::Rect GetSavedWindowBounds() const; - bool GetSavedMaximizedState() const; - - // Gets the FavIcon of the page in the selected tab. - SkBitmap GetCurrentPageIcon() const; - - // Gets the title of the window based on the selected tab's title. - string16 GetWindowTitleForCurrentTab() const; - - // Prepares a title string for display (removes embedded newlines, etc). - static void FormatTitleForDisplay(string16* title); - - // OnBeforeUnload handling ////////////////////////////////////////////////// - - // Gives beforeunload handlers the chance to cancel the close. - bool ShouldCloseWindow(); - - bool IsAttemptingToCloseBrowser() const { - return is_attempting_to_close_browser_; - } - - // Invoked when the window containing us is closing. Performs the necessary - // cleanup. - void OnWindowClosing(); - - // In-progress download termination handling ///////////////////////////////// - - // Called when the user has decided whether to proceed or not with the browser - // closure. |cancel_downloads| is true if the downloads should be canceled - // and the browser closed, false if the browser should stay open and the - // downloads running. - void InProgressDownloadResponse(bool cancel_downloads); - - // TabStripModel pass-thrus ///////////////////////////////////////////////// - - TabStripModel* tabstrip_model() const { - // TODO(beng): remove this accessor. It violates google style. - return tab_handler_->GetTabStripModel(); - } - - int tab_count() const; - int selected_index() const; - int GetIndexOfController(const NavigationController* controller) const; - TabContents* GetTabContentsAt(int index) const; - TabContents* GetSelectedTabContents() const; - void SelectTabContentsAt(int index, bool user_gesture); - void CloseAllTabs(); - - // Tab adding/showing functions ///////////////////////////////////////////// - - // Returns the index to insert a tab at during session restore and startup. - // |relative_index| gives the index of the url into the number of tabs that - // are going to be opened. For example, if three urls are passed in on the - // command line this is invoked three times with the values 0, 1 and 2. - int GetIndexForInsertionDuringRestore(int relative_index); - - // Adds a selected tab with the specified URL and transition, returns the - // created TabContents. - TabContents* AddSelectedTabWithURL(const GURL& url, - PageTransition::Type transition); - - // Add a new tab, given a TabContents. A TabContents appropriate to - // display the last committed entry is created and returned. - TabContents* AddTab(TabContents* tab_contents, PageTransition::Type type); - - // Add a tab with its session history restored from the SessionRestore - // system. If select is true, the tab is selected. |tab_index| gives the index - // to insert the tab at. |selected_navigation| is the index of the - // TabNavigation in |navigations| to select. If |extension_app_id| is - // non-empty the tab is an app tab and |extension_app_id| is the id of the - // extension. If |pin| is true and |tab_index|/ is the last pinned tab, then - // the newly created tab is pinned. If |from_last_session| is true, - // |navigations| are from the previous session. - TabContents* AddRestoredTab(const std::vector& navigations, - int tab_index, - int selected_navigation, - const std::string& extension_app_id, - bool select, - bool pin, - bool from_last_session, - SessionStorageNamespace* storage_namespace); - // Creates a new tab with the already-created TabContents 'new_contents'. - // The window for the added contents will be reparented correctly when this - // method returns. If |disposition| is NEW_POPUP, |pos| should hold the - // initial position. - void AddTabContents(TabContents* new_contents, - WindowOpenDisposition disposition, - const gfx::Rect& initial_pos, - bool user_gesture); - void CloseTabContents(TabContents* contents); - - // Show a dialog with HTML content. |delegate| contains a pointer to the - // delegate who knows how to display the dialog (which file URL and JSON - // string input to use during initialization). |parent_window| is the window - // that should be parent of the dialog, or NULL for the default. - void BrowserShowHtmlDialog(HtmlDialogUIDelegate* delegate, - gfx::NativeWindow parent_window); - - // Called when a popup select is about to be displayed. - void BrowserRenderWidgetShowing(); - - // Notification that some of our content has changed size as - // part of an animation. - void ToolbarSizeChanged(bool is_animating); - - // Replaces the state of the currently selected tab with the session - // history restored from the SessionRestore system. - void ReplaceRestoredTab( - const std::vector& navigations, - int selected_navigation, - bool from_last_session, - const std::string& extension_app_id, - SessionStorageNamespace* session_storage_namespace); - - // Navigate to an index in the tab history, opening a new tab depending on the - // disposition. - bool NavigateToIndexWithDisposition(int index, WindowOpenDisposition disp); - - // Show a given a URL. If a tab with the same URL (ignoring the ref) is - // already visible in this browser, it becomes selected. Otherwise a new tab - // is created. - void ShowSingletonTab(const GURL& url); - - // Update commands whose state depends on whether the window is in fullscreen - // mode. This is a public function because on Linux, fullscreen mode is an - // async call to X. Once we get the fullscreen callback, the browser window - // will call this method. - void UpdateCommandsForFullscreenMode(bool is_fullscreen); - - // Assorted browser commands //////////////////////////////////////////////// - - // NOTE: Within each of the following sections, the IDs are ordered roughly by - // how they appear in the GUI/menus (left to right, top to bottom, etc.). - - // Navigation commands - void GoBack(WindowOpenDisposition disposition); - void GoForward(WindowOpenDisposition disposition); - void Reload(WindowOpenDisposition disposition); - void ReloadIgnoringCache(WindowOpenDisposition disposition); // Shift-reload. - void Home(WindowOpenDisposition disposition); - void OpenCurrentURL(); - void Stop(); - // Window management commands - void NewWindow(); - void NewIncognitoWindow(); - void CloseWindow(); - void NewTab(); - void CloseTab(); - void SelectNextTab(); - void SelectPreviousTab(); - void OpenTabpose(); - void MoveTabNext(); - void MoveTabPrevious(); - void SelectNumberedTab(int index); - void SelectLastTab(); - void DuplicateTab(); - void WriteCurrentURLToClipboard(); - void ConvertPopupToTabbedBrowser(); - // In kiosk mode, the first toggle is valid, the rest is discarded. - void ToggleFullscreenMode(); - void Exit(); -#if defined(OS_CHROMEOS) - void ToggleCompactNavigationBar(); - void Search(); -#endif - - // Page-related commands - void BookmarkCurrentPage(); - void SavePage(); - void ViewSource(); - void ShowFindBar(); - - // Returns true if the Browser supports the specified feature. The value of - // this varies during the lifetime of the browser. For example, if the window - // is fullscreen this may return a different value. If you only care about - // whether or not it's possible for the browser to support a particular - // feature use |CanSupportWindowFeature|. - bool SupportsWindowFeature(WindowFeature feature) const; - - // Returns true if the Browser can support the specified feature. See comment - // in |SupportsWindowFeature| for details on this. - bool CanSupportWindowFeature(WindowFeature feature) const; - -// TODO(port): port these, and re-merge the two function declaration lists. - // Page-related commands. - void Print(); - void EmailPageLocation(); - void ToggleEncodingAutoDetect(); - void OverrideEncoding(int encoding_id); - - // Clipboard commands - void Cut(); - void Copy(); - void Paste(); - - // Find-in-page - void Find(); - void FindNext(); - void FindPrevious(); - - // Zoom - void Zoom(PageZoom::Function zoom_function); - - // Focus various bits of UI - void FocusToolbar(); - void FocusLocationBar(); // Also selects any existing text. - void FocusSearch(); - void FocusAppMenu(); - void FocusBookmarksToolbar(); - void FocusChromeOSStatus(); - void FocusNextPane(); - void FocusPreviousPane(); - - // Show various bits of UI - void OpenFile(); - void OpenCreateShortcutsDialog(); - void ToggleDevToolsWindow(DevToolsToggleAction action); - void OpenTaskManager(); - void OpenBugReportDialog(); - - void ToggleBookmarkBar(); - - void OpenBookmarkManager(); - void ShowAppMenu(); - void ShowBookmarkManagerTab(); - void ShowHistoryTab(); - void ShowDownloadsTab(); - void ShowExtensionsTab(); - void ShowAboutConflictsTab(); - void ShowBrokenPageTab(TabContents* contents); - void ShowOptionsTab(const std::string& sub_page); - void OpenClearBrowsingDataDialog(); - void OpenOptionsDialog(); - void OpenKeywordEditor(); - void OpenPasswordManager(); - void OpenSyncMyBookmarksDialog(); -#if defined(ENABLE_REMOTING) - void OpenRemotingSetupDialog(); -#endif - void OpenImportSettingsDialog(); - void OpenAboutChromeDialog(); - void OpenUpdateChromeDialog(); - void OpenHelpTab(); - // Used by the "Get themes" link in the options dialog. - void OpenThemeGalleryTabAndActivate(); - void OpenAutoFillHelpTabAndActivate(); - void OpenPrivacyDashboardTabAndActivate(); - void OpenSearchEngineOptionsDialog(); -#if defined(OS_CHROMEOS) - void OpenSystemOptionsDialog(); - void OpenInternetOptionsDialog(); - void OpenLanguageOptionsDialog(); - void OpenSystemTabAndActivate(); - void OpenMobilePlanTabAndActivate(); -#endif - void OpenPluginsTabAndActivate(); - - virtual void UpdateDownloadShelfVisibility(bool visible); - - // Overridden from TabStripModelDelegate: - virtual bool UseVerticalTabs() const; - - ///////////////////////////////////////////////////////////////////////////// - - // Sets the value of homepage related prefs to new values. Since we do not - // want to change these values for existing users, we can not change the - // default values under RegisterUserPrefs. Also if user already has an - // existing profile we do not want to override those preferences so we only - // set new values if they have not been set already. This method gets called - // during First Run. - static void SetNewHomePagePrefs(PrefService* prefs); - - static void RegisterPrefs(PrefService* prefs); - static void RegisterUserPrefs(PrefService* prefs); - - // Helper function to run unload listeners on a TabContents. - static bool RunUnloadEventsHelper(TabContents* contents); - - // Returns the Browser which contains the tab with the given - // NavigationController, also filling in |index| (if valid) with the tab's - // index in the tab strip. - // Returns NULL if not found. - // This call is O(N) in the number of tabs. - static Browser* GetBrowserForController( - const NavigationController* controller, int* index); - - // Retrieve the last active tabbed browser with a profile matching |profile|. - static Browser* GetTabbedBrowser(Profile* profile, bool match_incognito); - - // Retrieve the last active tabbed browser with a profile matching |profile|. - // Creates a new Browser if none are available. - static Browser* GetOrCreateTabbedBrowser(Profile* profile); - - // Calls ExecuteCommandWithDisposition with the given disposition. - void ExecuteCommandWithDisposition(int id, WindowOpenDisposition); - - // Returns whether the |id| is a reserved command, whose keyboard shortcuts - // should not be sent to the renderer. - bool IsReservedCommand(int id); - - // Sets if command execution shall be blocked. If |block| is true then - // following calls to ExecuteCommand() or ExecuteCommandWithDisposition() - // method will not execute the command, and the last blocked command will be - // recorded for retrieval. - void SetBlockCommandExecution(bool block); - - // Gets the last blocked command after calling SetBlockCommandExecution(true). - // Returns the command id or -1 if there is no command blocked. The - // disposition type of the command will be stored in |*disposition| if it's - // not null. - int GetLastBlockedCommand(WindowOpenDisposition* disposition); - - // Called by browser::Navigate() when a navigation has occurred in a tab in - // this Browser. Updates the UI for the start of this navigation. - void UpdateUIForNavigationInTab(TabContents* contents, - PageTransition::Type transition, - bool user_initiated); - - // Called by browser::Navigate() to retrieve the home page if no URL is - // specified. - GURL GetHomePage() const; - - // Interface implementations //////////////////////////////////////////////// - - // Overridden from PageNavigator: - virtual void OpenURL(const GURL& url, const GURL& referrer, - WindowOpenDisposition disposition, - PageTransition::Type transition); - - // Overridden from CommandUpdater::CommandUpdaterDelegate: - virtual void ExecuteCommand(int id); - - // Overridden from TabRestoreServiceObserver: - virtual void TabRestoreServiceChanged(TabRestoreService* service); - virtual void TabRestoreServiceDestroyed(TabRestoreService* service); - - - // Overridden from TabHandlerDelegate: - virtual Profile* GetProfile() const; - virtual Browser* AsBrowser(); - - // Overridden from TabStripModelDelegate: - virtual TabContents* AddBlankTab(bool foreground); - virtual TabContents* AddBlankTabAt(int index, bool foreground); - virtual Browser* CreateNewStripWithContents(TabContents* detached_contents, - const gfx::Rect& window_bounds, - const DockInfo& dock_info, - bool maximize); - virtual void ContinueDraggingDetachedTab(TabContents* contents, - const gfx::Rect& window_bounds, - const gfx::Rect& tab_bounds); - virtual int GetDragActions() const; - // Construct a TabContents for a given URL, profile and transition type. - // If instance is not null, its process will be used to render the tab. - virtual TabContents* CreateTabContentsForURL(const GURL& url, - const GURL& referrer, - Profile* profile, - PageTransition::Type transition, - bool defer_load, - SiteInstance* instance) const; - virtual bool CanDuplicateContentsAt(int index); - virtual void DuplicateContentsAt(int index); - virtual void CloseFrameAfterDragSession(); - virtual void CreateHistoricalTab(TabContents* contents); - virtual bool RunUnloadListenerBeforeClosing(TabContents* contents); - virtual bool CanCloseContentsAt(int index); - virtual bool CanBookmarkAllTabs() const; - virtual void BookmarkAllTabs(); - virtual bool CanCloseTab() const; - virtual void ToggleUseVerticalTabs(); - virtual bool CanRestoreTab(); - virtual void RestoreTab(); - virtual bool LargeIconsPermitted() const; - - // Overridden from TabStripModelObserver: - virtual void TabInsertedAt(TabContents* contents, - int index, - bool foreground); - virtual void TabClosingAt(TabStripModel* tab_strip_model, - TabContents* contents, - int index); - virtual void TabDetachedAt(TabContents* contents, int index); - virtual void TabDeselectedAt(TabContents* contents, int index); - virtual void TabSelectedAt(TabContents* old_contents, - TabContents* new_contents, - int index, - bool user_gesture); - virtual void TabMoved(TabContents* contents, - int from_index, - int to_index); - virtual void TabReplacedAt(TabContents* old_contents, - TabContents* new_contents, - int index); - virtual void TabPinnedStateChanged(TabContents* contents, int index); - virtual void TabStripEmpty(); - - private: - FRIEND_TEST_ALL_PREFIXES(BrowserTest, NoTabsInPopups); - - // Used to describe why a tab is being detached. This is used by - // TabDetachedAtImpl. - enum DetachType { - // Result of TabDetachedAt. - DETACH_TYPE_DETACH, - - // Result of TabReplacedAt. - DETACH_TYPE_REPLACE, - - // Result of the tab strip not having any significant tabs. - DETACH_TYPE_EMPTY - }; - - // Overridden from TabContentsDelegate: - virtual void OpenURLFromTab(TabContents* source, - const GURL& url, - const GURL& referrer, - WindowOpenDisposition disposition, - PageTransition::Type transition); - virtual void NavigationStateChanged(const TabContents* source, - unsigned changed_flags); - virtual void AddNewContents(TabContents* source, - TabContents* new_contents, - WindowOpenDisposition disposition, - const gfx::Rect& initial_pos, - bool user_gesture); - virtual void ActivateContents(TabContents* contents); - virtual void DeactivateContents(TabContents* contents); - virtual void LoadingStateChanged(TabContents* source); - virtual void CloseContents(TabContents* source); - virtual void MoveContents(TabContents* source, const gfx::Rect& pos); - virtual void DetachContents(TabContents* source); - virtual bool IsPopup(const TabContents* source) const; - virtual bool CanReloadContents(TabContents* source) const; - virtual void ToolbarSizeChanged(TabContents* source, bool is_animating); - virtual void URLStarredChanged(TabContents* source, bool starred); - virtual void UpdateTargetURL(TabContents* source, const GURL& url); - virtual void ContentsMouseEvent( - TabContents* source, const gfx::Point& location, bool motion); - virtual void ContentsZoomChange(bool zoom_in); - virtual void OnContentSettingsChange(TabContents* source); - virtual void SetTabContentBlocked(TabContents* contents, bool blocked); - virtual void TabContentsFocused(TabContents* tab_content); - virtual bool TakeFocus(bool reverse); - virtual bool IsApplication() const; - virtual void ConvertContentsToApplication(TabContents* source); - virtual bool ShouldDisplayURLField(); - virtual gfx::Rect GetRootWindowResizerRect() const; - virtual void ShowHtmlDialog(HtmlDialogUIDelegate* delegate, - gfx::NativeWindow parent_window); - virtual void BeforeUnloadFired(TabContents* source, - bool proceed, - bool* proceed_to_fire_unload); - virtual void SetFocusToLocationBar(bool select_all); - virtual void RenderWidgetShowing(); - virtual int GetExtraRenderViewHeight() const; - virtual void OnStartDownload(DownloadItem* download, TabContents* tab); - virtual void ConfirmSetDefaultSearchProvider( - TabContents* tab_contents, - TemplateURL* template_url, - TemplateURLModel* template_url_model); - virtual void ConfirmAddSearchProvider(const TemplateURL* template_url, - Profile* profile); - virtual void ShowPageInfo(Profile* profile, - const GURL& url, - const NavigationEntry::SSLStatus& ssl, - bool show_history); - virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, - bool* is_keyboard_shortcut); - virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event); - virtual void ShowRepostFormWarningDialog(TabContents* tab_contents); - virtual void ShowContentSettingsWindow(ContentSettingsType content_type); - virtual void ShowCollectedCookiesDialog(TabContents* tab_contents); - virtual bool ShouldAddNavigationToHistory( - const history::HistoryAddPageArgs& add_page_args, - NavigationType::Type navigation_type); - virtual void OnDidGetApplicationInfo(TabContents* tab_contents, - int32 page_id); - virtual void ContentRestrictionsChanged(TabContents* source); - - // Overridden from SelectFileDialog::Listener: - virtual void FileSelected(const FilePath& path, int index, void* params); - - // Overridden from NotificationObserver: - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); - - // Overridden from ProfileSyncServiceObserver: - virtual void OnStateChanged(); - - // Overriden from InstantDelegate: - virtual void ShowInstant(TabContents* preview_contents); - virtual void HideInstant(); - virtual void CommitInstant(TabContents* preview_contents); - virtual void SetSuggestedText(const string16& text); - virtual gfx::Rect GetInstantBounds(); - - // Command and state updating /////////////////////////////////////////////// - - // Initialize state for all browser commands. - void InitCommandState(); - - // Update commands whose state depends on the tab's state. - void UpdateCommandsForTabState(); - - // Updates commands when the content's restrictions change. - void UpdateCommandsForContentRestrictionState(); - - // Updates commands for enabling developer tools. - void UpdateCommandsForDevTools(); - - // Updates the printing command state. - void UpdatePrintingState(int content_restrictions); - - // Ask the Reload/Stop button to change its icon, and update the Stop command - // state. |is_loading| is true if the current TabContents is loading. - // |force| is true if the button should change its icon immediately. - void UpdateReloadStopState(bool is_loading, bool force); - - // UI update coalescing and handling //////////////////////////////////////// - - // Asks the toolbar (and as such the location bar) to update its state to - // reflect the current tab's current URL, security state, etc. - // If |should_restore_state| is true, we're switching (back?) to this tab and - // should restore any previous location bar state (such as user editing) as - // well. - void UpdateToolbar(bool should_restore_state); - - // Does one or both of the following for each bit in |changed_flags|: - // . If the update should be processed immediately, it is. - // . If the update should processed asynchronously (to avoid lots of ui - // updates), then scheduled_updates_ is updated for the |source| and update - // pair and a task is scheduled (assuming it isn't running already) - // that invokes ProcessPendingUIUpdates. - void ScheduleUIUpdate(const TabContents* source, unsigned changed_flags); - - // Processes all pending updates to the UI that have been scheduled by - // ScheduleUIUpdate in scheduled_updates_. - void ProcessPendingUIUpdates(); - - // Removes all entries from scheduled_updates_ whose source is contents. - void RemoveScheduledUpdatesFor(TabContents* contents); - - // Getters for UI /////////////////////////////////////////////////////////// - - // TODO(beng): remove, and provide AutomationProvider a better way to access - // the LocationBarView's edit. - friend class AutomationProvider; - friend class TestingAutomationProvider; - - // Returns the StatusBubble from the current toolbar. It is possible for - // this to return NULL if called before the toolbar has initialized. - // TODO(beng): remove this. - StatusBubble* GetStatusBubble(); - - // Session restore functions //////////////////////////////////////////////// - - // Notifies the history database of the index for all tabs whose index is - // >= index. - void SyncHistoryWithTabs(int index); - - // OnBeforeUnload handling ////////////////////////////////////////////////// - - typedef std::set UnloadListenerSet; - - // Processes the next tab that needs it's beforeunload/unload event fired. - void ProcessPendingTabs(); - - // Whether we've completed firing all the tabs' beforeunload/unload events. - bool HasCompletedUnloadProcessing() const; - - // Clears all the state associated with processing tabs' beforeunload/unload - // events since the user cancelled closing the window. - void CancelWindowClose(); - - // Removes |tab| from the passed |set|. - // Returns whether the tab was in the set in the first place. - // TODO(beng): this method needs a better name! - bool RemoveFromSet(UnloadListenerSet* set, TabContents* tab); - - // Cleans up state appropriately when we are trying to close the browser and - // the tab has finished firing its unload handler. We also use this in the - // cases where a tab crashes or hangs even if the beforeunload/unload haven't - // successfully fired. - void ClearUnloadState(TabContents* tab); - - // In-progress download termination handling ///////////////////////////////// - - // Called when the window is closing to check if potential in-progress - // downloads should prevent it from closing. - // Returns true if the window can close, false otherwise. - bool CanCloseWithInProgressDownloads(); - - // Assorted utility functions /////////////////////////////////////////////// - - // Checks whether |source| is about to navigate across extension extents, and - // if so, navigates in the correct window. For example if this is a normal - // browser and we're about to navigate into an extent, this method will - // navigate the app's window instead. If we're in an app window and - // navigating out of the app, this method will find and navigate a normal - // browser instead. - // - // Returns true if the navigation was handled, eg, it was opened in some other - // browser. - // - // Returns false if it was not handled. In this case, the method may also - // modify |disposition| to a more suitable value. - bool HandleCrossAppNavigation(TabContents* source, - const GURL& url, - const GURL& referrer, - WindowOpenDisposition *disposition, - PageTransition::Type transition); - - // Shows the Find Bar, optionally selecting the next entry that matches the - // existing search string for that Tab. |forward_direction| controls the - // search direction. - void FindInPage(bool find_next, bool forward_direction); - - // Closes the frame. - // TODO(beng): figure out if we need this now that the frame itself closes - // after a return to the message loop. - void CloseFrame(); - - void TabDetachedAtImpl(TabContents* contents, int index, DetachType type); - - // Create a preference dictionary for the provided application name. This is - // done only once per application name / per session. - static void RegisterAppPrefs(const std::string& app_name); - - // Shared code between Reload() and ReloadIgnoringCache(). - void ReloadInternal(WindowOpenDisposition disposition, bool ignore_cache); - - // Return true if the window dispositions means opening a new tab. - bool ShouldOpenNewTabForWindowDisposition(WindowOpenDisposition disposition); - - // Depending on the disposition, return the current tab or a clone of the - // current tab. - TabContents* GetOrCloneTabForDisposition(WindowOpenDisposition disposition); - - // Sets the insertion policy of the tabstrip based on whether vertical tabs - // are enabled. - void UpdateTabStripModelInsertionPolicy(); - - // Invoked when the use vertical tabs preference changes. Resets the insertion - // policy of the tab strip model and notifies the window. - void UseVerticalTabsChanged(); - - // Implementation of SupportsWindowFeature and CanSupportWindowFeature. If - // |check_fullscreen| is true, the set of features reflect the actual state of - // the browser, otherwise the set of features reflect the possible state of - // the browser. - bool SupportsWindowFeatureImpl(WindowFeature feature, - bool check_fullscreen) const; - - // Determines if closing of browser can really be permitted after normal - // sequence of downloads and unload handlers have given the go-ahead to close. - // It is called from ShouldCloseWindow. It checks with - // TabCloseableStateWatcher to confirm if browser can really be closed. - // Appropriate action is taken by watcher as it sees fit. - // If watcher denies closing of browser, CancelWindowClose is called to - // cancel closing of window. - bool IsClosingPermitted(); - - // Commits the current instant, returning true on success. This is intended - // for use from OpenCurrentURL. - bool OpenInstant(WindowOpenDisposition disposition); - - // If this browser should have instant one is created, otherwise does nothing. - void CreateInstantIfNecessary(); - - // Data members ///////////////////////////////////////////////////////////// - - NotificationRegistrar registrar_; - - // This Browser's type. - const Type type_; - - // This Browser's profile. - Profile* const profile_; - - // This Browser's window. - BrowserWindow* window_; - - // This Browser's current TabHandler. - scoped_ptr tab_handler_; - - // The CommandUpdater that manages the browser window commands. - CommandUpdater command_updater_; - - // An optional application name which is used to retrieve and save window - // positions. - std::string app_name_; - - // Unique identifier of this browser for session restore. This id is only - // unique within the current session, and is not guaranteed to be unique - // across sessions. - const SessionID session_id_; - - // The model for the toolbar view. - ToolbarModel toolbar_model_; - - // UI update coalescing and handling //////////////////////////////////////// - - typedef std::map UpdateMap; - - // Maps from TabContents to pending UI updates that need to be processed. - // We don't update things like the URL or tab title right away to avoid - // flickering and extra painting. - // See ScheduleUIUpdate and ProcessPendingUIUpdates. - UpdateMap scheduled_updates_; - - // The following factory is used for chrome update coalescing. - ScopedRunnableMethodFactory chrome_updater_factory_; - - // OnBeforeUnload handling ////////////////////////////////////////////////// - - // Tracks tabs that need there beforeunload event fired before we can - // close the browser. Only gets populated when we try to close the browser. - UnloadListenerSet tabs_needing_before_unload_fired_; - - // Tracks tabs that need there unload event fired before we can - // close the browser. Only gets populated when we try to close the browser. - UnloadListenerSet tabs_needing_unload_fired_; - - // Whether we are processing the beforeunload and unload events of each tab - // in preparation for closing the browser. - bool is_attempting_to_close_browser_; - - // In-progress download termination handling ///////////////////////////////// - - enum CancelDownloadConfirmationState { - NOT_PROMPTED, // We have not asked the user. - WAITING_FOR_RESPONSE, // We have asked the user and have not received a - // reponse yet. - RESPONSE_RECEIVED // The user was prompted and made a decision already. - }; - - // State used to figure-out whether we should prompt the user for confirmation - // when the browser is closed with in-progress downloads. - CancelDownloadConfirmationState cancel_download_confirmation_state_; - - ///////////////////////////////////////////////////////////////////////////// - - // Override values for the bounds of the window and its maximized state. - // These are supplied by callers that don't want to use the default values. - // The default values are typically loaded from local state (last session), - // obtained from the last window of the same type, or obtained from the - // shell shortcut's startup info. - gfx::Rect override_bounds_; - MaximizedState maximized_state_; - - // The following factory is used to close the frame at a later time. - ScopedRunnableMethodFactory method_factory_; - - // The Find Bar. This may be NULL if there is no Find Bar, and if it is - // non-NULL, it may or may not be visible. - scoped_ptr find_bar_controller_; - - // Dialog box used for opening and saving files. - scoped_refptr select_file_dialog_; - - // Keep track of the encoding auto detect pref. - BooleanPrefMember encoding_auto_detect_; - - // Keep track of the printing enabled pref. - BooleanPrefMember printing_enabled_; - - // Keep track of the development tools disabled pref. - BooleanPrefMember dev_tools_disabled_; - - // Keep track of when instant enabled changes. - BooleanPrefMember instant_enabled_; - - // Indicates if command execution is blocked. - bool block_command_execution_; - - // Stores the last blocked command id when |block_command_execution_| is true. - int last_blocked_command_id_; - - // Stores the disposition type of the last blocked command. - WindowOpenDisposition last_blocked_command_disposition_; - - // Different types of action when web app info is available. - // OnDidGetApplicationInfo uses this to dispatch calls. - enum WebAppAction { - NONE, // No action at all. - CREATE_SHORTCUT, // Bring up create application shortcut dialog. - UPDATE_SHORTCUT // Update icon for app shortcut. - }; - - // Which deferred action to perform when OnDidGetApplicationInfo is notified - // from a TabContents. Currently, only one pending action is allowed. - WebAppAction pending_web_app_action_; - - // The extension app associated with this window, if any. - const Extension* extension_app_; - - // Tracks the display mode of the tabstrip. - mutable BooleanPrefMember use_vertical_tabs_; - - // The profile's tab restore service. The service is owned by the profile, - // and we install ourselves as an observer. - TabRestoreService* tab_restore_service_; - - scoped_ptr instant_; - - DISALLOW_COPY_AND_ASSIGN(Browser); -}; +#include "chrome/browser/ui/browser.h" +// TODO(beng): remove this file once all includes have been updated. #endif // CHROME_BROWSER_BROWSER_H_ + diff --git a/chrome/browser/browser_window.h b/chrome/browser/browser_window.h index d45f2c1..0b93616 100644 --- a/chrome/browser/browser_window.h +++ b/chrome/browser/browser_window.h @@ -6,379 +6,8 @@ #define CHROME_BROWSER_BROWSER_WINDOW_H_ #pragma once -#include "chrome/browser/tab_contents/navigation_entry.h" -#include "chrome/common/content_settings_types.h" -#include "gfx/native_widget_types.h" - -class Browser; -class BrowserWindowTesting; -class DownloadShelf; -class FindBar; -class GURL; -class HtmlDialogUIDelegate; -class LocationBar; -class Profile; -class StatusBubble; -class TabContents; -class TemplateURL; -class TemplateURLModel; -#if !defined(OS_MACOSX) -class ToolbarView; -#endif -struct NativeWebKeyboardEvent; - -namespace gfx { -class Rect; -} - -namespace views { -class Window; -} - -//////////////////////////////////////////////////////////////////////////////// -// BrowserWindow interface -// An interface implemented by the "view" of the Browser window. -// -// NOTE: All getters may return NULL. -class BrowserWindow { - public: - // Show the window, or activates it if it's already visible. - virtual void Show() = 0; - - // Sets the window's size and position to the specified values. - virtual void SetBounds(const gfx::Rect& bounds) = 0; - - // Closes the frame as soon as possible. If the frame is not in a drag - // session, it will close immediately; otherwise, it will move offscreen (so - // events are still fired) until the drag ends, then close. This assumes - // that the Browser is not immediately destroyed, but will be eventually - // destroyed by other means (eg, the tab strip going to zero elements). - // Bad things happen if the Browser dtor is called directly as a result of - // invoking this method. - virtual void Close() = 0; - - // Activates (brings to front) the window. Restores the window from minimized - // state if necessary. - virtual void Activate() = 0; - - // Deactivates the window, making the next window in the Z order the active - // window. - virtual void Deactivate() = 0; - - // Returns true if the window is currently the active/focused window. - virtual bool IsActive() const = 0; - - // Flashes the taskbar item associated with this frame. - virtual void FlashFrame() = 0; - - // Return a platform dependent identifier for this frame. On Windows, this - // returns an HWND. - virtual gfx::NativeWindow GetNativeHandle() = 0; - - // Returns a pointer to the testing interface to the Browser window, or NULL - // if there is none. - virtual BrowserWindowTesting* GetBrowserWindowTesting() = 0; - - // Return the status bubble associated with the frame - virtual StatusBubble* GetStatusBubble() = 0; - - // Inform the receiving frame that an animation has progressed in the - // selected tab. - // TODO(beng): Remove. Infobars/Boomarks bars should talk directly to - // BrowserView. - virtual void SelectedTabToolbarSizeChanged(bool is_animating) = 0; - - // Inform the frame that the selected tab favicon or title has changed. Some - // frames may need to refresh their title bar. - virtual void UpdateTitleBar() = 0; - - // Invoked when the visibility of the bookmark bar. - // NOTE: this is NOT sent when the user toggles the visibility of this, - // but rather when the user transitions from a page that forces - // it to be visibile to one that doesn't have it visible (or - // vice-versa). - // TODO(sky): see about routing visibility pref changing through here too. - virtual void ShelfVisibilityChanged() = 0; - - // Inform the frame that the dev tools window for the selected tab has - // changed. - virtual void UpdateDevTools() = 0; - - // Update any loading animations running in the window. |should_animate| is - // true if there are tabs loading and the animations should continue, false - // if there are no active loads and the animations should end. - virtual void UpdateLoadingAnimations(bool should_animate) = 0; - - // Sets the starred state for the current tab. - virtual void SetStarredState(bool is_starred) = 0; - - // Returns the nonmaximized bounds of the frame (even if the frame is - // currently maximized or minimized) in terms of the screen coordinates. - virtual gfx::Rect GetRestoredBounds() const = 0; - - // TODO(beng): REMOVE? - // Returns true if the frame is maximized (aka zoomed). - virtual bool IsMaximized() const = 0; - - // Accessors for fullscreen mode state. - virtual void SetFullscreen(bool fullscreen) = 0; - virtual bool IsFullscreen() const = 0; - - // Returns true if the fullscreen bubble is visible. - virtual bool IsFullscreenBubbleVisible() const = 0; - - // Returns the location bar. - virtual LocationBar* GetLocationBar() const = 0; - - // Tries to focus the location bar. Clears the window focus (to avoid - // inconsistent state) if this fails. - virtual void SetFocusToLocationBar(bool select_all) = 0; - - // Informs the view whether or not a load is in progress for the current tab. - // The view can use this notification to update the reload/stop button. - virtual void UpdateReloadStopState(bool is_loading, bool force) = 0; - - // Updates the toolbar with the state for the specified |contents|. - virtual void UpdateToolbar(TabContents* contents, - bool should_restore_state) = 0; - - // Focuses the toolbar (for accessibility). - virtual void FocusToolbar() = 0; - - // Focuses the app menu like it was a menu bar. - // - // Not used on the Mac, which has a "normal" menu bar. - virtual void FocusAppMenu() = 0; - - // Focuses the bookmarks toolbar (for accessibility). - virtual void FocusBookmarksToolbar() = 0; - - // Focuses the Chrome OS status view (for accessibility). - virtual void FocusChromeOSStatus() = 0; - - // Moves keyboard focus to the next pane. - virtual void RotatePaneFocus(bool forwards) = 0; - - // Returns whether the bookmark bar is visible or not. - virtual bool IsBookmarkBarVisible() const = 0; - - // Returns whether the bookmark bar is animating or not. - virtual bool IsBookmarkBarAnimating() const = 0; - - // Returns whether the tool bar is visible or not. - virtual bool IsToolbarVisible() const = 0; - - // Returns the rect where the resize corner should be drawn by the render - // widget host view (on top of what the renderer returns). We return an empty - // rect to identify that there shouldn't be a resize corner (in the cases - // where we take care of it ourselves at the browser level). - virtual gfx::Rect GetRootWindowResizerRect() const = 0; - - // Tells the frame not to render as inactive until the next activation change. - // This is required on Windows when dropdown selects are shown to prevent the - // select from deactivating the browser frame. A stub implementation is - // provided here since the functionality is Windows-specific. - virtual void DisableInactiveFrame() {} - - // Shows a confirmation dialog box for setting the default search engine - // described by |template_url|. Takes ownership of |template_url|. - virtual void ConfirmSetDefaultSearchProvider( - TabContents* tab_contents, - TemplateURL* template_url, - TemplateURLModel* template_url_model) { - // TODO(levin): Implement this for non-Windows platforms and make it pure. - } - - // Shows a confirmation dialog box for adding a search engine described by - // |template_url|. Takes ownership of |template_url|. - virtual void ConfirmAddSearchProvider(const TemplateURL* template_url, - Profile* profile) = 0; - - // Shows or hides the bookmark bar depending on its current visibility. - virtual void ToggleBookmarkBar() = 0; - - // Shows the About Chrome dialog box. - virtual views::Window* ShowAboutChromeDialog() = 0; - - // Shows the Update Recommended dialog box. - virtual void ShowUpdateChromeDialog() = 0; - - // Shows the Task manager. - virtual void ShowTaskManager() = 0; - - // Shows the Bookmark bubble. |url| is the URL being bookmarked, - // |already_bookmarked| is true if the url is already bookmarked. - virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked) = 0; - - // Whether or not the shelf view is visible. - virtual bool IsDownloadShelfVisible() const = 0; - - // Returns the DownloadShelf. - virtual DownloadShelf* GetDownloadShelf() = 0; - - // Shows the Report a Bug dialog box. - virtual void ShowReportBugDialog() = 0; - - // Shows the Clear Browsing Data dialog box. - virtual void ShowClearBrowsingDataDialog() = 0; - - // Shows the Import Bookmarks & Settings dialog box. - virtual void ShowImportDialog() = 0; - - // Shows the Search Engines dialog box. - virtual void ShowSearchEnginesDialog() = 0; - - // Shows the Password Manager dialog box. - virtual void ShowPasswordManager() = 0; - - // Shows the repost form confirmation dialog box. - virtual void ShowRepostFormWarningDialog(TabContents* tab_contents) = 0; - - // Shows the Content Settings dialog box. - virtual void ShowContentSettingsWindow(ContentSettingsType content_type, - Profile* profile) = 0; - - // Shows the collected cookies dialog box. - virtual void ShowCollectedCookiesDialog(TabContents* tab_contents) = 0; - - // Shows a dialog to the user that something is wrong with the profile. - // |message_id| is the ID for a string in the string table which will be - // displayed in the dialog. - virtual void ShowProfileErrorDialog(int message_id) = 0; - - // Show the bubble that indicates to the user that a theme is being installed. - virtual void ShowThemeInstallBubble() = 0; - - // Shows the confirmation dialog box warning that the browser is closing with - // in-progress downloads. - // This method should call Browser::InProgressDownloadResponse once the user - // has confirmed. - virtual void ConfirmBrowserCloseWithPendingDownloads() = 0; - - // Shows a dialog box with HTML content, e.g. for Gears. |parent_window| is - // the window the dialog should be opened modal to and is a native window - // handle. - virtual void ShowHTMLDialog(HtmlDialogUIDelegate* delegate, - gfx::NativeWindow parent_window) = 0; - - // Asks the window to continue a drag operation begun in a different browser - // window. |tab_bounds| are the bounds of the Tab view that was dragged from - // the source window, in screen coordinates. The corresponding Tab view in - // this new window will be positioned at these bounds for a seamless - // appearance. - virtual void ContinueDraggingDetachedTab(const gfx::Rect& tab_bounds) {} - - // BrowserThemeProvider calls this when a user has changed his or her theme, - // indicating that it's time to redraw everything. - virtual void UserChangedTheme() = 0; - - // Get extra vertical height that the render view should add to its requests - // to webkit. This can help prevent sending extraneous layout/repaint requests - // when the delegate is in the process of resizing the tab contents view (e.g. - // during infobar animations). - virtual int GetExtraRenderViewHeight() const = 0; - - // Notification that |tab_contents| got the focus through user action (click - // on the page). - virtual void TabContentsFocused(TabContents* tab_contents) = 0; - - // Shows the page info using the specified information. - // |url| is the url of the page/frame the info applies to, |ssl| is the SSL - // information for that page/frame. If |show_history| is true, a section - // showing how many times that URL has been visited is added to the page info. - virtual void ShowPageInfo(Profile* profile, - const GURL& url, - const NavigationEntry::SSLStatus& ssl, - bool show_history) = 0; - - // Shows the app menu (for accessibility). - virtual void ShowAppMenu() = 0; - - // Allows the BrowserWindow object to handle the specified keyboard event - // before sending it to the renderer. - // Returns true if the |event| was handled. Otherwise, if the |event| would - // be handled in HandleKeyboardEvent() method as a normal keyboard shortcut, - // |*is_keyboard_shortcut| should be set to true. - virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, - bool* is_keyboard_shortcut) = 0; - - // Allows the BrowserWindow object to handle the specified keyboard event, - // if the renderer did not process it. - virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) = 0; - - // Shows the create web app shortcut dialog box. - virtual void ShowCreateShortcutsDialog(TabContents* tab_contents) = 0; - - // Clipboard commands applied to the whole browser window. - virtual void Cut() = 0; - virtual void Copy() = 0; - virtual void Paste() = 0; - - // Switches between available tabstrip display modes. - virtual void ToggleTabStripMode() = 0; - -#if defined(OS_MACOSX) - // Opens the tabpose view. - virtual void OpenTabpose() = 0; -#endif - - // Invoked when instant's tab contents should be shown. - virtual void ShowInstant(TabContents* preview_contents) = 0; - - // Invoked when the instant's tab contents should be hidden. - virtual void HideInstant() = 0; - - // Returns the desired bounds for instant in screen coordinates. Note that if - // instant isn't currently visible this returns the bounds instant would be - // placed at. - virtual gfx::Rect GetInstantBounds() = 0; - - // Construct a BrowserWindow implementation for the specified |browser|. - static BrowserWindow* CreateBrowserWindow(Browser* browser); - - // Construct a FindBar implementation for the specified |browser|. - static FindBar* CreateFindBar(Browser* browser_window); - - protected: - friend class BrowserList; - friend class BrowserView; - virtual void DestroyBrowser() = 0; - - virtual ~BrowserWindow() {} -}; - -#if defined(OS_WIN) || defined(TOOLKIT_VIEWS) -class BookmarkBarView; -class LocationBarView; - -namespace views { -class View; -} -#endif // defined(OS_WIN) - -// A BrowserWindow utility interface used for accessing elements of the browser -// UI used only by UI test automation. -class BrowserWindowTesting { - public: -#if defined(OS_WIN) || defined(TOOLKIT_VIEWS) - // Returns the BookmarkBarView. - virtual BookmarkBarView* GetBookmarkBarView() const = 0; - - // Returns the LocationBarView. - virtual LocationBarView* GetLocationBarView() const = 0; - - // Returns the TabContentsContainer. - virtual views::View* GetTabContentsContainerView() const = 0; - - // Returns the TabContentsContainer. - virtual views::View* GetSidebarContainerView() const = 0; - - // Returns the ToolbarView. - virtual ToolbarView* GetToolbarView() const = 0; -#endif - - protected: - virtual ~BrowserWindowTesting() {} -}; +#include "chrome/browser/ui/browser_window.h" +// TODO(beng): remove this file once all includes have been updated. #endif // CHROME_BROWSER_BROWSER_WINDOW_H_ + diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc new file mode 100644 index 0000000..52d3e5e --- /dev/null +++ b/chrome/browser/ui/browser.cc @@ -0,0 +1,4089 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/browser.h" + +#if defined(OS_WIN) +#include +#include +#endif // OS_WIN + +#include +#include + +#include "app/animation.h" +#include "app/l10n_util.h" +#include "base/base_paths.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "base/metrics/histogram.h" +#include "base/path_service.h" +#include "base/string_util.h" +#include "base/thread.h" +#include "base/thread_restrictions.h" +#include "base/utf_string_conversions.h" +#include "gfx/point.h" +#include "chrome/app/chrome_dll_resource.h" +#include "chrome/browser/autofill/autofill_manager.h" +#if defined(OS_WIN) +#include "chrome/browser/autofill/autofill_ie_toolbar_import_win.h" +#endif // defined(OS_WIN) +#include "chrome/browser/bookmarks/bookmark_model.h" +#include "chrome/browser/bookmarks/bookmark_utils.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/browser_navigator.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_shutdown.h" +#include "chrome/browser/browser_window.h" +#include "chrome/browser/browser_url_handler.h" +#include "chrome/browser/character_encoding.h" +#include "chrome/browser/debugger/devtools_manager.h" +#include "chrome/browser/debugger/devtools_toggle_action.h" +#include "chrome/browser/debugger/devtools_window.h" +#include "chrome/browser/dock_info.h" +#include "chrome/browser/dom_ui/filebrowse_ui.h" +#include "chrome/browser/dom_ui/options/content_settings_handler.h" +#include "chrome/browser/download/download_item.h" +#include "chrome/browser/download/download_item_model.h" +#include "chrome/browser/download/download_manager.h" +#include "chrome/browser/download/download_shelf.h" +#include "chrome/browser/download/download_started_animation.h" +#include "chrome/browser/extensions/crashed_extension_infobar.h" +#include "chrome/browser/extensions/extension_browser_event_router.h" +#include "chrome/browser/extensions/extension_disabled_infobar_delegate.h" +#include "chrome/browser/extensions/extension_host.h" +#include "chrome/browser/extensions/extension_prefs.h" +#include "chrome/browser/extensions/extension_tabs_module.h" +#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/find_bar.h" +#include "chrome/browser/find_bar_controller.h" +#include "chrome/browser/first_run/first_run.h" +#include "chrome/browser/google/google_url_tracker.h" +#include "chrome/browser/google/google_util.h" +#include "chrome/browser/host_zoom_map.h" +#include "chrome/browser/instant/instant_controller.h" +#include "chrome/browser/location_bar.h" +#include "chrome/browser/metrics/user_metrics.h" +#include "chrome/browser/net/browser_url_util.h" +#include "chrome/browser/net/url_fixer_upper.h" +#include "chrome/browser/options_window.h" +#include "chrome/browser/platform_util.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/browser/renderer_host/site_instance.h" +#include "chrome/browser/sessions/session_service.h" +#include "chrome/browser/sessions/session_types.h" +#include "chrome/browser/sessions/tab_restore_service.h" +#include "chrome/browser/status_bubble.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/browser/sync/sync_ui_util.h" +#include "chrome/browser/tab_closeable_state_watcher.h" +#include "chrome/browser/tab_contents/interstitial_page.h" +#include "chrome/browser/tab_contents/navigation_controller.h" +#include "chrome/browser/tab_contents/navigation_entry.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/tab_contents/tab_contents_view.h" +#include "chrome/browser/tab_menu_model.h" +#include "chrome/browser/tabs/tab_strip_model.h" +#include "chrome/browser/upgrade_detector.h" +#include "chrome/browser/web_applications/web_app.h" +#include "chrome/browser/window_sizer.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/content_restriction.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/page_transition_types.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" +#include "net/base/cookie_monster.h" +#include "net/base/net_util.h" +#include "net/base/registry_controlled_domain.h" +#include "net/base/static_cookie_policy.h" +#include "net/url_request/url_request_context.h" +#include "webkit/glue/window_open_disposition.h" + +#if defined(ENABLE_REMOTING) +#include "chrome/browser/remoting/remoting_setup_flow.h" +#endif + +#if defined(OS_WIN) +#include "app/win_util.h" +#include "chrome/browser/browser_child_process_host.h" +#include "chrome/browser/cert_store.h" +#include "chrome/browser/download/save_package.h" +#include "chrome/browser/ssl/ssl_error_info.h" +#include "chrome/browser/shell_integration.h" +#include "chrome/browser/task_manager/task_manager.h" +#include "chrome/browser/view_ids.h" +#include "chrome/browser/views/location_bar/location_bar_view.h" +#endif // OS_WIN + +#if defined(OS_MACOSX) +#include "chrome/browser/cocoa/find_pasteboard.h" +#endif + +#if defined(OS_CHROMEOS) +#include // For GdkScreen +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/cros/login_library.h" +#include "chrome/browser/chromeos/options/language_config_view.h" +#endif + +using base::TimeDelta; + +// How long we wait before updating the browser chrome while loading a page. +static const int kUIUpdateCoalescingTimeMS = 200; + +// The URL to be loaded to display Help. +#if defined(OS_CHROMEOS) +static const char* const kHelpContentUrl = + "chrome-extension://nifaohjgppdbmalmmgkmfdlodaggnbpe/main.html"; +#else +static const char* const kHelpContentUrl = + "http://www.google.com/support/chrome/"; +#endif + +// The URL to be loaded to display the "Report a broken page" form. +static const std::string kBrokenPageUrl = + "http://www.google.com/support/chrome/bin/request.py?contact_type=" + "broken_website&format=inproduct&p.page_title=$1&p.page_url=$2"; + +static const std::string kHashMark = "#"; + +// The URL for the privacy dashboard. +static const char kPrivacyDashboardUrl[] = "https://www.google.com/dashboard"; + +/////////////////////////////////////////////////////////////////////////////// + +namespace { + +#if defined(OS_CHROMEOS) +// If a popup window is bigger than this fraction of the screen on chrome os, +// turn it into a tab +const float kPopupMaxWidthFactor = 0.5; +const float kPopupMaxHeightFactor = 0.6; +#endif + +// Returns true if the specified TabContents has unload listeners registered. +bool TabHasUnloadListener(TabContents* contents) { + return contents->notify_disconnection() && + !contents->showing_interstitial_page() && + !contents->render_view_host()->SuddenTerminationAllowed(); +} + +} // namespace + +extern bool g_log_bug53991; + +/////////////////////////////////////////////////////////////////////////////// +// Browser, Constructors, Creation, Showing: + +Browser::Browser(Type type, Profile* profile) + : type_(type), + profile_(profile), + window_(NULL), + ALLOW_THIS_IN_INITIALIZER_LIST( + tab_handler_(TabHandler::CreateTabHandler(this))), + command_updater_(this), + toolbar_model_(this), + chrome_updater_factory_(this), + is_attempting_to_close_browser_(false), + cancel_download_confirmation_state_(NOT_PROMPTED), + maximized_state_(MAXIMIZED_STATE_DEFAULT), + method_factory_(this), + block_command_execution_(false), + last_blocked_command_id_(-1), + last_blocked_command_disposition_(CURRENT_TAB), + pending_web_app_action_(NONE), + extension_app_(NULL) { + registrar_.Add(this, NotificationType::SSL_VISIBLE_STATE_CHANGED, + NotificationService::AllSources()); + registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED, + NotificationService::AllSources()); + registrar_.Add(this, NotificationType::EXTENSION_LOADED, + NotificationService::AllSources()); + registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, + NotificationService::AllSources()); + registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED, + NotificationService::AllSources()); + registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED, + NotificationService::AllSources()); + registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, + NotificationService::AllSources()); + registrar_.Add(this, NotificationType::PROFILE_ERROR, + NotificationService::AllSources()); + + // Need to know when to alert the user of theme install delay. + registrar_.Add(this, NotificationType::EXTENSION_READY_FOR_INSTALL, + NotificationService::AllSources()); + + PrefService* local_state = g_browser_process->local_state(); + if (local_state) + printing_enabled_.Init(prefs::kPrintingEnabled, local_state, this); + dev_tools_disabled_.Init(prefs::kDevToolsDisabled, + profile_->GetPrefs(), this); + + InitCommandState(); + BrowserList::AddBrowser(this); + + encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector, + profile_->GetPrefs(), NULL); + use_vertical_tabs_.Init(prefs::kUseVerticalTabs, profile_->GetPrefs(), this); + instant_enabled_.Init(prefs::kInstantEnabled, profile_->GetPrefs(), this); + if (!TabMenuModel::AreVerticalTabsEnabled()) { + // If vertical tabs aren't enabled, explicitly turn them off. Otherwise we + // might show vertical tabs but not show an option to turn them off. + use_vertical_tabs_.SetValue(false); + } + UpdateTabStripModelInsertionPolicy(); + + tab_restore_service_ = profile->GetTabRestoreService(); + if (tab_restore_service_) { + tab_restore_service_->AddObserver(this); + TabRestoreServiceChanged(tab_restore_service_); + } + + if (profile_->GetProfileSyncService()) + profile_->GetProfileSyncService()->AddObserver(this); + + CreateInstantIfNecessary(); +} + +Browser::~Browser() { + VLOG_IF(1, g_log_bug53991) << "~Browser: " << profile_->IsOffTheRecord() + << "; stillActive=" + << BrowserList::IsOffTheRecordSessionActive(); + + if (profile_->GetProfileSyncService()) + profile_->GetProfileSyncService()->RemoveObserver(this); + + BrowserList::RemoveBrowser(this); + +#if defined(OS_WIN) || defined(OS_LINUX) + if (!BrowserList::HasBrowserWithProfile(profile_)) { + // We're the last browser window with this profile. We need to nuke the + // TabRestoreService, which will start the shutdown of the + // NavigationControllers and allow for proper shutdown. If we don't do this + // chrome won't shutdown cleanly, and may end up crashing when some + // thread tries to use the IO thread (or another thread) that is no longer + // valid. + // This isn't a valid assumption for Mac OS, as it stays running after + // the last browser has closed. The Mac equivalent is in its app + // controller. + profile_->ResetTabRestoreService(); + } +#endif + + SessionService* session_service = profile_->GetSessionService(); + if (session_service) + session_service->WindowClosed(session_id_); + + TabRestoreService* tab_restore_service = profile()->GetTabRestoreService(); + if (tab_restore_service) + tab_restore_service->BrowserClosed(this); + + if (profile_->IsOffTheRecord() && + !BrowserList::IsOffTheRecordSessionActive()) { + // An off-the-record profile is no longer needed, this indirectly + // frees its cache and cookies. + profile_->GetOriginalProfile()->DestroyOffTheRecordProfile(); + } + + // There may be pending file dialogs, we need to tell them that we've gone + // away so they don't try and call back to us. + if (select_file_dialog_.get()) + select_file_dialog_->ListenerDestroyed(); + + TabRestoreServiceDestroyed(tab_restore_service_); +} + +// static +Browser* Browser::Create(Profile* profile) { + Browser* browser = new Browser(TYPE_NORMAL, profile); + browser->CreateBrowserWindow(); + return browser; +} + +// static +Browser* Browser::CreateForPopup(Type type, + Profile* profile, + TabContents* new_contents, + const gfx::Rect& initial_bounds) { + DCHECK(type & TYPE_POPUP); + Browser* browser = new Browser(type, profile); + browser->set_override_bounds(initial_bounds); + browser->CreateBrowserWindow(); + browser->tabstrip_model()->AppendTabContents(new_contents, true); + return browser; +} + +// static +Browser* Browser::CreateForType(Type type, Profile* profile) { + Browser* browser = new Browser(type, profile); + browser->CreateBrowserWindow(); + return browser; +} + +// static +Browser* Browser::CreateForApp(const std::string& app_name, + const Extension* extension, + Profile* profile, + bool is_panel) { + Browser::Type type = TYPE_APP; + + if (is_panel) { + // TYPE_APP_PANEL is the logical choice. However, the panel UI + // is not fully implemented. See crbug/55943. + type = TYPE_APP_POPUP; + } else if (extension) { + type = TYPE_EXTENSION_APP; + } + + Browser* browser = new Browser(type, profile); + browser->app_name_ = app_name; + browser->extension_app_ = extension; + + if (extension) { + gfx::Rect initial_pos(extension->launch_width(), + extension->launch_height()); + if (!initial_pos.IsEmpty()) + browser->set_override_bounds(initial_pos); + } + + browser->CreateBrowserWindow(); + + return browser; +} + +// static +Browser* Browser::CreateForDevTools(Profile* profile) { + Browser* browser = new Browser(TYPE_DEVTOOLS, profile); + browser->app_name_ = DevToolsWindow::kDevToolsApp; + browser->CreateBrowserWindow(); + return browser; +} + +void Browser::CreateBrowserWindow() { + DCHECK(!window_); + + window_ = BrowserWindow::CreateBrowserWindow(this); + +#if defined(OS_WIN) + { + // TODO: This might hit the disk + // http://code.google.com/p/chromium/issues/detail?id=61638 + base::ThreadRestrictions::ScopedAllowIO allow_io; + + // Set the app user model id for this application to that of the application + // name. See http://crbug.com/7028. + win_util::SetAppIdForWindow( + type_ & TYPE_APP ? + ShellIntegration::GetAppId(UTF8ToWide(app_name_), profile_->GetPath()) : + ShellIntegration::GetChromiumAppId(profile_->GetPath()), + window()->GetNativeHandle()); + } +#endif + + NotificationService::current()->Notify( + NotificationType::BROWSER_WINDOW_READY, + Source(this), + NotificationService::NoDetails()); + + // Show the First Run information bubble if we've been told to. + PrefService* local_state = g_browser_process->local_state(); + if (!local_state) + return; + if (local_state->FindPreference(prefs::kShouldShowFirstRunBubble) && + local_state->GetBoolean(prefs::kShouldShowFirstRunBubble)) { + FirstRun::BubbleType bubble_type = FirstRun::LARGE_BUBBLE; + if (local_state-> + FindPreference(prefs::kShouldUseOEMFirstRunBubble) && + local_state->GetBoolean(prefs::kShouldUseOEMFirstRunBubble)) { + bubble_type = FirstRun::OEM_BUBBLE; + } else if (local_state-> + FindPreference(prefs::kShouldUseMinimalFirstRunBubble) && + local_state->GetBoolean(prefs::kShouldUseMinimalFirstRunBubble)) { + bubble_type = FirstRun::MINIMAL_BUBBLE; + } + // Reset the preference so we don't show the bubble for subsequent windows. + local_state->ClearPref(prefs::kShouldShowFirstRunBubble); + window_->GetLocationBar()->ShowFirstRunBubble(bubble_type); + } + if (local_state->FindPreference( + prefs::kAutoFillPersonalDataManagerFirstRun) && + local_state->GetBoolean(prefs::kAutoFillPersonalDataManagerFirstRun)) { + // Notify PDM that this is a first run. +#if defined(OS_WIN) + ImportAutofillDataWin(profile_->GetPersonalDataManager()); +#endif // defined(OS_WIN) + // Reset the preference so we don't call it again for subsequent windows. + local_state->ClearPref(prefs::kAutoFillPersonalDataManagerFirstRun); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Getters & Setters + +const std::vector& Browser::user_data_dir_profiles() const { + return g_browser_process->user_data_dir_profiles(); +} + +void Browser::set_user_data_dir_profiles( + const std::vector& profiles) { + g_browser_process->user_data_dir_profiles() = profiles; +} + +FindBarController* Browser::GetFindBarController() { + if (!find_bar_controller_.get()) { + FindBar* find_bar = BrowserWindow::CreateFindBar(this); + find_bar_controller_.reset(new FindBarController(find_bar)); + find_bar->SetFindBarController(find_bar_controller_.get()); + find_bar_controller_->ChangeTabContents(GetSelectedTabContents()); + find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true); + } + return find_bar_controller_.get(); +} + +bool Browser::HasFindBarController() const { + return find_bar_controller_.get() != NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, Creation Helpers: + +// static +void Browser::OpenEmptyWindow(Profile* profile) { + Browser* browser = Browser::Create(profile); + browser->AddBlankTab(true); + browser->window()->Show(); +} + +// static +void Browser::OpenWindowWithRestoredTabs(Profile* profile) { + TabRestoreService* service = profile->GetTabRestoreService(); + if (service) + service->RestoreMostRecentEntry(NULL); +} + +// static +void Browser::OpenURLOffTheRecord(Profile* profile, const GURL& url) { + Browser* browser = GetOrCreateTabbedBrowser( + profile->GetOffTheRecordProfile()); + browser->AddSelectedTabWithURL(url, PageTransition::LINK); + browser->window()->Show(); +} + +// static +// TODO(erikkay): There are multiple reasons why this could fail. Should +// this function return an error reason as well so that callers can show +// reasonable errors? +TabContents* Browser::OpenApplication(Profile* profile, + const std::string& app_id, + TabContents* existing_tab) { + ExtensionsService* extensions_service = profile->GetExtensionsService(); + if (!extensions_service->is_ready()) + return NULL; + + // If the extension with |app_id| could't be found, most likely because it + // was uninstalled. + const Extension* extension = + extensions_service->GetExtensionById(app_id, false); + if (!extension) + return NULL; + + return OpenApplication(profile, extension, extension->launch_container(), + existing_tab); +} + +// static +TabContents* Browser::OpenApplication( + Profile* profile, + const Extension* extension, + extension_misc::LaunchContainer container, + TabContents* existing_tab) { + TabContents* tab = NULL; + + UMA_HISTOGRAM_ENUMERATION("Extensions.AppLaunchContainer", container, 100); + + // The app is not yet open. Load it. + switch (container) { + case extension_misc::LAUNCH_WINDOW: + case extension_misc::LAUNCH_PANEL: + tab = Browser::OpenApplicationWindow(profile, extension, container, + GURL()); + break; + case extension_misc::LAUNCH_TAB: { + tab = Browser::OpenApplicationTab(profile, extension, existing_tab); + break; + } + default: + NOTREACHED(); + break; + } + return tab; +} + +// static +TabContents* Browser::OpenApplicationWindow( + Profile* profile, + const Extension* extension, + extension_misc::LaunchContainer container, + const GURL& url_input) { + GURL url; + if (!url_input.is_empty()) { + if (extension) + DCHECK(extension->web_extent().ContainsURL(url_input)); + url = url_input; + } else { + DCHECK(extension); + url = extension->GetFullLaunchURL(); + } + + // TODO(erikkay) this can't be correct for extensions + std::string app_name = web_app::GenerateApplicationNameFromURL(url); + RegisterAppPrefs(app_name); + + bool as_panel = extension && (container == extension_misc::LAUNCH_PANEL); + Browser* browser = Browser::CreateForApp(app_name, extension, profile, + as_panel); + TabContents* contents = + browser->AddSelectedTabWithURL(url, PageTransition::START_PAGE); + contents->GetMutableRendererPrefs()->can_accept_load_drops = false; + contents->render_view_host()->SyncRendererPrefs(); + browser->window()->Show(); + + // TODO(jcampan): http://crbug.com/8123 we should not need to set the initial + // focus explicitly. + contents->view()->SetInitialFocus(); + + if (!as_panel) { + // Set UPDATE_SHORTCUT as the pending web app action. This action is picked + // up in LoadingStateChanged to schedule a GetApplicationInfo. And when + // the web app info is available, TabContents notifies Browser via + // OnDidGetApplicationInfo, which calls + // web_app::UpdateShortcutForTabContents when it sees UPDATE_SHORTCUT as + // pending web app action. + browser->pending_web_app_action_ = UPDATE_SHORTCUT; + } + + return contents; +} + +// static +TabContents* Browser::OpenApplicationWindow(Profile* profile, GURL& url) { + return OpenApplicationWindow(profile, NULL, extension_misc::LAUNCH_WINDOW, + url); +} + +// static +TabContents* Browser::OpenApplicationTab(Profile* profile, + const Extension* extension, + TabContents* existing_tab) { + Browser* browser = BrowserList::GetLastActiveWithProfile(profile); + TabContents* contents = NULL; + if (!browser || browser->type() != Browser::TYPE_NORMAL) + return contents; + + // Check the prefs for overridden mode. + ExtensionsService* extensions_service = profile->GetExtensionsService(); + DCHECK(extensions_service); + + ExtensionPrefs::LaunchType launch_type = + extensions_service->extension_prefs()->GetLaunchType(extension->id()); + UMA_HISTOGRAM_ENUMERATION("Extensions.AppTabLaunchType", launch_type, 100); + int add_type = TabStripModel::ADD_SELECTED; + if (launch_type == ExtensionPrefs::LAUNCH_PINNED) + add_type |= TabStripModel::ADD_PINNED; + + // TODO(erikkay): START_PAGE doesn't seem like the right transition in all + // cases. + browser::NavigateParams params(browser, extension->GetFullLaunchURL(), + PageTransition::START_PAGE); + params.tabstrip_add_types = add_type; + + // Launch the application in the existing TabContents, if it was supplied. + if (existing_tab) { + TabStripModel* model = browser->tabstrip_model(); + int tab_index = model->GetIndexOfTabContents(existing_tab); + + existing_tab->OpenURL(extension->GetFullLaunchURL(), existing_tab->GetURL(), + CURRENT_TAB, PageTransition::LINK); + if (params.tabstrip_add_types & TabStripModel::ADD_PINNED) { + model->SetTabPinned(tab_index, true); + tab_index = model->GetIndexOfTabContents(existing_tab); + } + if (params.tabstrip_add_types & TabStripModel::ADD_SELECTED) + model->SelectTabContentsAt(tab_index, true); + + contents = existing_tab; + } else { + params.disposition = NEW_FOREGROUND_TAB; + browser::Navigate(¶ms); + contents = params.target_contents; + } + + if (launch_type == ExtensionPrefs::LAUNCH_FULLSCREEN) + browser->window()->SetFullscreen(true); + + return contents; +} + +// static +void Browser::OpenBookmarkManagerWindow(Profile* profile) { + Browser* browser = Browser::Create(profile); + browser->ShowBookmarkManagerTab(); + browser->window()->Show(); +} + +#if defined(OS_MACOSX) +// static +void Browser::OpenHistoryWindow(Profile* profile) { + Browser* browser = Browser::Create(profile); + browser->ShowHistoryTab(); + browser->window()->Show(); +} + +// static +void Browser::OpenDownloadsWindow(Profile* profile) { + Browser* browser = Browser::Create(profile); + browser->ShowDownloadsTab(); + browser->window()->Show(); +} + +// static +void Browser::OpenHelpWindow(Profile* profile) { + Browser* browser = Browser::Create(profile); + browser->OpenHelpTab(); + browser->window()->Show(); +} + +void Browser::OpenOptionsWindow(Profile* profile) { + Browser* browser = Browser::Create(profile); + browser->ShowOptionsTab(chrome::kDefaultOptionsSubPage); + browser->window()->Show(); +} +#endif + +// static +void Browser::OpenExtensionsWindow(Profile* profile) { + Browser* browser = Browser::Create(profile); + browser->ShowExtensionsTab(); + browser->window()->Show(); +} + + +/////////////////////////////////////////////////////////////////////////////// +// Browser, State Storage and Retrieval for UI: + +std::string Browser::GetWindowPlacementKey() const { + std::string name(prefs::kBrowserWindowPlacement); + if (!app_name_.empty()) { + name.append("_"); + name.append(app_name_); + } + return name; +} + +bool Browser::ShouldSaveWindowPlacement() const { + // Only save the window placement of popups if they are restored. + return (type() & TYPE_POPUP) == 0 || browser_defaults::kRestorePopups; +} + +void Browser::SaveWindowPlacement(const gfx::Rect& bounds, bool maximized) { + // Save to the session storage service, used when reloading a past session. + // Note that we don't want to be the ones who cause lazy initialization of + // the session service. This function gets called during initial window + // showing, and we don't want to bring in the session service this early. + if (profile()->HasSessionService()) { + SessionService* session_service = profile()->GetSessionService(); + if (session_service) + session_service->SetWindowBounds(session_id_, bounds, maximized); + } +} + +gfx::Rect Browser::GetSavedWindowBounds() const { + const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); + bool record_mode = parsed_command_line.HasSwitch(switches::kRecordMode); + bool playback_mode = parsed_command_line.HasSwitch(switches::kPlaybackMode); + if (record_mode || playback_mode) { + // In playback/record mode we always fix the size of the browser and + // move it to (0,0). The reason for this is two reasons: First we want + // resize/moves in the playback to still work, and Second we want + // playbacks to work (as much as possible) on machines w/ different + // screen sizes. + return gfx::Rect(0, 0, 800, 600); + } + + gfx::Rect restored_bounds = override_bounds_; + bool maximized; + WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, NULL, + &restored_bounds, &maximized); + return restored_bounds; +} + +// TODO(beng): obtain maximized state some other way so we don't need to go +// through all this hassle. +bool Browser::GetSavedMaximizedState() const { + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStartMaximized)) + return true; + + if (maximized_state_ == MAXIMIZED_STATE_MAXIMIZED) + return true; + if (maximized_state_ == MAXIMIZED_STATE_UNMAXIMIZED) + return false; + + // An explicit maximized state was not set. Query the window sizer. + gfx::Rect restored_bounds; + bool maximized = false; + WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, NULL, + &restored_bounds, &maximized); + return maximized; +} + +SkBitmap Browser::GetCurrentPageIcon() const { + TabContents* contents = GetSelectedTabContents(); + // |contents| can be NULL since GetCurrentPageIcon() is called by the window + // during the window's creation (before tabs have been added). + return contents ? contents->GetFavIcon() : SkBitmap(); +} + +string16 Browser::GetWindowTitleForCurrentTab() const { + TabContents* contents = + tab_handler_->GetTabStripModel()->GetSelectedTabContents(); + string16 title; + + // |contents| can be NULL because GetWindowTitleForCurrentTab is called by the + // window during the window's creation (before tabs have been added). + if (contents) { + title = contents->GetTitle(); + FormatTitleForDisplay(&title); + } + if (title.empty()) + title = TabContents::GetDefaultTitle(); + +#if defined(OS_MACOSX) || defined(OS_CHROMEOS) + // On Mac or ChromeOS, we don't want to suffix the page title with + // the application name. + return title; +#elif defined(OS_WIN) || defined(OS_LINUX) + int string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT; + // Don't append the app name to window titles on app frames and app popups + if (type_ & TYPE_APP) + string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT_NO_LOGO; + return l10n_util::GetStringFUTF16(string_id, title); +#endif +} + +// static +void Browser::FormatTitleForDisplay(string16* title) { + size_t current_index = 0; + size_t match_index; + while ((match_index = title->find(L'\n', current_index)) != string16::npos) { + title->replace(match_index, 1, string16()); + current_index = match_index; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, OnBeforeUnload handling: + +bool Browser::ShouldCloseWindow() { + if (!CanCloseWithInProgressDownloads()) + return false; + + if (HasCompletedUnloadProcessing()) + return IsClosingPermitted(); + + is_attempting_to_close_browser_ = true; + + for (int i = 0; i < tab_count(); ++i) { + TabContents* contents = GetTabContentsAt(i); + if (TabHasUnloadListener(contents)) + tabs_needing_before_unload_fired_.insert(contents); + } + + if (tabs_needing_before_unload_fired_.empty()) + return IsClosingPermitted(); + + ProcessPendingTabs(); + return false; +} + +void Browser::OnWindowClosing() { + if (!ShouldCloseWindow()) + return; + + bool exiting = false; + + // Application should shutdown on last window close if the user is explicitly + // trying to quit, or if there is nothing keeping the browser alive (such as + // AppController on the Mac, or BackgroundContentsService for background + // pages). + bool should_quit_if_last_browser = + browser_shutdown::IsTryingToQuit() || !BrowserList::WillKeepAlive(); + + if (should_quit_if_last_browser && BrowserList::size() == 1) { + browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE); + exiting = true; + } + + // Don't use HasSessionService here, we want to force creation of the + // session service so that user can restore what was open. + SessionService* session_service = profile()->GetSessionService(); + if (session_service) + session_service->WindowClosing(session_id()); + + TabRestoreService* tab_restore_service = profile()->GetTabRestoreService(); + if (tab_restore_service) + tab_restore_service->BrowserClosing(this); + + // TODO(sky): convert session/tab restore to use notification. + NotificationService::current()->Notify( + NotificationType::BROWSER_CLOSING, + Source(this), + Details(&exiting)); + + CloseAllTabs(); +} + +//////////////////////////////////////////////////////////////////////////////// +// In-progress download termination handling: + +void Browser::InProgressDownloadResponse(bool cancel_downloads) { + if (cancel_downloads) { + cancel_download_confirmation_state_ = RESPONSE_RECEIVED; + CloseWindow(); + return; + } + + // Sets the confirmation state to NOT_PROMPTED so that if the user tries to + // close again we'll show the warning again. + cancel_download_confirmation_state_ = NOT_PROMPTED; + + // Show the download page so the user can figure-out what downloads are still + // in-progress. + ShowDownloadsTab(); +} + +//////////////////////////////////////////////////////////////////////////////// +// Browser, TabStripModel pass-thrus: + +int Browser::tab_count() const { + return tab_handler_->GetTabStripModel()->count(); +} + +int Browser::selected_index() const { + return tab_handler_->GetTabStripModel()->selected_index(); +} + +int Browser::GetIndexOfController( + const NavigationController* controller) const { + return tab_handler_->GetTabStripModel()->GetIndexOfController(controller); +} + +TabContents* Browser::GetTabContentsAt(int index) const { + return tab_handler_->GetTabStripModel()->GetTabContentsAt(index); +} + +TabContents* Browser::GetSelectedTabContents() const { + return tab_handler_->GetTabStripModel()->GetSelectedTabContents(); +} + +void Browser::SelectTabContentsAt(int index, bool user_gesture) { + tab_handler_->GetTabStripModel()->SelectTabContentsAt(index, user_gesture); +} + +void Browser::CloseAllTabs() { + tab_handler_->GetTabStripModel()->CloseAllTabs(); +} + +//////////////////////////////////////////////////////////////////////////////// +// Browser, Tab adding/showing functions: + +int Browser::GetIndexForInsertionDuringRestore(int relative_index) { + return (tab_handler_->GetTabStripModel()->insertion_policy() == + TabStripModel::INSERT_AFTER) ? tab_count() : relative_index; +} + +TabContents* Browser::AddSelectedTabWithURL(const GURL& url, + PageTransition::Type transition) { + browser::NavigateParams params(this, url, transition); + params.disposition = NEW_FOREGROUND_TAB; + browser::Navigate(¶ms); + return params.target_contents; +} + +TabContents* Browser::AddTab(TabContents* tab_contents, + PageTransition::Type type) { + tab_handler_->GetTabStripModel()->AddTabContents( + tab_contents, -1, type, TabStripModel::ADD_SELECTED); + return tab_contents; +} + +void Browser::AddTabContents(TabContents* new_contents, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture) { + AddNewContents(NULL, new_contents, disposition, initial_pos, user_gesture); +} + +void Browser::CloseTabContents(TabContents* contents) { + CloseContents(contents); +} + +void Browser::BrowserShowHtmlDialog(HtmlDialogUIDelegate* delegate, + gfx::NativeWindow parent_window) { + ShowHtmlDialog(delegate, parent_window); +} + +void Browser::BrowserRenderWidgetShowing() { + RenderWidgetShowing(); +} + +void Browser::ToolbarSizeChanged(bool is_animating) { + ToolbarSizeChanged(NULL, is_animating); +} + +TabContents* Browser::AddRestoredTab( + const std::vector& navigations, + int tab_index, + int selected_navigation, + const std::string& extension_app_id, + bool select, + bool pin, + bool from_last_session, + SessionStorageNamespace* session_storage_namespace) { + TabContents* new_tab = new TabContents( + profile(), NULL, MSG_ROUTING_NONE, + tab_handler_->GetTabStripModel()->GetSelectedTabContents(), + session_storage_namespace); + new_tab->SetExtensionAppById(extension_app_id); + new_tab->controller().RestoreFromState(navigations, selected_navigation, + from_last_session); + + bool really_pin = + (pin && tab_index == tabstrip_model()->IndexOfFirstNonMiniTab()); + tab_handler_->GetTabStripModel()->InsertTabContentsAt( + tab_index, new_tab, + select ? TabStripModel::ADD_SELECTED : TabStripModel::ADD_NONE); + if (really_pin) + tab_handler_->GetTabStripModel()->SetTabPinned(tab_index, true); + if (select) { + window_->Activate(); + } else { + // We set the size of the view here, before WebKit does its initial + // layout. If we don't, the initial layout of background tabs will be + // performed with a view width of 0, which may cause script outputs and + // anchor link location calculations to be incorrect even after a new + // layout with proper view dimensions. TabStripModel::AddTabContents() + // contains similar logic. + new_tab->view()->SizeContents(window_->GetRestoredBounds().size()); + new_tab->HideContents(); + } + if (profile_->HasSessionService()) { + SessionService* session_service = profile_->GetSessionService(); + if (session_service) + session_service->TabRestored(&new_tab->controller(), really_pin); + } + return new_tab; +} + +void Browser::ReplaceRestoredTab( + const std::vector& navigations, + int selected_navigation, + bool from_last_session, + const std::string& extension_app_id, + SessionStorageNamespace* session_storage_namespace) { + TabContents* replacement = new TabContents(profile(), NULL, + MSG_ROUTING_NONE, + tab_handler_->GetTabStripModel()->GetSelectedTabContents(), + session_storage_namespace); + replacement->SetExtensionAppById(extension_app_id); + replacement->controller().RestoreFromState(navigations, selected_navigation, + from_last_session); + + tab_handler_->GetTabStripModel()->ReplaceNavigationControllerAt( + tab_handler_->GetTabStripModel()->selected_index(), + &replacement->controller()); +} + +bool Browser::CanRestoreTab() { + return command_updater_.IsCommandEnabled(IDC_RESTORE_TAB); +} + +bool Browser::NavigateToIndexWithDisposition(int index, + WindowOpenDisposition disp) { + NavigationController& controller = + GetOrCloneTabForDisposition(disp)->controller(); + if (index < 0 || index >= controller.entry_count()) + return false; + controller.GoToIndex(index); + return true; +} + +void Browser::ShowSingletonTab(const GURL& url) { + browser::NavigateParams params(this, url, PageTransition::AUTO_BOOKMARK); + params.disposition = SINGLETON_TAB; + params.show_window = true; + browser::Navigate(¶ms); +} + +void Browser::UpdateCommandsForFullscreenMode(bool is_fullscreen) { +#if !defined(OS_MACOSX) + const bool show_main_ui = (type() == TYPE_NORMAL) && !is_fullscreen; +#else + const bool show_main_ui = (type() == TYPE_NORMAL); +#endif + + bool main_not_fullscreen_or_popup = + show_main_ui && !is_fullscreen && (type() & TYPE_POPUP) == 0; + + // Navigation commands + command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, show_main_ui); + + // Window management commands + command_updater_.UpdateCommandEnabled(IDC_SHOW_AS_TAB, + (type() & TYPE_POPUP) && !is_fullscreen); + + // Focus various bits of UI + command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, show_main_ui); + command_updater_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, show_main_ui); + command_updater_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, show_main_ui); + command_updater_.UpdateCommandEnabled( + IDC_FOCUS_MENU_BAR, main_not_fullscreen_or_popup); + command_updater_.UpdateCommandEnabled( + IDC_FOCUS_NEXT_PANE, main_not_fullscreen_or_popup); + command_updater_.UpdateCommandEnabled( + IDC_FOCUS_PREVIOUS_PANE, main_not_fullscreen_or_popup); + command_updater_.UpdateCommandEnabled( + IDC_FOCUS_BOOKMARKS, main_not_fullscreen_or_popup); + command_updater_.UpdateCommandEnabled( + IDC_FOCUS_CHROMEOS_STATUS, main_not_fullscreen_or_popup); + + // Show various bits of UI + command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, show_main_ui); + command_updater_.UpdateCommandEnabled(IDC_REPORT_BUG, show_main_ui); + command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR, + browser_defaults::bookmarks_enabled && show_main_ui); + command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, show_main_ui); + command_updater_.UpdateCommandEnabled(IDC_SYNC_BOOKMARKS, + show_main_ui && profile_->IsSyncAccessible()); + +#if defined(ENABLE_REMOTING) + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableRemoting)) { + command_updater_.UpdateCommandEnabled(IDC_REMOTING_SETUP, show_main_ui); + } +#endif + + command_updater_.UpdateCommandEnabled(IDC_OPTIONS, show_main_ui); + command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui); + command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui); + command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui); + command_updater_.UpdateCommandEnabled(IDC_SHOW_APP_MENU, show_main_ui); + command_updater_.UpdateCommandEnabled(IDC_TOGGLE_VERTICAL_TABS, show_main_ui); +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, Assorted browser commands: + +bool Browser::ShouldOpenNewTabForWindowDisposition( + WindowOpenDisposition disposition) { + return (disposition == NEW_FOREGROUND_TAB || + disposition == NEW_BACKGROUND_TAB); +} + +TabContents* Browser::GetOrCloneTabForDisposition( + WindowOpenDisposition disposition) { + TabContents* current_tab = GetSelectedTabContents(); + if (ShouldOpenNewTabForWindowDisposition(disposition)) { + current_tab = current_tab->Clone(); + tab_handler_->GetTabStripModel()->AddTabContents( + current_tab, -1, PageTransition::LINK, + disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_SELECTED : + TabStripModel::ADD_NONE); + } + return current_tab; +} + +void Browser::UpdateTabStripModelInsertionPolicy() { + tab_handler_->GetTabStripModel()->SetInsertionPolicy(UseVerticalTabs() ? + TabStripModel::INSERT_BEFORE : TabStripModel::INSERT_AFTER); +} + +void Browser::UseVerticalTabsChanged() { + UpdateTabStripModelInsertionPolicy(); + window()->ToggleTabStripMode(); +} + +bool Browser::SupportsWindowFeatureImpl(WindowFeature feature, + bool check_fullscreen) const { + // On Mac, fullscreen mode has most normal things (in a slide-down panel). On + // other platforms, we hide some controls when in fullscreen mode. + bool hide_ui_for_fullscreen = false; +#if !defined(OS_MACOSX) + hide_ui_for_fullscreen = check_fullscreen && window_ && + window_->IsFullscreen(); +#endif + + unsigned int features = FEATURE_INFOBAR | FEATURE_SIDEBAR; + +#if !defined(OS_CHROMEOS) + // Chrome OS opens a FileBrowse pop up instead of using download shelf. + // So FEATURE_DOWNLOADSHELF is only added for non-chromeos platforms. + features |= FEATURE_DOWNLOADSHELF; +#endif // !defined(OS_CHROMEOS) + + if (type() == TYPE_NORMAL) { + features |= FEATURE_BOOKMARKBAR; + } + + if (!hide_ui_for_fullscreen) { + if (type() != TYPE_NORMAL && type() != TYPE_EXTENSION_APP) + features |= FEATURE_TITLEBAR; + + if (type() == TYPE_NORMAL || type() == TYPE_EXTENSION_APP) + features |= FEATURE_TABSTRIP; + + if (type() == TYPE_NORMAL || type() == TYPE_EXTENSION_APP) + features |= FEATURE_TOOLBAR; + + if (type() != TYPE_EXTENSION_APP && (type() & Browser::TYPE_APP) == 0) + features |= FEATURE_LOCATIONBAR; + } + return !!(features & feature); +} + +bool Browser::IsClosingPermitted() { + TabCloseableStateWatcher* watcher = + g_browser_process->tab_closeable_state_watcher(); + bool can_close = !watcher || watcher->CanCloseBrowser(this); + if (!can_close && is_attempting_to_close_browser_) + CancelWindowClose(); + return can_close; +} + +void Browser::GoBack(WindowOpenDisposition disposition) { + UserMetrics::RecordAction(UserMetricsAction("Back"), profile_); + + TabContents* current_tab = GetSelectedTabContents(); + if (current_tab->controller().CanGoBack()) { + TabContents* new_tab = GetOrCloneTabForDisposition(disposition); + // If we are on an interstitial page and clone the tab, it won't be copied + // to the new tab, so we don't need to go back. + if (current_tab->showing_interstitial_page() && (new_tab != current_tab)) + return; + new_tab->controller().GoBack(); + } +} + +void Browser::GoForward(WindowOpenDisposition disposition) { + UserMetrics::RecordAction(UserMetricsAction("Forward"), profile_); + if (GetSelectedTabContents()->controller().CanGoForward()) + GetOrCloneTabForDisposition(disposition)->controller().GoForward(); +} + +void Browser::Reload(WindowOpenDisposition disposition) { + UserMetrics::RecordAction(UserMetricsAction("Reload"), profile_); + ReloadInternal(disposition, false); +} + +void Browser::ReloadIgnoringCache(WindowOpenDisposition disposition) { + UserMetrics::RecordAction(UserMetricsAction("ReloadIgnoringCache"), profile_); + ReloadInternal(disposition, true); +} + +void Browser::ReloadInternal(WindowOpenDisposition disposition, + bool ignore_cache) { + // If we are showing an interstitial, treat this as an OpenURL. + TabContents* current_tab = GetSelectedTabContents(); + if (current_tab && current_tab->showing_interstitial_page()) { + NavigationEntry* entry = current_tab->controller().GetActiveEntry(); + DCHECK(entry); // Should exist if interstitial is showing. + OpenURL(entry->url(), GURL(), disposition, PageTransition::RELOAD); + return; + } + + // As this is caused by a user action, give the focus to the page. + current_tab = GetOrCloneTabForDisposition(disposition); + if (!current_tab->FocusLocationBarByDefault()) + current_tab->Focus(); + if (ignore_cache) + current_tab->controller().ReloadIgnoringCache(true); + else + current_tab->controller().Reload(true); +} + +void Browser::Home(WindowOpenDisposition disposition) { + UserMetrics::RecordAction(UserMetricsAction("Home"), profile_); + OpenURL(GetHomePage(), GURL(), disposition, PageTransition::AUTO_BOOKMARK); +} + +void Browser::OpenCurrentURL() { + UserMetrics::RecordAction(UserMetricsAction("LoadURL"), profile_); + LocationBar* location_bar = window_->GetLocationBar(); + WindowOpenDisposition open_disposition = + location_bar->GetWindowOpenDisposition(); + if (OpenInstant(open_disposition)) + return; + + GURL url(WideToUTF8(location_bar->GetInputString())); + browser::NavigateParams params(this, url, location_bar->GetPageTransition()); + params.disposition = open_disposition; + // Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least + // inherit the opener. In some cases the tabstrip will determine the group + // should be inherited, in which case the group is inherited instead of the + // opener. + params.tabstrip_add_types = + TabStripModel::ADD_FORCE_INDEX | TabStripModel::ADD_INHERIT_OPENER; + browser::Navigate(¶ms); +} + +void Browser::Stop() { + UserMetrics::RecordAction(UserMetricsAction("Stop"), profile_); + GetSelectedTabContents()->Stop(); +} + +void Browser::NewWindow() { + if (browser_defaults::kAlwaysOpenIncognitoWindow && + CommandLine::ForCurrentProcess()->HasSwitch(switches::kIncognito)) { + NewIncognitoWindow(); + return; + } + UserMetrics::RecordAction(UserMetricsAction("NewWindow"), profile_); + SessionService* session_service = + profile_->GetOriginalProfile()->GetSessionService(); + if (!session_service || + !session_service->RestoreIfNecessary(std::vector())) { + Browser::OpenEmptyWindow(profile_->GetOriginalProfile()); + } +} + +void Browser::NewIncognitoWindow() { + UserMetrics::RecordAction(UserMetricsAction("NewIncognitoWindow"), profile_); + Browser::OpenEmptyWindow(profile_->GetOffTheRecordProfile()); +} + +void Browser::CloseWindow() { + UserMetrics::RecordAction(UserMetricsAction("CloseWindow"), profile_); + window_->Close(); +} + +void Browser::NewTab() { + UserMetrics::RecordAction(UserMetricsAction("NewTab"), profile_); + + if (type() == TYPE_NORMAL) { + AddBlankTab(true); + } else { + Browser* b = GetOrCreateTabbedBrowser(profile_); + b->AddBlankTab(true); + b->window()->Show(); + // The call to AddBlankTab above did not set the focus to the tab as its + // window was not active, so we have to do it explicitly. + // See http://crbug.com/6380. + b->GetSelectedTabContents()->view()->RestoreFocus(); + } +} + +void Browser::CloseTab() { + UserMetrics::RecordAction(UserMetricsAction("CloseTab_Accelerator"), + profile_); + if (CanCloseTab()) { + tab_handler_->GetTabStripModel()->CloseTabContentsAt( + tab_handler_->GetTabStripModel()->selected_index(), + TabStripModel::CLOSE_USER_GESTURE | + TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); + } +} + +void Browser::SelectNextTab() { + UserMetrics::RecordAction(UserMetricsAction("SelectNextTab"), profile_); + tab_handler_->GetTabStripModel()->SelectNextTab(); +} + +void Browser::SelectPreviousTab() { + UserMetrics::RecordAction(UserMetricsAction("SelectPrevTab"), profile_); + tab_handler_->GetTabStripModel()->SelectPreviousTab(); +} + +void Browser::OpenTabpose() { +#if defined(OS_MACOSX) + if (!CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableExposeForTabs)) { + return; + } + + UserMetrics::RecordAction(UserMetricsAction("OpenTabpose"), profile_); + window()->OpenTabpose(); +#else + NOTREACHED(); +#endif +} + +void Browser::MoveTabNext() { + UserMetrics::RecordAction(UserMetricsAction("MoveTabNext"), profile_); + tab_handler_->GetTabStripModel()->MoveTabNext(); +} + +void Browser::MoveTabPrevious() { + UserMetrics::RecordAction(UserMetricsAction("MoveTabPrevious"), profile_); + tab_handler_->GetTabStripModel()->MoveTabPrevious(); +} + +void Browser::SelectNumberedTab(int index) { + if (index < tab_count()) { + UserMetrics::RecordAction(UserMetricsAction("SelectNumberedTab"), + profile_); + tab_handler_->GetTabStripModel()->SelectTabContentsAt(index, true); + } +} + +void Browser::SelectLastTab() { + UserMetrics::RecordAction(UserMetricsAction("SelectLastTab"), profile_); + tab_handler_->GetTabStripModel()->SelectLastTab(); +} + +void Browser::DuplicateTab() { + UserMetrics::RecordAction(UserMetricsAction("Duplicate"), profile_); + DuplicateContentsAt(selected_index()); +} + +void Browser::RestoreTab() { + UserMetrics::RecordAction(UserMetricsAction("RestoreTab"), profile_); + TabRestoreService* service = profile_->GetTabRestoreService(); + if (!service) + return; + + service->RestoreMostRecentEntry(this); +} + +void Browser::WriteCurrentURLToClipboard() { + // TODO(ericu): There isn't currently a metric for this. Should there be? + // We don't appear to track the action when it comes from the + // RenderContextViewMenu. + + TabContents* contents = GetSelectedTabContents(); + if (!contents->ShouldDisplayURL()) + return; + + chrome_browser_net::WriteURLToClipboard( + contents->GetURL(), + profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), + g_browser_process->clipboard()); +} + +void Browser::ConvertPopupToTabbedBrowser() { + UserMetrics::RecordAction(UserMetricsAction("ShowAsTab"), profile_); + int tab_strip_index = tab_handler_->GetTabStripModel()->selected_index(); + TabContents* contents = + tab_handler_->GetTabStripModel()->DetachTabContentsAt(tab_strip_index); + Browser* browser = Browser::Create(profile_); + browser->tabstrip_model()->AppendTabContents(contents, true); + browser->window()->Show(); +} + +void Browser::ToggleFullscreenMode() { +#if !defined(OS_MACOSX) + // In kiosk mode, we always want to be fullscreen. When the browser first + // starts we're not yet fullscreen, so let the initial toggle go through. + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode) && + window_->IsFullscreen()) + return; +#endif + + UserMetrics::RecordAction(UserMetricsAction("ToggleFullscreen"), profile_); + window_->SetFullscreen(!window_->IsFullscreen()); + // On Linux, setting fullscreen mode is an async call to the X server, which + // may or may not support fullscreen mode. +#if !defined(OS_LINUX) + UpdateCommandsForFullscreenMode(window_->IsFullscreen()); +#endif +} + +#if defined(OS_CHROMEOS) +void Browser::Search() { + // If the NTP is showing, close it. + if (StartsWithASCII(GetSelectedTabContents()->GetURL().spec(), + chrome::kChromeUINewTabURL, true)) { + CloseTab(); + return; + } + + // Exit fullscreen to show omnibox. + if (window_->IsFullscreen()) { + ToggleFullscreenMode(); + // ToggleFullscreenMode is asynchronous, so we don't have omnibox + // visible at this point. Wait for next event cycle which toggles + // the visibility of omnibox before creating new tab. + MessageLoop::current()->PostTask( + FROM_HERE, method_factory_.NewRunnableMethod(&Browser::Search)); + return; + } + + // Otherwise just open it. + NewTab(); +} +#endif + +void Browser::Exit() { + UserMetrics::RecordAction(UserMetricsAction("Exit"), profile_); +#if defined(OS_CHROMEOS) + if (chromeos::CrosLibrary::Get()->EnsureLoaded()) { + chromeos::CrosLibrary::Get()->GetLoginLibrary()->StopSession(""); + return; + } + // If running the Chrome OS build, but we're not on the device, fall through +#endif + BrowserList::CloseAllBrowsersAndExit(); +} + +void Browser::BookmarkCurrentPage() { + UserMetrics::RecordAction(UserMetricsAction("Star"), profile_); + + BookmarkModel* model = profile()->GetBookmarkModel(); + if (!model || !model->IsLoaded()) + return; // Ignore requests until bookmarks are loaded. + + GURL url; + string16 title; + bookmark_utils::GetURLAndTitleToBookmark(GetSelectedTabContents(), &url, + &title); + bool was_bookmarked = model->IsBookmarked(url); + model->SetURLStarred(url, title, true); + // Make sure the model actually added a bookmark before showing the star. A + // bookmark isn't created if the url is invalid. + if (window_->IsActive() && model->IsBookmarked(url)) { + // Only show the bubble if the window is active, otherwise we may get into + // weird situations were the bubble is deleted as soon as it is shown. + window_->ShowBookmarkBubble(url, was_bookmarked); + } +} + +void Browser::SavePage() { + UserMetrics::RecordAction(UserMetricsAction("SavePage"), profile_); + TabContents* current_tab = GetSelectedTabContents(); + if (current_tab && current_tab->contents_mime_type() == "application/pdf") + UserMetrics::RecordAction(UserMetricsAction("PDF.SavePage"), profile_); + GetSelectedTabContents()->OnSavePage(); +} + +void Browser::ViewSource() { + UserMetrics::RecordAction(UserMetricsAction("ViewSource"), profile_); + + TabContents* current_tab = GetSelectedTabContents(); + NavigationEntry* entry = current_tab->controller().GetLastCommittedEntry(); + if (entry) { + OpenURL(GURL(chrome::kViewSourceScheme + std::string(":") + + entry->url().spec()), GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); + } +} + +void Browser::ShowFindBar() { + GetFindBarController()->Show(); +} + +bool Browser::SupportsWindowFeature(WindowFeature feature) const { + return SupportsWindowFeatureImpl(feature, true); +} + +bool Browser::CanSupportWindowFeature(WindowFeature feature) const { + return SupportsWindowFeatureImpl(feature, false); +} + +void Browser::EmailPageLocation() { + UserMetrics::RecordAction(UserMetricsAction("EmailPageLocation"), profile_); + GetSelectedTabContents()->EmailPageLocation(); +} + +void Browser::Print() { + UserMetrics::RecordAction(UserMetricsAction("PrintPreview"), profile_); + GetSelectedTabContents()->PrintPreview(); +} + +void Browser::ToggleEncodingAutoDetect() { + UserMetrics::RecordAction(UserMetricsAction("AutoDetectChange"), profile_); + encoding_auto_detect_.SetValue(!encoding_auto_detect_.GetValue()); + // If "auto detect" is turned on, then any current override encoding + // is cleared. This also implicitly performs a reload. + // OTOH, if "auto detect" is turned off, we don't change the currently + // active encoding. + if (encoding_auto_detect_.GetValue()) { + TabContents* contents = GetSelectedTabContents(); + if (contents) + contents->ResetOverrideEncoding(); + } +} + +void Browser::OverrideEncoding(int encoding_id) { + UserMetrics::RecordAction(UserMetricsAction("OverrideEncoding"), profile_); + const std::string selected_encoding = + CharacterEncoding::GetCanonicalEncodingNameByCommandId(encoding_id); + TabContents* contents = GetSelectedTabContents(); + if (!selected_encoding.empty() && contents) + contents->SetOverrideEncoding(selected_encoding); + // Update the list of recently selected encodings. + std::string new_selected_encoding_list; + if (CharacterEncoding::UpdateRecentlySelectedEncoding( + profile_->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding), + encoding_id, + &new_selected_encoding_list)) { + profile_->GetPrefs()->SetString(prefs::kRecentlySelectedEncoding, + new_selected_encoding_list); + } +} + +void Browser::Cut() { + UserMetrics::RecordAction(UserMetricsAction("Cut"), profile_); + window()->Cut(); +} + +void Browser::Copy() { + UserMetrics::RecordAction(UserMetricsAction("Copy"), profile_); + window()->Copy(); +} + +void Browser::Paste() { + UserMetrics::RecordAction(UserMetricsAction("Paste"), profile_); + window()->Paste(); +} + +void Browser::Find() { + UserMetrics::RecordAction(UserMetricsAction("Find"), profile_); + FindInPage(false, false); +} + +void Browser::FindNext() { + UserMetrics::RecordAction(UserMetricsAction("FindNext"), profile_); + FindInPage(true, true); +} + +void Browser::FindPrevious() { + UserMetrics::RecordAction(UserMetricsAction("FindPrevious"), profile_); + FindInPage(true, false); +} + +void Browser::Zoom(PageZoom::Function zoom_function) { + static const UserMetricsAction kActions[] = { + UserMetricsAction("ZoomMinus"), + UserMetricsAction("ZoomNormal"), + UserMetricsAction("ZoomPlus") + }; + + UserMetrics::RecordAction(kActions[zoom_function - PageZoom::ZOOM_OUT], + profile_); + TabContents* tab_contents = GetSelectedTabContents(); + tab_contents->render_view_host()->Zoom(zoom_function); +} + +void Browser::FocusToolbar() { + UserMetrics::RecordAction(UserMetricsAction("FocusToolbar"), profile_); + window_->FocusToolbar(); +} + +void Browser::FocusAppMenu() { + UserMetrics::RecordAction(UserMetricsAction("FocusAppMenu"), profile_); + window_->FocusAppMenu(); +} + +void Browser::FocusLocationBar() { + UserMetrics::RecordAction(UserMetricsAction("FocusLocation"), profile_); + window_->SetFocusToLocationBar(true); +} + +void Browser::FocusBookmarksToolbar() { + UserMetrics::RecordAction(UserMetricsAction("FocusBookmarksToolbar"), + profile_); + window_->FocusBookmarksToolbar(); +} + +void Browser::FocusChromeOSStatus() { + UserMetrics::RecordAction(UserMetricsAction("FocusChromeOSStatus"), profile_); + window_->FocusChromeOSStatus(); +} + +void Browser::FocusNextPane() { + UserMetrics::RecordAction(UserMetricsAction("FocusNextPane"), profile_); + window_->RotatePaneFocus(true); +} + +void Browser::FocusPreviousPane() { + UserMetrics::RecordAction(UserMetricsAction("FocusPreviousPane"), profile_); + window_->RotatePaneFocus(false); +} + +void Browser::FocusSearch() { + // TODO(beng): replace this with FocusLocationBar + UserMetrics::RecordAction(UserMetricsAction("FocusSearch"), profile_); + window_->GetLocationBar()->FocusSearch(); +} + +void Browser::OpenFile() { + UserMetrics::RecordAction(UserMetricsAction("OpenFile"), profile_); +#if defined(OS_CHROMEOS) + FileBrowseUI::OpenPopup(profile_, + "", + FileBrowseUI::kPopupWidth, + FileBrowseUI::kPopupHeight); +#else + if (!select_file_dialog_.get()) + select_file_dialog_ = SelectFileDialog::Create(this); + + const FilePath directory = profile_->last_selected_directory(); + + // TODO(beng): figure out how to juggle this. + gfx::NativeWindow parent_window = window_->GetNativeHandle(); + select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE, + string16(), directory, + NULL, 0, FILE_PATH_LITERAL(""), + parent_window, NULL); +#endif +} + +void Browser::OpenCreateShortcutsDialog() { + UserMetrics::RecordAction(UserMetricsAction("CreateShortcut"), profile_); +#if defined(OS_WIN) || defined(OS_LINUX) + TabContents* current_tab = GetSelectedTabContents(); + DCHECK(current_tab && web_app::IsValidUrl(current_tab->GetURL())) << + "Menu item should be disabled."; + + NavigationEntry* entry = current_tab->controller().GetLastCommittedEntry(); + if (!entry) + return; + + // RVH's GetApplicationInfo should not be called before it returns. + DCHECK(pending_web_app_action_ == NONE); + pending_web_app_action_ = CREATE_SHORTCUT; + + // Start fetching web app info for CreateApplicationShortcut dialog and show + // the dialog when the data is available in OnDidGetApplicationInfo. + current_tab->render_view_host()->GetApplicationInfo(entry->page_id()); +#else + NOTIMPLEMENTED(); +#endif +} + +void Browser::ToggleDevToolsWindow(DevToolsToggleAction action) { + std::string uma_string; + switch (action) { + case DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE: + uma_string = "DevTools_ToggleConsole"; + break; + case DEVTOOLS_TOGGLE_ACTION_NONE: + case DEVTOOLS_TOGGLE_ACTION_INSPECT: + default: + uma_string = "DevTools_ToggleWindow"; + break; + } + UserMetrics::RecordAction(UserMetricsAction(uma_string.c_str()), profile_); + DevToolsManager::GetInstance()->ToggleDevToolsWindow( + GetSelectedTabContents()->render_view_host(), action); +} + +void Browser::OpenTaskManager() { + UserMetrics::RecordAction(UserMetricsAction("TaskManager"), profile_); + window_->ShowTaskManager(); +} + +void Browser::OpenBugReportDialog() { + UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_); + window_->ShowReportBugDialog(); +} + +void Browser::ToggleBookmarkBar() { + UserMetrics::RecordAction(UserMetricsAction("ShowBookmarksBar"), profile_); + window_->ToggleBookmarkBar(); +} + +void Browser::OpenBookmarkManager() { + UserMetrics::RecordAction(UserMetricsAction("ShowBookmarkManager"), profile_); + ShowBookmarkManagerTab(); +} + +void Browser::ShowAppMenu() { + UserMetrics::RecordAction(UserMetricsAction("ShowAppMenu"), profile_); + window_->ShowAppMenu(); +} + +void Browser::ShowBookmarkManagerTab() { + UserMetrics::RecordAction(UserMetricsAction("ShowBookmarks"), profile_); + ShowSingletonTab(GURL(chrome::kChromeUIBookmarksURL)); +} + +void Browser::ShowHistoryTab() { + UserMetrics::RecordAction(UserMetricsAction("ShowHistory"), profile_); + ShowSingletonTab(GURL(chrome::kChromeUIHistoryURL)); +} + +void Browser::ShowDownloadsTab() { + UserMetrics::RecordAction(UserMetricsAction("ShowDownloads"), profile_); + ShowSingletonTab(GURL(chrome::kChromeUIDownloadsURL)); +} + +void Browser::ShowExtensionsTab() { + UserMetrics::RecordAction(UserMetricsAction("ShowExtensions"), profile_); + ShowSingletonTab(GURL(chrome::kChromeUIExtensionsURL)); +} + +void Browser::ShowAboutConflictsTab() { + UserMetrics::RecordAction(UserMetricsAction("AboutConflicts"), profile_); + ShowSingletonTab(GURL(chrome::kChromeUIConflictsURL)); +} + +void Browser::ShowBrokenPageTab(TabContents* contents) { + UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_); + string16 page_title = contents->GetTitle(); + NavigationEntry* entry = contents->controller().GetActiveEntry(); + if (!entry) + return; + std::string page_url = entry->url().spec(); + std::vector subst; + subst.push_back(UTF16ToASCII(page_title)); + subst.push_back(page_url); + std::string report_page_url = + ReplaceStringPlaceholders(kBrokenPageUrl, subst, NULL); + ShowSingletonTab(GURL(report_page_url)); +} + +void Browser::ShowOptionsTab(const std::string& sub_page) { + GURL url(chrome::kChromeUISettingsURL + sub_page); + + // See if there is already an options tab open that we can use. + TabStripModel* model = tab_handler_->GetTabStripModel(); + for (int i = 0; i < model->count(); i++) { + TabContents* tc = model->GetTabContentsAt(i); + const GURL& tab_url = tc->GetURL(); + + if (tab_url.scheme() == url.scheme() && tab_url.host() == url.host()) { + // We found an existing options tab, load the URL in this tab. (Note: + // this may cause us to unnecessarily reload the same page. We can't + // really detect that unless the options page is permitted to change the + // URL in the address bar, but security policy doesn't allow that. + browser::NavigateParams params(this, url, PageTransition::GENERATED); + params.source_contents = tc; + browser::Navigate(¶ms); + model->SelectTabContentsAt(i, false); + return; + } + } + + // No options tab found, so create a new one. + AddSelectedTabWithURL(url, PageTransition::AUTO_BOOKMARK); +} + +void Browser::OpenClearBrowsingDataDialog() { + UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_ShowDlg"), + profile_); + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableTabbedOptions)) { + ShowOptionsTab( + chrome::kAdvancedOptionsSubPage + kHashMark + + chrome::kClearBrowserDataSubPage); + } else { + window_->ShowClearBrowsingDataDialog(); + } +} + +void Browser::OpenOptionsDialog() { + UserMetrics::RecordAction(UserMetricsAction("ShowOptions"), profile_); + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableTabbedOptions)) { + ShowOptionsTab(chrome::kDefaultOptionsSubPage); + } else { + ShowOptionsWindow(OPTIONS_PAGE_DEFAULT, OPTIONS_GROUP_NONE, profile_); + } +} + +void Browser::OpenKeywordEditor() { + UserMetrics::RecordAction(UserMetricsAction("EditSearchEngines"), profile_); + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableTabbedOptions)) { + ShowOptionsTab(chrome::kSearchEnginesSubPage); + } else { + window_->ShowSearchEnginesDialog(); + } +} + +void Browser::OpenPasswordManager() { + window_->ShowPasswordManager(); +} + +void Browser::OpenImportSettingsDialog() { + UserMetrics::RecordAction(UserMetricsAction("Import_ShowDlg"), profile_); + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableTabbedOptions)) { + ShowOptionsTab( + chrome::kPersonalOptionsSubPage + kHashMark + + chrome::kImportDataSubPage); + } else { + window_->ShowImportDialog(); + } +} + +void Browser::OpenSyncMyBookmarksDialog() { + sync_ui_util::OpenSyncMyBookmarksDialog( + profile_, ProfileSyncService::START_FROM_WRENCH); +} + +#if defined(ENABLE_REMOTING) +void Browser::OpenRemotingSetupDialog() { + RemotingSetupFlow::OpenDialog(profile_); +} +#endif + +void Browser::OpenAboutChromeDialog() { + UserMetrics::RecordAction(UserMetricsAction("AboutChrome"), profile_); +#if defined(OS_CHROMEOS) + ShowSingletonTab(GURL(chrome::kChromeUIAboutURL)); +#else + window_->ShowAboutChromeDialog(); +#endif +} + +void Browser::OpenUpdateChromeDialog() { + UserMetrics::RecordAction(UserMetricsAction("UpdateChrome"), profile_); + window_->ShowUpdateChromeDialog(); +} + +void Browser::OpenHelpTab() { + GURL help_url = google_util::AppendGoogleLocaleParam(GURL(kHelpContentUrl)); + AddSelectedTabWithURL(help_url, PageTransition::AUTO_BOOKMARK); +} + +void Browser::OpenThemeGalleryTabAndActivate() { + AddSelectedTabWithURL(GURL(l10n_util::GetStringUTF8(IDS_THEMES_GALLERY_URL)), + PageTransition::LINK); +} + +void Browser::OpenPrivacyDashboardTabAndActivate() { + OpenURL(GURL(kPrivacyDashboardUrl), GURL(), + NEW_FOREGROUND_TAB, PageTransition::LINK); + window_->Activate(); +} + +void Browser::OpenAutoFillHelpTabAndActivate() { + AddSelectedTabWithURL(GURL(l10n_util::GetStringUTF8(IDS_AUTOFILL_HELP_URL)), + PageTransition::LINK); +} + +void Browser::OpenSearchEngineOptionsDialog() { + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableTabbedOptions)) { + OpenKeywordEditor(); + } else { + ShowOptionsWindow(OPTIONS_PAGE_GENERAL, OPTIONS_GROUP_DEFAULT_SEARCH, + profile_); + } +} + +#if defined(OS_CHROMEOS) +void Browser::OpenSystemOptionsDialog() { + UserMetrics::RecordAction(UserMetricsAction("OpenSystemOptionsDialog"), + profile_); + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableTabbedOptions)) { + ShowOptionsTab(chrome::kSystemOptionsSubPage); + } else { + ShowOptionsWindow(OPTIONS_PAGE_SYSTEM, OPTIONS_GROUP_NONE, + profile_); + } +} + +void Browser::OpenInternetOptionsDialog() { + UserMetrics::RecordAction(UserMetricsAction("OpenInternetOptionsDialog"), + profile_); + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableTabbedOptions)) { + ShowOptionsTab(chrome::kInternetOptionsSubPage); + } else { + ShowOptionsWindow(OPTIONS_PAGE_INTERNET, OPTIONS_GROUP_DEFAULT_SEARCH, + profile_); + } +} + +void Browser::OpenLanguageOptionsDialog() { + UserMetrics::RecordAction(UserMetricsAction("OpenLanguageOptionsDialog"), + profile_); + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableTabbedOptions)) { + ShowOptionsTab(chrome::kLanguageOptionsSubPage); + } else { + chromeos::LanguageConfigView::Show(profile_, NULL); + } +} + +void Browser::OpenSystemTabAndActivate() { + OpenURL(GURL(chrome::kChromeUISystemInfoURL), GURL(), + NEW_FOREGROUND_TAB, PageTransition::LINK); + window_->Activate(); +} + +void Browser::OpenMobilePlanTabAndActivate() { + OpenURL(GURL(chrome::kChromeUIMobileSetupURL), GURL(), + NEW_FOREGROUND_TAB, PageTransition::LINK); + window_->Activate(); +} +#endif + +void Browser::OpenPluginsTabAndActivate() { + OpenURL(GURL(chrome::kAboutPluginsURL), GURL(), + NEW_FOREGROUND_TAB, PageTransition::LINK); + window_->Activate(); +} + +/////////////////////////////////////////////////////////////////////////////// + +// static +void Browser::SetNewHomePagePrefs(PrefService* prefs) { + const PrefService::Preference* home_page_pref = + prefs->FindPreference(prefs::kHomePage); + if (home_page_pref && + !home_page_pref->IsManaged() && + !prefs->HasPrefPath(prefs::kHomePage)) { + prefs->SetString(prefs::kHomePage, + GoogleURLTracker::kDefaultGoogleHomepage); + } + const PrefService::Preference* home_page_is_new_tab_page_pref = + prefs->FindPreference(prefs::kHomePageIsNewTabPage); + if (home_page_is_new_tab_page_pref && + !home_page_is_new_tab_page_pref->IsManaged() && + !prefs->HasPrefPath(prefs::kHomePageIsNewTabPage)) + prefs->SetBoolean(prefs::kHomePageIsNewTabPage, false); +} + +// static +void Browser::RegisterPrefs(PrefService* prefs) { + prefs->RegisterDictionaryPref(prefs::kBrowserWindowPlacement); + prefs->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex, 0); + prefs->RegisterIntegerPref(prefs::kDevToolsSplitLocation, -1); + prefs->RegisterDictionaryPref(prefs::kPreferencesWindowPlacement); + prefs->RegisterIntegerPref(prefs::kExtensionSidebarWidth, -1); +} + +// static +void Browser::RegisterUserPrefs(PrefService* prefs) { + prefs->RegisterStringPref(prefs::kHomePage, + chrome::kChromeUINewTabURL); + prefs->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true); + prefs->RegisterBooleanPref(prefs::kClearSiteDataOnExit, false); + prefs->RegisterBooleanPref(prefs::kShowHomeButton, false); +#if defined(OS_MACOSX) + // This really belongs in platform code, but there's no good place to + // initialize it between the time when the AppController is created + // (where there's no profile) and the time the controller gets another + // crack at the start of the main event loop. By that time, BrowserInit + // has already created the browser window, and it's too late: we need the + // pref to be already initialized. Doing it here also saves us from having + // to hard-code pref registration in the several unit tests that use + // this preference. + prefs->RegisterBooleanPref(prefs::kShowPageOptionsButtons, false); + prefs->RegisterBooleanPref(prefs::kShowUpdatePromotionInfoBar, true); +#endif + prefs->RegisterStringPref(prefs::kRecentlySelectedEncoding, ""); + prefs->RegisterBooleanPref(prefs::kDeleteBrowsingHistory, true); + prefs->RegisterBooleanPref(prefs::kDeleteDownloadHistory, true); + prefs->RegisterBooleanPref(prefs::kDeleteCache, true); + prefs->RegisterBooleanPref(prefs::kDeleteCookies, true); + prefs->RegisterBooleanPref(prefs::kDeletePasswords, false); + prefs->RegisterBooleanPref(prefs::kDeleteFormData, false); + prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0); + prefs->RegisterBooleanPref(prefs::kCheckDefaultBrowser, true); + prefs->RegisterBooleanPref(prefs::kShowOmniboxSearchHint, true); + prefs->RegisterBooleanPref(prefs::kWebAppCreateOnDesktop, true); + prefs->RegisterBooleanPref(prefs::kWebAppCreateInAppsMenu, true); + prefs->RegisterBooleanPref(prefs::kWebAppCreateInQuickLaunchBar, true); + prefs->RegisterBooleanPref(prefs::kUseVerticalTabs, false); + prefs->RegisterBooleanPref(prefs::kEnableTranslate, true); + prefs->RegisterBooleanPref(prefs::kRemotingHasSetupCompleted, false); + prefs->RegisterStringPref(prefs::kCloudPrintEmail, std::string()); + prefs->RegisterBooleanPref(prefs::kDevToolsDisabled, false); + prefs->RegisterRealPref(prefs::kDefaultZoomLevel, 0.0); +} + +// static +bool Browser::RunUnloadEventsHelper(TabContents* contents) { + // If the TabContents is not connected yet, then there's no unload + // handler we can fire even if the TabContents has an unload listener. + // One case where we hit this is in a tab that has an infinite loop + // before load. + if (TabHasUnloadListener(contents)) { + // If the page has unload listeners, then we tell the renderer to fire + // them. Once they have fired, we'll get a message back saying whether + // to proceed closing the page or not, which sends us back to this method + // with the HasUnloadListener bit cleared. + contents->render_view_host()->FirePageBeforeUnload(false); + return true; + } + return false; +} + +// static +Browser* Browser::GetBrowserForController( + const NavigationController* controller, int* index_result) { + BrowserList::const_iterator it; + for (it = BrowserList::begin(); it != BrowserList::end(); ++it) { + int index = (*it)->tab_handler_->GetTabStripModel()->GetIndexOfController( + controller); + if (index != TabStripModel::kNoTab) { + if (index_result) + *index_result = index; + return *it; + } + } + + return NULL; +} + +void Browser::ExecuteCommandWithDisposition( + int id, WindowOpenDisposition disposition) { + // No commands are enabled if there is not yet any selected tab. + // TODO(pkasting): It seems like we should not need this, because either + // most/all commands should not have been enabled yet anyway or the ones that + // are enabled should be global, or safe themselves against having no selected + // tab. However, Ben says he tried removing this before and got lots of + // crashes, e.g. from Windows sending WM_COMMANDs at random times during + // window construction. This probably could use closer examination someday. + if (!GetSelectedTabContents()) + return; + + DCHECK(command_updater_.IsCommandEnabled(id)) << "Invalid/disabled command"; + + // If command execution is blocked then just record the command and return. + if (block_command_execution_) { + // We actually only allow no more than one blocked command, otherwise some + // commands maybe lost. + DCHECK_EQ(last_blocked_command_id_, -1); + last_blocked_command_id_ = id; + last_blocked_command_disposition_ = disposition; + return; + } + + // The order of commands in this switch statement must match the function + // declaration order in browser.h! + switch (id) { + // Navigation commands + case IDC_BACK: GoBack(disposition); break; + case IDC_FORWARD: GoForward(disposition); break; + case IDC_RELOAD: Reload(disposition); break; + case IDC_RELOAD_IGNORING_CACHE: ReloadIgnoringCache(disposition); break; + case IDC_HOME: Home(disposition); break; + case IDC_OPEN_CURRENT_URL: OpenCurrentURL(); break; + case IDC_STOP: Stop(); break; + + // Window management commands + case IDC_NEW_WINDOW: NewWindow(); break; + case IDC_NEW_INCOGNITO_WINDOW: NewIncognitoWindow(); break; + case IDC_CLOSE_WINDOW: CloseWindow(); break; + case IDC_NEW_TAB: NewTab(); break; + case IDC_CLOSE_TAB: CloseTab(); break; + case IDC_SELECT_NEXT_TAB: SelectNextTab(); break; + case IDC_SELECT_PREVIOUS_TAB: SelectPreviousTab(); break; + case IDC_TABPOSE: OpenTabpose(); break; + case IDC_MOVE_TAB_NEXT: MoveTabNext(); break; + case IDC_MOVE_TAB_PREVIOUS: MoveTabPrevious(); break; + case IDC_SELECT_TAB_0: + case IDC_SELECT_TAB_1: + case IDC_SELECT_TAB_2: + case IDC_SELECT_TAB_3: + case IDC_SELECT_TAB_4: + case IDC_SELECT_TAB_5: + case IDC_SELECT_TAB_6: + case IDC_SELECT_TAB_7: SelectNumberedTab(id - IDC_SELECT_TAB_0); + break; + case IDC_SELECT_LAST_TAB: SelectLastTab(); break; + case IDC_DUPLICATE_TAB: DuplicateTab(); break; + case IDC_RESTORE_TAB: RestoreTab(); break; + case IDC_COPY_URL: WriteCurrentURLToClipboard(); break; + case IDC_SHOW_AS_TAB: ConvertPopupToTabbedBrowser(); break; + case IDC_FULLSCREEN: ToggleFullscreenMode(); break; + case IDC_EXIT: Exit(); break; + case IDC_TOGGLE_VERTICAL_TABS: ToggleUseVerticalTabs(); break; +#if defined(OS_CHROMEOS) + case IDC_SEARCH: Search(); break; +#endif + + // Page-related commands + case IDC_SAVE_PAGE: SavePage(); break; + case IDC_BOOKMARK_PAGE: BookmarkCurrentPage(); break; + case IDC_BOOKMARK_ALL_TABS: BookmarkAllTabs(); break; + case IDC_VIEW_SOURCE: ViewSource(); break; + case IDC_EMAIL_PAGE_LOCATION: EmailPageLocation(); break; + case IDC_PRINT: Print(); break; + case IDC_ENCODING_AUTO_DETECT: ToggleEncodingAutoDetect(); break; + case IDC_ENCODING_UTF8: + case IDC_ENCODING_UTF16LE: + case IDC_ENCODING_ISO88591: + case IDC_ENCODING_WINDOWS1252: + case IDC_ENCODING_GBK: + case IDC_ENCODING_GB18030: + case IDC_ENCODING_BIG5HKSCS: + case IDC_ENCODING_BIG5: + case IDC_ENCODING_KOREAN: + case IDC_ENCODING_SHIFTJIS: + case IDC_ENCODING_ISO2022JP: + case IDC_ENCODING_EUCJP: + case IDC_ENCODING_THAI: + case IDC_ENCODING_ISO885915: + case IDC_ENCODING_MACINTOSH: + case IDC_ENCODING_ISO88592: + case IDC_ENCODING_WINDOWS1250: + case IDC_ENCODING_ISO88595: + case IDC_ENCODING_WINDOWS1251: + case IDC_ENCODING_KOI8R: + case IDC_ENCODING_KOI8U: + case IDC_ENCODING_ISO88597: + case IDC_ENCODING_WINDOWS1253: + case IDC_ENCODING_ISO88594: + case IDC_ENCODING_ISO885913: + case IDC_ENCODING_WINDOWS1257: + case IDC_ENCODING_ISO88593: + case IDC_ENCODING_ISO885910: + case IDC_ENCODING_ISO885914: + case IDC_ENCODING_ISO885916: + case IDC_ENCODING_WINDOWS1254: + case IDC_ENCODING_ISO88596: + case IDC_ENCODING_WINDOWS1256: + case IDC_ENCODING_ISO88598: + case IDC_ENCODING_ISO88598I: + case IDC_ENCODING_WINDOWS1255: + case IDC_ENCODING_WINDOWS1258: OverrideEncoding(id); break; + + // Clipboard commands + case IDC_CUT: Cut(); break; + case IDC_COPY: Copy(); break; + case IDC_PASTE: Paste(); break; + + // Find-in-page + case IDC_FIND: Find(); break; + case IDC_FIND_NEXT: FindNext(); break; + case IDC_FIND_PREVIOUS: FindPrevious(); break; + + // Zoom + case IDC_ZOOM_PLUS: Zoom(PageZoom::ZOOM_IN); break; + case IDC_ZOOM_NORMAL: Zoom(PageZoom::RESET); break; + case IDC_ZOOM_MINUS: Zoom(PageZoom::ZOOM_OUT); break; + + // Focus various bits of UI + case IDC_FOCUS_TOOLBAR: FocusToolbar(); break; + case IDC_FOCUS_LOCATION: FocusLocationBar(); break; + case IDC_FOCUS_SEARCH: FocusSearch(); break; + case IDC_FOCUS_MENU_BAR: FocusAppMenu(); break; + case IDC_FOCUS_BOOKMARKS: FocusBookmarksToolbar(); break; + case IDC_FOCUS_CHROMEOS_STATUS: FocusChromeOSStatus(); break; + case IDC_FOCUS_NEXT_PANE: FocusNextPane(); break; + case IDC_FOCUS_PREVIOUS_PANE: FocusPreviousPane(); break; + + // Show various bits of UI + case IDC_OPEN_FILE: OpenFile(); break; + case IDC_CREATE_SHORTCUTS: OpenCreateShortcutsDialog(); break; + case IDC_DEV_TOOLS: ToggleDevToolsWindow( + DEVTOOLS_TOGGLE_ACTION_NONE); + break; + case IDC_DEV_TOOLS_CONSOLE: ToggleDevToolsWindow( + DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE); + break; + case IDC_DEV_TOOLS_INSPECT: ToggleDevToolsWindow( + DEVTOOLS_TOGGLE_ACTION_INSPECT); + break; + case IDC_TASK_MANAGER: OpenTaskManager(); break; + case IDC_REPORT_BUG: OpenBugReportDialog(); break; + + case IDC_SHOW_BOOKMARK_BAR: ToggleBookmarkBar(); break; + + case IDC_SHOW_BOOKMARK_MANAGER: OpenBookmarkManager(); break; + case IDC_SHOW_APP_MENU: ShowAppMenu(); break; + case IDC_SHOW_HISTORY: ShowHistoryTab(); break; + case IDC_SHOW_DOWNLOADS: ShowDownloadsTab(); break; + case IDC_MANAGE_EXTENSIONS: ShowExtensionsTab(); break; + case IDC_SYNC_BOOKMARKS: OpenSyncMyBookmarksDialog(); break; +#if defined(ENABLE_REMOTING) + case IDC_REMOTING_SETUP: OpenRemotingSetupDialog(); break; +#endif + case IDC_OPTIONS: OpenOptionsDialog(); break; + case IDC_EDIT_SEARCH_ENGINES: OpenKeywordEditor(); break; + case IDC_VIEW_PASSWORDS: OpenPasswordManager(); break; + case IDC_CLEAR_BROWSING_DATA: OpenClearBrowsingDataDialog(); break; + case IDC_IMPORT_SETTINGS: OpenImportSettingsDialog(); break; + case IDC_ABOUT: OpenAboutChromeDialog(); break; + case IDC_UPGRADE_DIALOG: OpenUpdateChromeDialog(); break; + case IDC_VIEW_INCOMPATIBILITIES: ShowAboutConflictsTab(); break; + case IDC_HELP_PAGE: OpenHelpTab(); break; +#if defined(OS_CHROMEOS) + case IDC_SYSTEM_OPTIONS: OpenSystemOptionsDialog(); break; + case IDC_INTERNET_OPTIONS: OpenInternetOptionsDialog(); break; + case IDC_LANGUAGE_OPTIONS: OpenLanguageOptionsDialog(); break; +#endif + + default: + LOG(WARNING) << "Received Unimplemented Command: " << id; + break; + } +} + +bool Browser::IsReservedCommand(int command_id) { + return command_id == IDC_CLOSE_TAB || + command_id == IDC_CLOSE_WINDOW || + command_id == IDC_NEW_INCOGNITO_WINDOW || + command_id == IDC_NEW_TAB || + command_id == IDC_NEW_WINDOW || + command_id == IDC_RESTORE_TAB || + command_id == IDC_SELECT_NEXT_TAB || + command_id == IDC_SELECT_PREVIOUS_TAB || + command_id == IDC_TABPOSE || + command_id == IDC_EXIT || + command_id == IDC_SEARCH; +} + +void Browser::SetBlockCommandExecution(bool block) { + block_command_execution_ = block; + if (block) { + last_blocked_command_id_ = -1; + last_blocked_command_disposition_ = CURRENT_TAB; + } +} + +int Browser::GetLastBlockedCommand(WindowOpenDisposition* disposition) { + if (disposition) + *disposition = last_blocked_command_disposition_; + return last_blocked_command_id_; +} + +void Browser::UpdateUIForNavigationInTab(TabContents* contents, + PageTransition::Type transition, + bool user_initiated) { + tabstrip_model()->TabNavigating(contents, transition); + + bool contents_is_selected = contents == GetSelectedTabContents(); + if (user_initiated && contents_is_selected && window()->GetLocationBar()) { + // Forcibly reset the location bar if the url is going to change in the + // current tab, since otherwise it won't discard any ongoing user edits, + // since it doesn't realize this is a user-initiated action. + window()->GetLocationBar()->Revert(); + } + + if (GetStatusBubble()) + GetStatusBubble()->Hide(); + + // Update the location bar. This is synchronous. We specifically don't + // update the load state since the load hasn't started yet and updating it + // will put it out of sync with the actual state like whether we're + // displaying a favicon, which controls the throbber. If we updated it here, + // the throbber will show the default favicon for a split second when + // navigating away from the new tab page. + ScheduleUIUpdate(contents, TabContents::INVALIDATE_URL); + + if (contents_is_selected) + contents->Focus(); +} + +GURL Browser::GetHomePage() const { + // --homepage overrides any preferences. + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + if (command_line.HasSwitch(switches::kHomePage)) { + // TODO(evanm): clean up usage of DIR_CURRENT. + // http://code.google.com/p/chromium/issues/detail?id=60630 + // For now, allow this code to call getcwd(). + base::ThreadRestrictions::ScopedAllowIO allow_io; + + FilePath browser_directory; + PathService::Get(base::DIR_CURRENT, &browser_directory); + GURL home_page(URLFixerUpper::FixupRelativeFile(browser_directory, + command_line.GetSwitchValuePath(switches::kHomePage))); + if (home_page.is_valid()) + return home_page; + } + + if (profile_->GetPrefs()->GetBoolean(prefs::kHomePageIsNewTabPage)) + return GURL(chrome::kChromeUINewTabURL); + GURL home_page(URLFixerUpper::FixupURL( + profile_->GetPrefs()->GetString(prefs::kHomePage), + std::string())); + if (!home_page.is_valid()) + return GURL(chrome::kChromeUINewTabURL); + return home_page; +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, PageNavigator implementation: + +void Browser::OpenURL(const GURL& url, const GURL& referrer, + WindowOpenDisposition disposition, + PageTransition::Type transition) { + OpenURLFromTab(NULL, url, referrer, disposition, transition); +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, CommandUpdater::CommandUpdaterDelegate implementation: + +void Browser::ExecuteCommand(int id) { + ExecuteCommandWithDisposition(id, CURRENT_TAB); +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, TabHandlerDelegate implementation: + +Profile* Browser::GetProfile() const { + return profile(); +} + +Browser* Browser::AsBrowser() { + return this; +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, TabStripModelDelegate implementation: + +TabContents* Browser::AddBlankTab(bool foreground) { + return AddBlankTabAt(-1, foreground); +} + +TabContents* Browser::AddBlankTabAt(int index, bool foreground) { + // Time new tab page creation time. We keep track of the timing data in + // TabContents, but we want to include the time it takes to create the + // TabContents object too. + base::TimeTicks new_tab_start_time = base::TimeTicks::Now(); + browser::NavigateParams params(this, GURL(chrome::kChromeUINewTabURL), + PageTransition::TYPED); + params.tabstrip_add_types = + foreground ? TabStripModel::ADD_SELECTED : TabStripModel::ADD_NONE; + params.disposition = foreground ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB; + params.tabstrip_index = index; + browser::Navigate(¶ms); + params.target_contents->set_new_tab_start_time(new_tab_start_time); + return params.target_contents; +} + +Browser* Browser::CreateNewStripWithContents(TabContents* detached_contents, + const gfx::Rect& window_bounds, + const DockInfo& dock_info, + bool maximize) { + DCHECK(CanSupportWindowFeature(FEATURE_TABSTRIP)); + + gfx::Rect new_window_bounds = window_bounds; + if (dock_info.GetNewWindowBounds(&new_window_bounds, &maximize)) + dock_info.AdjustOtherWindowBounds(); + + // Create an empty new browser window the same size as the old one. + Browser* browser = new Browser(TYPE_NORMAL, profile_); + browser->set_override_bounds(new_window_bounds); + browser->set_maximized_state( + maximize ? MAXIMIZED_STATE_MAXIMIZED : MAXIMIZED_STATE_UNMAXIMIZED); + browser->CreateBrowserWindow(); + browser->tabstrip_model()->AppendTabContents(detached_contents, true); + // Make sure the loading state is updated correctly, otherwise the throbber + // won't start if the page is loading. + browser->LoadingStateChanged(detached_contents); + return browser; +} + +void Browser::ContinueDraggingDetachedTab(TabContents* contents, + const gfx::Rect& window_bounds, + const gfx::Rect& tab_bounds) { + Browser* browser = new Browser(TYPE_NORMAL, profile_); + browser->set_override_bounds(window_bounds); + browser->CreateBrowserWindow(); + browser->tabstrip_model()->AppendTabContents(contents, true); + browser->LoadingStateChanged(contents); + browser->window()->Show(); + browser->window()->ContinueDraggingDetachedTab(tab_bounds); +} + +int Browser::GetDragActions() const { + return TabStripModelDelegate::TAB_TEAROFF_ACTION | (tab_count() > 1 ? + TabStripModelDelegate::TAB_MOVE_ACTION : 0); +} + +TabContents* Browser::CreateTabContentsForURL( + const GURL& url, const GURL& referrer, Profile* profile, + PageTransition::Type transition, bool defer_load, + SiteInstance* instance) const { + TabContents* contents = new TabContents(profile, instance, + MSG_ROUTING_NONE, + tab_handler_->GetTabStripModel()->GetSelectedTabContents(), NULL); + + if (!defer_load) { + // Load the initial URL before adding the new tab contents to the tab strip + // so that the tab contents has navigation state. + contents->controller().LoadURL(url, referrer, transition); + } + + return contents; +} + +bool Browser::CanDuplicateContentsAt(int index) { + NavigationController& nc = GetTabContentsAt(index)->controller(); + return nc.tab_contents() && nc.GetLastCommittedEntry(); +} + +void Browser::DuplicateContentsAt(int index) { + TabContents* contents = GetTabContentsAt(index); + TabContents* new_contents = NULL; + DCHECK(contents); + bool pinned = false; + + if (CanSupportWindowFeature(FEATURE_TABSTRIP)) { + // If this is a tabbed browser, just create a duplicate tab inside the same + // window next to the tab being duplicated. + new_contents = contents->Clone(); + pinned = tab_handler_->GetTabStripModel()->IsTabPinned(index); + int add_types = TabStripModel::ADD_SELECTED | + TabStripModel::ADD_INHERIT_GROUP | + (pinned ? TabStripModel::ADD_PINNED : 0); + tab_handler_->GetTabStripModel()->InsertTabContentsAt(index + 1, + new_contents, + add_types); + } else { + Browser* browser = NULL; + if (type_ & TYPE_APP) { + DCHECK((type_ & TYPE_POPUP) == 0); + DCHECK(type_ != TYPE_APP_PANEL); + browser = Browser::CreateForApp(app_name_, extension_app_, profile_, + false); + } else if (type_ == TYPE_POPUP) { + browser = Browser::CreateForType(TYPE_POPUP, profile_); + } + + // Preserve the size of the original window. The new window has already + // been given an offset by the OS, so we shouldn't copy the old bounds. + BrowserWindow* new_window = browser->window(); + new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(), + window()->GetRestoredBounds().size())); + + // We need to show the browser now. Otherwise ContainerWin assumes the + // TabContents is invisible and won't size it. + browser->window()->Show(); + + // The page transition below is only for the purpose of inserting the tab. + new_contents = browser->AddTab( + contents->Clone()->controller().tab_contents(), + PageTransition::LINK); + } + + if (profile_->HasSessionService()) { + SessionService* session_service = profile_->GetSessionService(); + if (session_service) + session_service->TabRestored(&new_contents->controller(), pinned); + } +} + +void Browser::CloseFrameAfterDragSession() { +#if defined(OS_WIN) || defined(OS_LINUX) + // This is scheduled to run after we return to the message loop because + // otherwise the frame will think the drag session is still active and ignore + // the request. + // TODO(port): figure out what is required here in a cross-platform world + MessageLoop::current()->PostTask( + FROM_HERE, method_factory_.NewRunnableMethod(&Browser::CloseFrame)); +#endif +} + +void Browser::CreateHistoricalTab(TabContents* contents) { + // We don't create historical tabs for incognito windows or windows without + // profiles. + if (!profile() || profile()->IsOffTheRecord() || + !profile()->GetTabRestoreService()) { + return; + } + + // We only create historical tab entries for tabbed browser windows. + if (CanSupportWindowFeature(FEATURE_TABSTRIP)) { + profile()->GetTabRestoreService()->CreateHistoricalTab( + &contents->controller()); + } +} + +bool Browser::RunUnloadListenerBeforeClosing(TabContents* contents) { + return Browser::RunUnloadEventsHelper(contents); +} + +bool Browser::CanReloadContents(TabContents* source) const { + return type() != TYPE_DEVTOOLS; +} + +bool Browser::CanCloseContentsAt(int index) { + if (!CanCloseTab()) + return false; + if (tab_handler_->GetTabStripModel()->count() > 1) + return true; + // We are closing the last tab for this browser. Make sure to check for + // in-progress downloads. + // Note that the next call when it returns false will ask the user for + // confirmation before closing the browser if the user decides so. + return CanCloseWithInProgressDownloads(); +} + +bool Browser::CanBookmarkAllTabs() const { + BookmarkModel* model = profile()->GetBookmarkModel(); + return (model && model->IsLoaded() && (tab_count() > 1)); +} + +void Browser::BookmarkAllTabs() { + BookmarkModel* model = profile()->GetBookmarkModel(); + DCHECK(model && model->IsLoaded()); + + BookmarkEditor::EditDetails details; + details.type = BookmarkEditor::EditDetails::NEW_FOLDER; + bookmark_utils::GetURLsForOpenTabs(this, &(details.urls)); + DCHECK(!details.urls.empty()); + + BookmarkEditor::Show(window()->GetNativeHandle(), profile_, + model->GetParentForNewNodes(), details, + BookmarkEditor::SHOW_TREE); +} + +bool Browser::CanCloseTab() const { + TabCloseableStateWatcher* watcher = + g_browser_process->tab_closeable_state_watcher(); + return !watcher || watcher->CanCloseTab(this); +} + +void Browser::ToggleUseVerticalTabs() { + use_vertical_tabs_.SetValue(!UseVerticalTabs()); + UseVerticalTabsChanged(); +} + +bool Browser::LargeIconsPermitted() const { + // We don't show the big icons in tabs for TYPE_EXTENSION_APP windows because + // for those windows, we already have a big icon in the top-left outside any + // tab. Having big tab icons too looks kinda redonk. + return TYPE_EXTENSION_APP != type(); +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, TabStripModelObserver implementation: + +void Browser::TabInsertedAt(TabContents* contents, + int index, + bool foreground) { + contents->set_delegate(this); + contents->controller().SetWindowID(session_id()); + + SyncHistoryWithTabs(index); + + // Make sure the loading state is updated correctly, otherwise the throbber + // won't start if the page is loading. + LoadingStateChanged(contents); + + // If the tab crashes in the beforeunload or unload handler, it won't be + // able to ack. But we know we can close it. + registrar_.Add(this, NotificationType::TAB_CONTENTS_DISCONNECTED, + Source(contents)); +} + +void Browser::TabClosingAt(TabStripModel* tab_strip_model, + TabContents* contents, + int index) { + NotificationService::current()->Notify( + NotificationType::TAB_CLOSING, + Source(&contents->controller()), + NotificationService::NoDetails()); + + // Sever the TabContents' connection back to us. + contents->set_delegate(NULL); +} + +void Browser::TabDetachedAt(TabContents* contents, int index) { + TabDetachedAtImpl(contents, index, DETACH_TYPE_DETACH); +} + +void Browser::TabDeselectedAt(TabContents* contents, int index) { + if (instant()) + instant()->DestroyPreviewContents(); + + // Save what the user's currently typing, so it can be restored when we + // switch back to this tab. + window_->GetLocationBar()->SaveStateToContents(contents); +} + +void Browser::TabSelectedAt(TabContents* old_contents, + TabContents* new_contents, + int index, + bool user_gesture) { + DCHECK(old_contents != new_contents); + + // If we have any update pending, do it now. + if (!chrome_updater_factory_.empty() && old_contents) + ProcessPendingUIUpdates(); + + // Propagate the profile to the location bar. + UpdateToolbar(true); + + // Update reload/stop state. + UpdateReloadStopState(new_contents->is_loading(), true); + + // Update commands to reflect current state. + UpdateCommandsForTabState(); + + // Reset the status bubble. + StatusBubble* status_bubble = GetStatusBubble(); + if (status_bubble) { + status_bubble->Hide(); + + // Show the loading state (if any). + status_bubble->SetStatus(WideToUTF16Hack( + GetSelectedTabContents()->GetStatusText())); + } + + if (HasFindBarController()) { + find_bar_controller_->ChangeTabContents(new_contents); + find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true); + } + + // Update sessions. Don't force creation of sessions. If sessions doesn't + // exist, the change will be picked up by sessions when created. + if (profile_->HasSessionService()) { + SessionService* session_service = profile_->GetSessionService(); + if (session_service && !tab_handler_->GetTabStripModel()->closing_all()) { + session_service->SetSelectedTabInWindow( + session_id(), tab_handler_->GetTabStripModel()->selected_index()); + } + } +} + +void Browser::TabMoved(TabContents* contents, + int from_index, + int to_index) { + DCHECK(from_index >= 0 && to_index >= 0); + // Notify the history service. + SyncHistoryWithTabs(std::min(from_index, to_index)); +} + +void Browser::TabReplacedAt(TabContents* old_contents, + TabContents* new_contents, + int index) { + TabDetachedAtImpl(old_contents, index, DETACH_TYPE_REPLACE); + TabInsertedAt(new_contents, index, + (index == tab_handler_->GetTabStripModel()->selected_index())); + + int entry_count = new_contents->controller().entry_count(); + if (entry_count > 0) { + // Send out notification so that observers are updated appropriately. + new_contents->controller().NotifyEntryChanged( + new_contents->controller().GetEntryAtIndex(entry_count - 1), + entry_count - 1); + } + + SessionService* session_service = profile()->GetSessionService(); + if (session_service) { + // The new_contents may end up with a different navigation stack. Force + // the session service to update itself. + session_service->TabRestored( + &new_contents->controller(), + tab_handler_->GetTabStripModel()->IsTabPinned(index)); + } +} + +void Browser::TabPinnedStateChanged(TabContents* contents, int index) { + if (!profile()->HasSessionService()) + return; + SessionService* session_service = profile()->GetSessionService(); + if (session_service) { + session_service->SetPinnedState( + session_id(), + GetTabContentsAt(index)->controller().session_id(), + tab_handler_->GetTabStripModel()->IsTabPinned(index)); + } +} + +void Browser::TabStripEmpty() { + // Close the frame after we return to the message loop (not immediately, + // otherwise it will destroy this object before the stack has a chance to + // cleanly unwind.) + // Note: This will be called several times if TabStripEmpty is called several + // times. This is because it does not close the window if tabs are + // still present. + // NOTE: If you change to be immediate (no invokeLater) then you'll need to + // update BrowserList::CloseAllBrowsers. + MessageLoop::current()->PostTask( + FROM_HERE, method_factory_.NewRunnableMethod(&Browser::CloseFrame)); +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, TabContentsDelegate implementation: + +void Browser::OpenURLFromTab(TabContents* source, + const GURL& url, + const GURL& referrer, + WindowOpenDisposition disposition, + PageTransition::Type transition) { + browser::NavigateParams params(this, url, transition); + params.source_contents = source; + params.referrer = referrer; + params.disposition = disposition; + params.tabstrip_add_types = TabStripModel::ADD_NONE; + browser::Navigate(¶ms); +} + +void Browser::NavigationStateChanged(const TabContents* source, + unsigned changed_flags) { + // Only update the UI when something visible has changed. + if (changed_flags) + ScheduleUIUpdate(source, changed_flags); + + // We don't schedule updates to commands since they will only change once per + // navigation, so we don't have to worry about flickering. + if (changed_flags & TabContents::INVALIDATE_URL) + UpdateCommandsForTabState(); +} + +void Browser::AddNewContents(TabContents* source, + TabContents* new_contents, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture) { + // No code for this yet + DCHECK(disposition != SAVE_TO_DISK); + // Can't create a new contents for the current tab - invalid case. + DCHECK(disposition != CURRENT_TAB); + + // TODO(beng): This belongs behind the platform-specific View interface. + // That's why it's there. +#if defined(OS_CHROMEOS) + if (disposition == NEW_POPUP) { + // If the popup is bigger than a given factor of the screen, then + // turn it into a foreground tab (on chrome os only) + // Also check for width or height == 0, which would otherwise indicate + // a tab sized popup window. + GdkScreen* screen = gdk_screen_get_default(); + int max_width = gdk_screen_get_width(screen) * kPopupMaxWidthFactor; + int max_height = gdk_screen_get_height(screen) * kPopupMaxHeightFactor; + if (initial_pos.width() > max_width || initial_pos.width() == 0 || + initial_pos.height() > max_height || initial_pos.height() == 0) { + disposition = NEW_FOREGROUND_TAB; + } + } +#endif + + browser::NavigateParams params(this, new_contents); + params.source_contents = source; + params.disposition = disposition; + params.window_bounds = initial_pos; + browser::Navigate(¶ms); +} + +void Browser::ActivateContents(TabContents* contents) { + tab_handler_->GetTabStripModel()->SelectTabContentsAt( + tab_handler_->GetTabStripModel()->GetIndexOfTabContents(contents), false); + window_->Activate(); +} + +void Browser::DeactivateContents(TabContents* contents) { + window_->Deactivate(); +} + +void Browser::LoadingStateChanged(TabContents* source) { + window_->UpdateLoadingAnimations( + tab_handler_->GetTabStripModel()->TabsAreLoading()); + window_->UpdateTitleBar(); + + if (source == GetSelectedTabContents()) { + UpdateReloadStopState(source->is_loading(), false); + if (GetStatusBubble()) { + GetStatusBubble()->SetStatus(WideToUTF16( + GetSelectedTabContents()->GetStatusText())); + } + + if (!source->is_loading() && + pending_web_app_action_ == UPDATE_SHORTCUT) { + // Schedule a shortcut update when web application info is available if + // last committed entry is not NULL. Last committed entry could be NULL + // when an interstitial page is injected (e.g. bad https certificate, + // malware site etc). When this happens, we abort the shortcut update. + NavigationEntry* entry = source->controller().GetLastCommittedEntry(); + if (entry) { + source->render_view_host()->GetApplicationInfo(entry->page_id()); + } else { + pending_web_app_action_ = NONE; + } + } + } +} + +void Browser::CloseContents(TabContents* source) { + if (is_attempting_to_close_browser_) { + // If we're trying to close the browser, just clear the state related to + // waiting for unload to fire. Don't actually try to close the tab as it + // will go down the slow shutdown path instead of the fast path of killing + // all the renderer processes. + ClearUnloadState(source); + return; + } + + int index = tab_handler_->GetTabStripModel()->GetIndexOfTabContents(source); + if (index == TabStripModel::kNoTab) { + NOTREACHED() << "CloseContents called for tab not in our strip"; + return; + } + tab_handler_->GetTabStripModel()->CloseTabContentsAt( + index, + TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); +} + +void Browser::MoveContents(TabContents* source, const gfx::Rect& pos) { + if ((type() & TYPE_POPUP) == 0) { + NOTREACHED() << "moving invalid browser type"; + return; + } + window_->SetBounds(pos); +} + +void Browser::DetachContents(TabContents* source) { + int index = tab_handler_->GetTabStripModel()->GetIndexOfTabContents(source); + if (index >= 0) + tab_handler_->GetTabStripModel()->DetachTabContentsAt(index); +} + +bool Browser::IsPopup(const TabContents* source) const { + // A non-tabbed BROWSER is an unconstrained popup. + return !!(type() & TYPE_POPUP); +} + +void Browser::ToolbarSizeChanged(TabContents* source, bool is_animating) { + if (source == GetSelectedTabContents() || source == NULL) { + // This will refresh the shelf if needed. + window_->SelectedTabToolbarSizeChanged(is_animating); + } +} + +void Browser::URLStarredChanged(TabContents* source, bool starred) { + if (source == GetSelectedTabContents()) + window_->SetStarredState(starred); +} + +void Browser::ContentsMouseEvent( + TabContents* source, const gfx::Point& location, bool motion) { + if (!GetStatusBubble()) + return; + + if (source == GetSelectedTabContents()) { + GetStatusBubble()->MouseMoved(location, !motion); + if (!motion) + GetStatusBubble()->SetURL(GURL(), string16()); + } +} + +void Browser::UpdateTargetURL(TabContents* source, const GURL& url) { + if (!GetStatusBubble()) + return; + + if (source == GetSelectedTabContents()) { + PrefService* prefs = profile_->GetPrefs(); + GetStatusBubble()->SetURL( + url, UTF8ToUTF16(prefs->GetString(prefs::kAcceptLanguages))); + } +} + +void Browser::UpdateDownloadShelfVisibility(bool visible) { + if (GetStatusBubble()) + GetStatusBubble()->UpdateDownloadShelfVisibility(visible); +} + +bool Browser::UseVerticalTabs() const { + return use_vertical_tabs_.GetValue(); +} + +void Browser::ContentsZoomChange(bool zoom_in) { + ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS); +} + +void Browser::OnContentSettingsChange(TabContents* source) { + if (source == GetSelectedTabContents()) + window_->GetLocationBar()->UpdateContentSettingsIcons(); +} + +void Browser::SetTabContentBlocked(TabContents* contents, bool blocked) { + int index = tabstrip_model()->GetIndexOfTabContents(contents); + if (index == TabStripModel::kNoTab) { + NOTREACHED(); + return; + } + tabstrip_model()->SetTabBlocked(index, blocked); +} + +void Browser::TabContentsFocused(TabContents* tab_content) { + window_->TabContentsFocused(tab_content); +} + +bool Browser::TakeFocus(bool reverse) { + NotificationService::current()->Notify( + NotificationType::FOCUS_RETURNED_TO_BROWSER, + Source(this), + NotificationService::NoDetails()); + return false; +} + +bool Browser::IsApplication() const { + return (type_ & TYPE_APP) != 0; +} + +void Browser::ConvertContentsToApplication(TabContents* contents) { + const GURL& url = contents->controller().GetActiveEntry()->url(); + std::string app_name = web_app::GenerateApplicationNameFromURL(url); + RegisterAppPrefs(app_name); + + DetachContents(contents); + Browser* browser = Browser::CreateForApp(app_name, NULL, profile_, false); + browser->tabstrip_model()->AppendTabContents(contents, true); + TabContents* tab_contents = browser->GetSelectedTabContents(); + tab_contents->GetMutableRendererPrefs()->can_accept_load_drops = false; + tab_contents->render_view_host()->SyncRendererPrefs(); + browser->window()->Show(); +} + +bool Browser::ShouldDisplayURLField() { + return !IsApplication(); +} + +void Browser::BeforeUnloadFired(TabContents* tab, + bool proceed, + bool* proceed_to_fire_unload) { + if (!is_attempting_to_close_browser_) { + *proceed_to_fire_unload = proceed; + if (!proceed) + tab->set_closed_by_user_gesture(false); + return; + } + + if (!proceed) { + CancelWindowClose(); + *proceed_to_fire_unload = false; + tab->set_closed_by_user_gesture(false); + return; + } + + if (RemoveFromSet(&tabs_needing_before_unload_fired_, tab)) { + // Now that beforeunload has fired, put the tab on the queue to fire + // unload. + tabs_needing_unload_fired_.insert(tab); + ProcessPendingTabs(); + // We want to handle firing the unload event ourselves since we want to + // fire all the beforeunload events before attempting to fire the unload + // events should the user cancel closing the browser. + *proceed_to_fire_unload = false; + return; + } + + *proceed_to_fire_unload = true; +} + +gfx::Rect Browser::GetRootWindowResizerRect() const { + return window_->GetRootWindowResizerRect(); +} + +void Browser::ShowHtmlDialog(HtmlDialogUIDelegate* delegate, + gfx::NativeWindow parent_window) { + window_->ShowHTMLDialog(delegate, parent_window); +} + +void Browser::SetFocusToLocationBar(bool select_all) { + // Two differences between this and FocusLocationBar(): + // (1) This doesn't get recorded in user metrics, since it's called + // internally. + // (2) This checks whether the location bar can be focused, and if not, clears + // the focus. FocusLocationBar() is only reached when the location bar is + // focusable, but this may be reached at other times, e.g. while in + // fullscreen mode, where we need to leave focus in a consistent state. + window_->SetFocusToLocationBar(select_all); +} + +void Browser::RenderWidgetShowing() { + window_->DisableInactiveFrame(); +} + +int Browser::GetExtraRenderViewHeight() const { + return window_->GetExtraRenderViewHeight(); +} + +void Browser::OnStartDownload(DownloadItem* download, TabContents* tab) { + if (!window()) + return; + +#if defined(OS_CHROMEOS) + // Don't show content browser for extension/theme downloads from gallery. + if (download->is_extension_install()) { + ExtensionsService* service = profile_->GetExtensionsService(); + if (service && service->IsDownloadFromGallery(download->url(), + download->referrer_url())) { + return; + } + } + + // skip the download shelf and just open the file browser in chromeos + std::string arg = download->full_path().DirName().value(); + FileBrowseUI::OpenPopup(profile_, + arg, + FileBrowseUI::kPopupWidth, + FileBrowseUI::kPopupHeight); + +#else + // GetDownloadShelf creates the download shelf if it was not yet created. + window()->GetDownloadShelf()->AddDownload(new DownloadItemModel(download)); + + // Don't show the animation for "Save file" downloads. + if (download->total_bytes() <= 0) + return; + + // For non-theme extensions, we don't show the download animation. + if (download->is_extension_install() && + !ExtensionsService::IsDownloadFromMiniGallery(download->url())) + return; + + TabContents* current_tab = GetSelectedTabContents(); + // We make this check for the case of minimized windows, unit tests, etc. + if (platform_util::IsVisible(current_tab->GetNativeView()) && + Animation::ShouldRenderRichAnimation()) { + DownloadStartedAnimation::Show(current_tab); + } +#endif + + // If the download occurs in a new tab, close it + if (tab->controller().IsInitialNavigation() && + GetConstrainingContents(tab) == tab && tab_count() > 1) { + CloseContents(tab); + } +} + +void Browser::ConfirmSetDefaultSearchProvider( + TabContents* tab_contents, + TemplateURL* template_url, + TemplateURLModel* template_url_model) { + window()->ConfirmSetDefaultSearchProvider(tab_contents, template_url, + template_url_model); +} +void Browser::ConfirmAddSearchProvider(const TemplateURL* template_url, + Profile* profile) { + window()->ConfirmAddSearchProvider(template_url, profile); +} + +void Browser::ShowPageInfo(Profile* profile, + const GURL& url, + const NavigationEntry::SSLStatus& ssl, + bool show_history) { + window()->ShowPageInfo(profile, url, ssl, show_history); +} + +bool Browser::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, + bool* is_keyboard_shortcut) { + return window()->PreHandleKeyboardEvent(event, is_keyboard_shortcut); +} + +void Browser::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) { + window()->HandleKeyboardEvent(event); +} + +void Browser::ShowRepostFormWarningDialog(TabContents *tab_contents) { + window()->ShowRepostFormWarningDialog(tab_contents); +} + +void Browser::ShowContentSettingsWindow(ContentSettingsType content_type) { + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableTabbedOptions)) { + ShowOptionsTab( + chrome::kContentSettingsSubPage + kHashMark + + ContentSettingsHandler::ContentSettingsTypeToGroupName(content_type)); + } else { + window()->ShowContentSettingsWindow(content_type, + profile_->GetOriginalProfile()); + } +} + +void Browser::ShowCollectedCookiesDialog(TabContents *tab_contents) { + window()->ShowCollectedCookiesDialog(tab_contents); +} + +bool Browser::ShouldAddNavigationToHistory( + const history::HistoryAddPageArgs& add_page_args, + NavigationType::Type navigation_type) { + // Don't update history if running as app. + return !IsApplication(); +} + +void Browser::OnDidGetApplicationInfo(TabContents* tab_contents, + int32 page_id) { + TabContents* current_tab = GetSelectedTabContents(); + if (current_tab != tab_contents) + return; + + NavigationEntry* entry = current_tab->controller().GetLastCommittedEntry(); + if (!entry || (entry->page_id() != page_id)) + return; + + switch (pending_web_app_action_) { + case CREATE_SHORTCUT: { + window()->ShowCreateShortcutsDialog(current_tab); + break; + } + case UPDATE_SHORTCUT: { + web_app::UpdateShortcutForTabContents(current_tab); + break; + } + default: + NOTREACHED(); + break; + } + + pending_web_app_action_ = NONE; +} + +void Browser::ContentRestrictionsChanged(TabContents* source) { + UpdateCommandsForContentRestrictionState(); +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, SelectFileDialog::Listener implementation: + +void Browser::FileSelected(const FilePath& path, int index, void* params) { + profile_->set_last_selected_directory(path.DirName()); + GURL file_url = net::FilePathToFileURL(path); + if (!file_url.is_empty()) + OpenURL(file_url, GURL(), CURRENT_TAB, PageTransition::TYPED); +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, NotificationObserver implementation: + +void Browser::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + switch (type.value) { + case NotificationType::TAB_CONTENTS_DISCONNECTED: + if (is_attempting_to_close_browser_) { + // Need to do this asynchronously as it will close the tab, which is + // currently on the call stack above us. + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod(&Browser::ClearUnloadState, + Source(source).ptr())); + } + break; + + case NotificationType::SSL_VISIBLE_STATE_CHANGED: + // When the current tab's SSL state changes, we need to update the URL + // bar to reflect the new state. Note that it's possible for the selected + // tab contents to be NULL. This is because we listen for all sources + // (NavigationControllers) for convenience, so the notification could + // actually be for a different window while we're doing asynchronous + // closing of this one. + if (GetSelectedTabContents() && + &GetSelectedTabContents()->controller() == + Source(source).ptr()) + UpdateToolbar(false); + break; + + case NotificationType::EXTENSION_UPDATE_DISABLED: { + // Show the UI if the extension was disabled for escalated permissions. + Profile* profile = Source(source).ptr(); + if (profile_->IsSameProfile(profile)) { + ExtensionsService* service = profile->GetExtensionsService(); + DCHECK(service); + const Extension* extension = Details(details).ptr(); + if (service->extension_prefs()->DidExtensionEscalatePermissions( + extension->id())) + ShowExtensionDisabledUI(service, profile_, extension); + } + break; + } + + case NotificationType::EXTENSION_UNLOADED: + case NotificationType::EXTENSION_UNLOADED_DISABLED: { + window()->GetLocationBar()->UpdatePageActions(); + + // Close any tabs from the unloaded extension. + const Extension* extension = Details(details).ptr(); + TabStripModel* model = tab_handler_->GetTabStripModel(); + for (int i = model->count() - 1; i >= 0; --i) { + TabContents* tc = model->GetTabContentsAt(i); + if (tc->GetURL().SchemeIs(chrome::kExtensionScheme) && + tc->GetURL().host() == extension->id()) { + CloseTabContents(tc); + } + } + + break; + } + + case NotificationType::EXTENSION_PROCESS_TERMINATED: { + window()->GetLocationBar()->InvalidatePageActions(); + + TabContents* tab_contents = GetSelectedTabContents(); + if (!tab_contents) + break; + ExtensionsService* extensions_service = + Source(source).ptr()->GetExtensionsService(); + ExtensionHost* extension_host = Details(details).ptr(); + tab_contents->AddInfoBar(new CrashedExtensionInfoBarDelegate( + tab_contents, extensions_service, extension_host->extension())); + break; + } + + case NotificationType::EXTENSION_LOADED: { + window()->GetLocationBar()->UpdatePageActions(); + + // If any "This extension has crashed" InfoBarDelegates are around for + // this extension, it means that it has been reloaded in another window + // so just remove the remaining CrashedExtensionInfoBarDelegate objects. + TabContents* tab_contents = GetSelectedTabContents(); + if (!tab_contents) + break; + const Extension* extension = Details(details).ptr(); + CrashedExtensionInfoBarDelegate* delegate = NULL; + for (int i = 0; i < tab_contents->infobar_delegate_count();) { + delegate = tab_contents->GetInfoBarDelegateAt(i)-> + AsCrashedExtensionInfoBarDelegate(); + if (delegate && delegate->extension_id() == extension->id()) { + tab_contents->RemoveInfoBar(delegate); + continue; + } + // Only increment |i| if we didn't remove an entry. + ++i; + } + break; + } + + case NotificationType::BROWSER_THEME_CHANGED: + window()->UserChangedTheme(); + break; + + case NotificationType::EXTENSION_READY_FOR_INSTALL: { + // Handle EXTENSION_READY_FOR_INSTALL for last active normal browser. + if (BrowserList::FindBrowserWithType(profile(), + Browser::TYPE_NORMAL, + true) != this) + break; + + // We only want to show the loading dialog for themes, but we don't want + // to wait until unpack to find out an extension is a theme, so we test + // the download_url GURL instead. This means that themes in the extensions + // gallery won't get the loading dialog. + GURL download_url = *(Details(details).ptr()); + if (ExtensionsService::IsDownloadFromMiniGallery(download_url)) + window()->ShowThemeInstallBubble(); + break; + } + + case NotificationType::PROFILE_ERROR: { + if (BrowserList::GetLastActive() != this) + break; + int* message_id = Details(details).ptr(); + window()->ShowProfileErrorDialog(*message_id); + break; + } + + case NotificationType::PREF_CHANGED: { + const std::string& pref_name = *Details(details).ptr(); + if (pref_name == prefs::kUseVerticalTabs) { + UseVerticalTabsChanged(); + } else if (pref_name == prefs::kPrintingEnabled) { + UpdatePrintingState(0); + } else if (pref_name == prefs::kInstantEnabled) { + if (!InstantController::IsEnabled(profile())) { + if (instant()) { + instant()->DestroyPreviewContents(); + instant_.reset(NULL); + } + } else { + CreateInstantIfNecessary(); + } + } else if (pref_name == prefs::kDevToolsDisabled) { + UpdateCommandsForDevTools(); + if (dev_tools_disabled_.GetValue()) + g_browser_process->devtools_manager()->CloseAllClientHosts(); + } else { + NOTREACHED(); + } + break; + } + + default: + NOTREACHED() << "Got a notification we didn't register for."; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, ProfileSyncServiceObserver implementation: + +void Browser::OnStateChanged() { + DCHECK(profile_->GetProfileSyncService()); + +#if !defined(OS_MACOSX) + const bool show_main_ui = (type() == TYPE_NORMAL) && !window_->IsFullscreen(); +#else + const bool show_main_ui = (type() == TYPE_NORMAL); +#endif + + command_updater_.UpdateCommandEnabled(IDC_SYNC_BOOKMARKS, + show_main_ui && profile_->IsSyncAccessible()); +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, InstantDelegate implementation: + +void Browser::ShowInstant(TabContents* preview_contents) { + DCHECK(instant_->tab_contents() == GetSelectedTabContents()); + window_->ShowInstant(preview_contents); +} + +void Browser::HideInstant() { + window_->HideInstant(); +} + +void Browser::CommitInstant(TabContents* preview_contents) { + TabContents* tab_contents = instant_->tab_contents(); + int index = tab_handler_->GetTabStripModel()->GetIndexOfTabContents( + tab_contents); + DCHECK_NE(-1, index); + preview_contents->controller().CopyStateFromAndPrune( + &tab_contents->controller()); + // TabStripModel takes ownership of preview_contents. + tab_handler_->GetTabStripModel()->ReplaceTabContentsAt( + index, preview_contents); +} + +void Browser::SetSuggestedText(const string16& text) { + window()->GetLocationBar()->SetSuggestedText(text); +} + +gfx::Rect Browser::GetInstantBounds() { + return window()->GetInstantBounds(); +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, Command and state updating (private): + +void Browser::InitCommandState() { + // All browser commands whose state isn't set automagically some other way + // (like Back & Forward with initial page load) must have their state + // initialized here, otherwise they will be forever disabled. + + // Navigation commands + command_updater_.UpdateCommandEnabled(IDC_RELOAD, true); + command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE, true); + + // Window management commands + command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW, true); + command_updater_.UpdateCommandEnabled(IDC_NEW_INCOGNITO_WINDOW, true); + command_updater_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true); + command_updater_.UpdateCommandEnabled(IDC_NEW_TAB, true); + command_updater_.UpdateCommandEnabled(IDC_CLOSE_TAB, true); + command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true); + command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB, false); + command_updater_.UpdateCommandEnabled(IDC_EXIT, true); + command_updater_.UpdateCommandEnabled(IDC_TOGGLE_VERTICAL_TABS, true); + + // Page-related commands + command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_AUTO_DETECT, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF8, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF16LE, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88591, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1252, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_GBK, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_GB18030, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5HKSCS, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_THAI, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOREAN, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_SHIFTJIS, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO2022JP, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_EUCJP, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885915, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_MACINTOSH, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88592, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1250, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88595, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1251, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8R, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8U, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88597, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1253, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88594, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885913, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1257, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88593, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885910, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885914, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885916, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1254, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88596, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1256, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598I, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1255, true); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1258, true); + + // Zoom + command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, true); + command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true); + command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, true); + command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true); + + // Show various bits of UI + command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, true); + command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false); + UpdateCommandsForDevTools(); + command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, true); + command_updater_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true); + command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER, + browser_defaults::bookmarks_enabled); + command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true); + command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE, true); + command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, true); + +#if defined(OS_CHROMEOS) + command_updater_.UpdateCommandEnabled(IDC_SEARCH, true); + command_updater_.UpdateCommandEnabled(IDC_SYSTEM_OPTIONS, true); + command_updater_.UpdateCommandEnabled(IDC_INTERNET_OPTIONS, true); +#endif + + ExtensionsService* extensions_service = profile()->GetExtensionsService(); + bool enable_extensions = + extensions_service && extensions_service->extensions_enabled(); + command_updater_.UpdateCommandEnabled(IDC_MANAGE_EXTENSIONS, + enable_extensions); + + // Initialize other commands based on the window type. + bool normal_window = type() == TYPE_NORMAL; + bool non_devtools_window = type() != TYPE_DEVTOOLS; + + // Navigation commands + command_updater_.UpdateCommandEnabled(IDC_HOME, normal_window); + + // Window management commands + command_updater_.UpdateCommandEnabled(IDC_FULLSCREEN, + type() != TYPE_APP_PANEL); + command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window); + command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB, + normal_window); + command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_NEXT, normal_window); + command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_PREVIOUS, normal_window); + command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_0, normal_window); + command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_1, normal_window); + command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_2, normal_window); + command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_3, normal_window); + command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_4, normal_window); + command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_5, normal_window); + command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window); + command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window); + command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window); +#if defined(OS_MACOSX) + command_updater_.UpdateCommandEnabled(IDC_TABPOSE, normal_window); +#endif + + // Page-related commands + command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_PAGE, + browser_defaults::bookmarks_enabled && normal_window); + + // Clipboard commands + command_updater_.UpdateCommandEnabled(IDC_COPY_URL, non_devtools_window); + + // Find-in-page + command_updater_.UpdateCommandEnabled(IDC_FIND, non_devtools_window); + command_updater_.UpdateCommandEnabled(IDC_FIND_NEXT, non_devtools_window); + command_updater_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, non_devtools_window); + + // AutoFill + command_updater_.UpdateCommandEnabled(IDC_AUTOFILL_DEFAULT, + non_devtools_window); + + // Show various bits of UI + command_updater_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA, normal_window); + + // The upgrade entry and the view incompatibility entry should always be + // enabled. Whether they are visible is a separate matter determined on menu + // show. + command_updater_.UpdateCommandEnabled(IDC_UPGRADE_DIALOG, true); + command_updater_.UpdateCommandEnabled(IDC_VIEW_INCOMPATIBILITIES, true); + + // Initialize other commands whose state changes based on fullscreen mode. + UpdateCommandsForFullscreenMode(false); + + UpdateCommandsForContentRestrictionState(); +} + +void Browser::UpdateCommandsForTabState() { + TabContents* current_tab = GetSelectedTabContents(); + if (!current_tab) // May be NULL during tab restore. + return; + + // Navigation commands + NavigationController& nc = current_tab->controller(); + command_updater_.UpdateCommandEnabled(IDC_BACK, nc.CanGoBack()); + command_updater_.UpdateCommandEnabled(IDC_FORWARD, nc.CanGoForward()); + command_updater_.UpdateCommandEnabled(IDC_RELOAD, + CanReloadContents(current_tab)); + command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE, + CanReloadContents(current_tab)); + + // Window management commands + bool non_app_window = !(type() & TYPE_APP); + command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, + non_app_window && CanDuplicateContentsAt(selected_index())); + command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, + non_app_window && tab_count() > 1); + command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB, + non_app_window && tab_count() > 1); + + // Page-related commands + window_->SetStarredState(current_tab->is_starred()); + command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_ALL_TABS, + browser_defaults::bookmarks_enabled && CanBookmarkAllTabs()); + command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE, + current_tab->controller().CanViewSource()); + command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION, + current_tab->ShouldDisplayURL() && current_tab->GetURL().is_valid()); + + // Changing the encoding is not possible on Chrome-internal webpages. + // Instead of using GetURL here, we use url() (which is the "real" url of the + // page) from the NavigationEntry because its reflects their origin rather + // than the display one (returned by GetURL) which may be different (like + // having "view-source:" on the front). + NavigationEntry* active_entry = nc.GetActiveEntry(); + bool is_chrome_internal = (active_entry ? + active_entry->url().SchemeIs(chrome::kChromeUIScheme) : false); + command_updater_.UpdateCommandEnabled(IDC_ENCODING_MENU, + !is_chrome_internal && SavePackage::IsSavableContents( + current_tab->contents_mime_type())); + + // Show various bits of UI + // TODO(pinkerton): Disable app-mode in the model until we implement it + // on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148 +#if !defined(OS_MACOSX) + command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, + web_app::IsValidUrl(current_tab->GetURL())); +#endif + + UpdateCommandsForContentRestrictionState(); +} + +void Browser::UpdateCommandsForContentRestrictionState() { + int restrictions = 0; + TabContents* current_tab = GetSelectedTabContents(); + if (current_tab) { + restrictions = current_tab->content_restrictions(); + NavigationEntry* active_entry = current_tab->controller().GetActiveEntry(); + // See comment in UpdateCommandsForTabState about why we call url(). + if (!SavePackage::IsSavableURL(active_entry ? active_entry->url() : GURL())) + restrictions |= CONTENT_RESTRICTION_SAVE; + } + + command_updater_.UpdateCommandEnabled( + IDC_COPY, !(restrictions & CONTENT_RESTRICTION_COPY)); + command_updater_.UpdateCommandEnabled( + IDC_CUT, !(restrictions & CONTENT_RESTRICTION_CUT)); + command_updater_.UpdateCommandEnabled( + IDC_PASTE, !(restrictions & CONTENT_RESTRICTION_PASTE)); + command_updater_.UpdateCommandEnabled( + IDC_SAVE_PAGE, !(restrictions & CONTENT_RESTRICTION_SAVE)); + UpdatePrintingState(restrictions); +} + +void Browser::UpdatePrintingState(int content_restrictions) { + bool enabled = true; + if (content_restrictions & CONTENT_RESTRICTION_PRINT) { + enabled = false; + } else if (g_browser_process->local_state()) { + enabled = printing_enabled_.GetValue(); + } + command_updater_.UpdateCommandEnabled(IDC_PRINT, enabled); +} + +void Browser::UpdateReloadStopState(bool is_loading, bool force) { + window_->UpdateReloadStopState(is_loading, force); + command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading); +} + +void Browser::UpdateCommandsForDevTools() { + bool dev_tools_enabled = !dev_tools_disabled_.GetValue(); + command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS, + dev_tools_enabled); + command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_CONSOLE, + dev_tools_enabled); + command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_INSPECT, + dev_tools_enabled); +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, UI update coalescing and handling (private): + +void Browser::UpdateToolbar(bool should_restore_state) { + window_->UpdateToolbar(GetSelectedTabContents(), should_restore_state); +} + +void Browser::ScheduleUIUpdate(const TabContents* source, + unsigned changed_flags) { + if (!source) + return; + + // Do some synchronous updates. + if (changed_flags & TabContents::INVALIDATE_URL && + source == GetSelectedTabContents()) { + // Only update the URL for the current tab. Note that we do not update + // the navigation commands since those would have already been updated + // synchronously by NavigationStateChanged. + UpdateToolbar(false); + changed_flags &= ~TabContents::INVALIDATE_URL; + } + if (changed_flags & TabContents::INVALIDATE_LOAD) { + // Update the loading state synchronously. This is so the throbber will + // immediately start/stop, which gives a more snappy feel. We want to do + // this for any tab so they start & stop quickly. + tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt( + tab_handler_->GetTabStripModel()->GetIndexOfController( + &source->controller()), + TabStripModelObserver::LOADING_ONLY); + // The status bubble needs to be updated during INVALIDATE_LOAD too, but + // we do that asynchronously by not stripping INVALIDATE_LOAD from + // changed_flags. + } + + if (changed_flags & TabContents::INVALIDATE_TITLE && !source->is_loading()) { + // To correctly calculate whether the title changed while not loading + // we need to process the update synchronously. This state only matters for + // the TabStripModel, so we notify the TabStripModel now and notify others + // asynchronously. + tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt( + tab_handler_->GetTabStripModel()->GetIndexOfController( + &source->controller()), + TabStripModelObserver::TITLE_NOT_LOADING); + } + + if (changed_flags & TabContents::INVALIDATE_BOOKMARK_BAR) { + window()->ShelfVisibilityChanged(); + changed_flags &= ~TabContents::INVALIDATE_BOOKMARK_BAR; + } + + // If the only updates were synchronously handled above, we're done. + if (changed_flags == 0) + return; + + // Save the dirty bits. + scheduled_updates_[source] |= changed_flags; + + if (chrome_updater_factory_.empty()) { + // No task currently scheduled, start another. + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + chrome_updater_factory_.NewRunnableMethod( + &Browser::ProcessPendingUIUpdates), + kUIUpdateCoalescingTimeMS); + } +} + +void Browser::ProcessPendingUIUpdates() { +#ifndef NDEBUG + // Validate that all tabs we have pending updates for exist. This is scary + // because the pending list must be kept in sync with any detached or + // deleted tabs. + for (UpdateMap::const_iterator i = scheduled_updates_.begin(); + i != scheduled_updates_.end(); ++i) { + bool found = false; + for (int tab = 0; tab < tab_count(); tab++) { + if (GetTabContentsAt(tab) == i->first) { + found = true; + break; + } + } + DCHECK(found); + } +#endif + + chrome_updater_factory_.RevokeAll(); + + for (UpdateMap::const_iterator i = scheduled_updates_.begin(); + i != scheduled_updates_.end(); ++i) { + // Do not dereference |contents|, it may be out-of-date! + const TabContents* contents = i->first; + unsigned flags = i->second; + + if (contents == GetSelectedTabContents()) { + // Updates that only matter when the tab is selected go here. + + if (flags & TabContents::INVALIDATE_PAGE_ACTIONS) + window()->GetLocationBar()->UpdatePageActions(); + + // Updating the URL happens synchronously in ScheduleUIUpdate. + if (flags & TabContents::INVALIDATE_LOAD && GetStatusBubble()) + GetStatusBubble()->SetStatus(WideToUTF16(contents->GetStatusText())); + + if (flags & (TabContents::INVALIDATE_TAB | + TabContents::INVALIDATE_TITLE)) { +// TODO(pinkerton): Disable app-mode in the model until we implement it +// on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148 +#if !defined(OS_MACOSX) + command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, + web_app::IsValidUrl(contents->GetURL())); +#endif + window_->UpdateTitleBar(); + } + } + + // Updates that don't depend upon the selected state go here. + if (flags & (TabContents::INVALIDATE_TAB | TabContents::INVALIDATE_TITLE)) { + tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt( + tab_handler_->GetTabStripModel()->GetIndexOfTabContents(contents), + TabStripModelObserver::ALL); + } + + // We don't need to process INVALIDATE_STATE, since that's not visible. + } + + scheduled_updates_.clear(); +} + +void Browser::RemoveScheduledUpdatesFor(TabContents* contents) { + if (!contents) + return; + + UpdateMap::iterator i = scheduled_updates_.find(contents); + if (i != scheduled_updates_.end()) + scheduled_updates_.erase(i); +} + + +/////////////////////////////////////////////////////////////////////////////// +// Browser, Getters for UI (private): + +StatusBubble* Browser::GetStatusBubble() { +#if !defined(OS_MACOSX) + // In kiosk mode, we want to always hide the status bubble. + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode)) + return NULL; +#endif + return window_ ? window_->GetStatusBubble() : NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, Session restore functions (private): + +void Browser::SyncHistoryWithTabs(int index) { + if (!profile()->HasSessionService()) + return; + SessionService* session_service = profile()->GetSessionService(); + if (session_service) { + for (int i = index; i < tab_count(); ++i) { + TabContents* contents = GetTabContentsAt(i); + if (contents) { + session_service->SetTabIndexInWindow( + session_id(), contents->controller().session_id(), i); + session_service->SetPinnedState( + session_id(), + contents->controller().session_id(), + tab_handler_->GetTabStripModel()->IsTabPinned(i)); + } + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, OnBeforeUnload handling (private): + +void Browser::ProcessPendingTabs() { + DCHECK(is_attempting_to_close_browser_); + + if (HasCompletedUnloadProcessing()) { + // We've finished all the unload events and can proceed to close the + // browser. + OnWindowClosing(); + return; + } + + // Process beforeunload tabs first. When that queue is empty, process + // unload tabs. + if (!tabs_needing_before_unload_fired_.empty()) { + TabContents* tab = *(tabs_needing_before_unload_fired_.begin()); + // Null check render_view_host here as this gets called on a PostTask and + // the tab's render_view_host may have been nulled out. + if (tab->render_view_host()) { + tab->render_view_host()->FirePageBeforeUnload(false); + } else { + ClearUnloadState(tab); + } + } else if (!tabs_needing_unload_fired_.empty()) { + // We've finished firing all beforeunload events and can proceed with unload + // events. + // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting + // somewhere around here so that we have accurate measurements of shutdown + // time. + // TODO(ojan): We can probably fire all the unload events in parallel and + // get a perf benefit from that in the cases where the tab hangs in it's + // unload handler or takes a long time to page in. + TabContents* tab = *(tabs_needing_unload_fired_.begin()); + // Null check render_view_host here as this gets called on a PostTask and + // the tab's render_view_host may have been nulled out. + if (tab->render_view_host()) { + tab->render_view_host()->ClosePage(false, -1, -1); + } else { + ClearUnloadState(tab); + } + } else { + NOTREACHED(); + } +} + +bool Browser::HasCompletedUnloadProcessing() const { + return is_attempting_to_close_browser_ && + tabs_needing_before_unload_fired_.empty() && + tabs_needing_unload_fired_.empty(); +} + +void Browser::CancelWindowClose() { + // Closing of window can be canceled from: + // - canceling beforeunload + // - disallowing closing from IsClosingPermitted. + DCHECK(is_attempting_to_close_browser_); + tabs_needing_before_unload_fired_.clear(); + tabs_needing_unload_fired_.clear(); + is_attempting_to_close_browser_ = false; + + // Inform TabCloseableStateWatcher that closing of window has been canceled. + TabCloseableStateWatcher* watcher = + g_browser_process->tab_closeable_state_watcher(); + if (watcher) + watcher->OnWindowCloseCanceled(this); +} + +bool Browser::RemoveFromSet(UnloadListenerSet* set, TabContents* tab) { + DCHECK(is_attempting_to_close_browser_); + + UnloadListenerSet::iterator iter = std::find(set->begin(), set->end(), tab); + if (iter != set->end()) { + set->erase(iter); + return true; + } + return false; +} + +void Browser::ClearUnloadState(TabContents* tab) { + // Closing of browser could be canceled (via IsClosingPermitted) between the + // time when request was initiated and when this method is called, so check + // for is_attempting_to_close_browser_ flag before proceeding. + if (is_attempting_to_close_browser_) { + RemoveFromSet(&tabs_needing_before_unload_fired_, tab); + RemoveFromSet(&tabs_needing_unload_fired_, tab); + ProcessPendingTabs(); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// Browser, In-progress download termination handling (private): + +bool Browser::CanCloseWithInProgressDownloads() { + if (cancel_download_confirmation_state_ != NOT_PROMPTED) { + if (cancel_download_confirmation_state_ == WAITING_FOR_RESPONSE) { + // We need to hear from the user before we can close. + return false; + } + // RESPONSE_RECEIVED case, the user decided to go along with the closing. + return true; + } + // Indicated that normal (non-incognito) downloads are pending. + bool normal_downloads_are_present = false; + bool incognito_downloads_are_present = false; + // If there are no download in-progress, our job is done. + DownloadManager* download_manager = NULL; + // But first we need to check for the existance of the download manager, as + // GetDownloadManager() will unnecessarily try to create one if it does not + // exist. + if (profile_->HasCreatedDownloadManager()) + download_manager = profile_->GetDownloadManager(); + if (profile_->IsOffTheRecord()) { + // Browser is incognito and so download_manager if present is for incognito + // downloads. + incognito_downloads_are_present = + (download_manager && download_manager->in_progress_count() != 0); + // Check original profile. + if (profile_->GetOriginalProfile()->HasCreatedDownloadManager()) + download_manager = profile_->GetOriginalProfile()->GetDownloadManager(); + } + + normal_downloads_are_present = + (download_manager && download_manager->in_progress_count() != 0); + if (!normal_downloads_are_present && !incognito_downloads_are_present) + return true; + + if (is_attempting_to_close_browser_) + return true; + + if ((!normal_downloads_are_present && !profile()->IsOffTheRecord()) || + (!incognito_downloads_are_present && profile()->IsOffTheRecord())) + return true; + + // Let's figure out if we are the last window for our profile. + // Note that we cannot just use BrowserList::GetBrowserCount as browser + // windows closing is delayed and the returned count might include windows + // that are being closed. + // The browser allowed to be closed only if: + // 1. It is a regular browser and there are no regular downloads present or + // this is not the last regular browser window. + // 2. It is an incognito browser and there are no incognito downloads present + // or this is not the last incognito browser window. + int count = 0; + for (BrowserList::const_iterator iter = BrowserList::begin(); + iter != BrowserList::end(); ++iter) { + // Don't count this browser window or any other in the process of closing. + if (*iter == this || (*iter)->is_attempting_to_close_browser_) + continue; + + // Verify that this is not the last non-incognito or incognito browser, + // depending on the pending downloads. + if (normal_downloads_are_present && !profile()->IsOffTheRecord() && + (*iter)->profile()->IsOffTheRecord()) + continue; + if (incognito_downloads_are_present && profile()->IsOffTheRecord() && + !(*iter)->profile()->IsOffTheRecord()) + continue; + + // We test the original profile, because an incognito browser window keeps + // the original profile alive (and its DownloadManager). + // We also need to test explicitly the profile directly so that 2 incognito + // profiles count as a match. + if ((*iter)->profile() == profile() || + (*iter)->profile()->GetOriginalProfile() == profile()) + count++; + } + if (count > 0) + return true; + + cancel_download_confirmation_state_ = WAITING_FOR_RESPONSE; + window_->ConfirmBrowserCloseWithPendingDownloads(); + + // Return false so the browser does not close. We'll close if the user + // confirms in the dialog. + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// Browser, Assorted utility functions (private): + +// static +Browser* Browser::GetTabbedBrowser(Profile* profile, bool match_incognito) { + return BrowserList::FindBrowserWithType(profile, TYPE_NORMAL, + match_incognito); +} + +// static +Browser* Browser::GetOrCreateTabbedBrowser(Profile* profile) { + Browser* browser = GetTabbedBrowser(profile, false); + if (!browser) + browser = Browser::Create(profile); + return browser; +} + +void Browser::FindInPage(bool find_next, bool forward_direction) { + ShowFindBar(); + if (find_next) { + string16 find_text; +#if defined(OS_MACOSX) + // We always want to search for the contents of the find pasteboard on OS X. + find_text = GetFindPboardText(); +#endif + GetSelectedTabContents()->StartFinding(find_text, + forward_direction, + false); // Not case sensitive. + } +} + +void Browser::CloseFrame() { + window_->Close(); +} + +void Browser::TabDetachedAtImpl(TabContents* contents, int index, + DetachType type) { + if (type == DETACH_TYPE_DETACH) { + // Save what the user's currently typed. + window_->GetLocationBar()->SaveStateToContents(contents); + + if (!tab_handler_->GetTabStripModel()->closing_all()) + SyncHistoryWithTabs(0); + } + + contents->set_delegate(NULL); + RemoveScheduledUpdatesFor(contents); + + if (find_bar_controller_.get() && + index == tab_handler_->GetTabStripModel()->selected_index()) { + find_bar_controller_->ChangeTabContents(NULL); + } + + registrar_.Remove(this, NotificationType::TAB_CONTENTS_DISCONNECTED, + Source(contents)); +} + +// static +void Browser::RegisterAppPrefs(const std::string& app_name) { + // A set of apps that we've already started. + static std::set* g_app_names = NULL; + + if (!g_app_names) + g_app_names = new std::set; + + // Only register once for each app name. + if (g_app_names->find(app_name) != g_app_names->end()) + return; + g_app_names->insert(app_name); + + // We need to register the window position pref. + std::string window_pref(prefs::kBrowserWindowPlacement); + window_pref.append("_"); + window_pref.append(app_name); + PrefService* prefs = g_browser_process->local_state(); + DCHECK(prefs); + + prefs->RegisterDictionaryPref(window_pref.c_str()); +} + +void Browser::TabRestoreServiceChanged(TabRestoreService* service) { + command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB, + !service->entries().empty()); +} + +void Browser::TabRestoreServiceDestroyed(TabRestoreService* service) { + if (!tab_restore_service_) + return; + + DCHECK_EQ(tab_restore_service_, service); + tab_restore_service_->RemoveObserver(this); + tab_restore_service_ = NULL; +} + +bool Browser::OpenInstant(WindowOpenDisposition disposition) { + if (!instant() || !instant()->is_active() || !instant()->IsCurrent()) + return false; + + if (disposition == CURRENT_TAB) { + instant()->CommitCurrentPreview(INSTANT_COMMIT_PRESSED_ENTER); + return true; + } + if (disposition == NEW_FOREGROUND_TAB || disposition == NEW_BACKGROUND_TAB) { + HideInstant(); + TabContents* preview_contents = instant()->ReleasePreviewContents( + INSTANT_COMMIT_PRESSED_ENTER); + preview_contents->controller().PruneAllButActive(); + tab_handler_->GetTabStripModel()->AddTabContents( + preview_contents, + -1, + instant()->last_transition_type(), + disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_SELECTED : + TabStripModel::ADD_NONE); + instant()->CompleteRelease(preview_contents); + return true; + } + // The omnibox currently doesn't use other dispositions, so we don't attempt + // to handle them. If you hit this NOTREACHED file a bug and I'll (sky) add + // support for the new disposition. + NOTREACHED(); + return false; +} + +void Browser::CreateInstantIfNecessary() { + if (type() == TYPE_NORMAL && InstantController::IsEnabled(profile()) && + !profile()->IsOffTheRecord()) { + instant_.reset(new InstantController(profile_, this)); + } +} diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h new file mode 100644 index 0000000..abd2be9 --- /dev/null +++ b/chrome/browser/ui/browser.h @@ -0,0 +1,1094 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_BROWSER_H_ +#define CHROME_BROWSER_UI_BROWSER_H_ +#pragma once + +#include +#include +#include +#include + +#include "base/basictypes.h" +#include "base/gtest_prod_util.h" +#include "base/scoped_ptr.h" +#include "base/string16.h" +#include "base/task.h" +#include "chrome/browser/command_updater.h" +#include "chrome/browser/debugger/devtools_toggle_action.h" +#include "chrome/browser/instant/instant_delegate.h" +#include "chrome/browser/prefs/pref_member.h" +#include "chrome/browser/sessions/session_id.h" +#include "chrome/browser/sessions/tab_restore_service_observer.h" +#include "chrome/browser/shell_dialogs.h" +#include "chrome/browser/sync/profile_sync_service_observer.h" +#include "chrome/browser/tabs/tab_handler.h" +#include "chrome/browser/tabs/tab_strip_model_delegate.h" // TODO(beng): remove +#include "chrome/browser/tabs/tab_strip_model_observer.h" // TODO(beng): remove +#include "chrome/browser/tab_contents/page_navigator.h" +#include "chrome/browser/tab_contents/tab_contents_delegate.h" +#include "chrome/browser/toolbar_model.h" +#include "chrome/common/extensions/extension_constants.h" +#include "chrome/common/notification_registrar.h" +#include "chrome/common/page_transition_types.h" +#include "chrome/common/page_zoom.h" +#include "gfx/rect.h" + +class BrowserWindow; +class Extension; +class FindBarController; +class InstantController; +class PrefService; +class Profile; +class SessionStorageNamespace; +class SkBitmap; +class StatusBubble; +class TabNavigation; +class TabStripModel; +namespace gfx { +class Point; +} + +class Browser : public TabHandlerDelegate, + public TabContentsDelegate, + public PageNavigator, + public CommandUpdater::CommandUpdaterDelegate, + public NotificationObserver, + public SelectFileDialog::Listener, + public TabRestoreServiceObserver, + public ProfileSyncServiceObserver, + public InstantDelegate { + public: + // If you change the values in this enum you'll need to update browser_proxy. + // TODO(sky): move into a common place that is referenced by both ui_tests + // and chrome. + enum Type { + TYPE_NORMAL = 1, + TYPE_POPUP = 2, + // The old-style app created via "Create application shortcuts". + TYPE_APP = 4, + // The new-style app created by installing a crx. This kinda needs to be + // separate because we require larger icons and an application name that + // are found in the crx. If we ever decide to create this kind of app + // using some other system (eg some web standard), maybe we should + // generalize this name to TYPE_MULTITAB or something. + TYPE_EXTENSION_APP = 8, + TYPE_APP_POPUP = TYPE_APP | TYPE_POPUP, + TYPE_DEVTOOLS = TYPE_APP | 16, + + // TODO(skerner): crbug/56776: Until the panel UI is complete on all + // platforms, apps that set app.launch.container = "panel" have type + // APP_POPUP. (see Browser::CreateForApp) + // NOTE: TYPE_APP_PANEL is a superset of TYPE_APP_POPUP. + TYPE_APP_PANEL = TYPE_APP | TYPE_POPUP | 32, + TYPE_ANY = TYPE_NORMAL | + TYPE_POPUP | + TYPE_APP | + TYPE_EXTENSION_APP | + TYPE_DEVTOOLS | + TYPE_APP_PANEL + }; + + // Possible elements of the Browser window. + enum WindowFeature { + FEATURE_NONE = 0, + FEATURE_TITLEBAR = 1, + FEATURE_TABSTRIP = 2, + FEATURE_TOOLBAR = 4, + FEATURE_LOCATIONBAR = 8, + FEATURE_BOOKMARKBAR = 16, + FEATURE_INFOBAR = 32, + FEATURE_SIDEBAR = 64, + FEATURE_DOWNLOADSHELF = 128 + }; + + // Maximized state on creation. + enum MaximizedState { + // The maximized state is set to the default, which varies depending upon + // what the user has done. + MAXIMIZED_STATE_DEFAULT, + + // Maximized state is explicitly maximized. + MAXIMIZED_STATE_MAXIMIZED, + + // Maximized state is explicitly not maximized (normal). + MAXIMIZED_STATE_UNMAXIMIZED + }; + + // Constructors, Creation, Showing ////////////////////////////////////////// + + // Creates a new browser of the given |type| and for the given |profile|. The + // Browser has a NULL window after its construction, CreateBrowserWindow must + // be called after configuration for window() to be valid. + // Avoid using this constructor directly if you can use one of the Create*() + // methods below. This applies to almost all non-testing code. + Browser(Type type, Profile* profile); + virtual ~Browser(); + + // Creates a normal tabbed browser with the specified profile. The Browser's + // window is created by this function call. + static Browser* Create(Profile* profile); + + // Like Create, but creates a browser of the specified (popup) type, with the + // specified contents, in a popup window of the specified size/position. + static Browser* CreateForPopup(Type type, Profile* profile, + TabContents* new_contents, + const gfx::Rect& initial_bounds); + + // Like Create, but creates a browser of the specified type. + static Browser* CreateForType(Type type, Profile* profile); + + // Like Create, but creates a toolbar-less "app" window for the specified + // app. |app_name| is required and is used to identify the window to the + // shell. |extension| is optional. If supplied, we create a window with + // a bigger icon and title text, that supports tabs. + static Browser* CreateForApp(const std::string& app_name, + const Extension* extension, + Profile* profile, + bool is_panel); + + // Like Create, but creates a tabstrip-less and toolbar-less + // DevTools "app" window. + static Browser* CreateForDevTools(Profile* profile); + + // Returns the extension app associated with this window, if any. + const Extension* extension_app() { return extension_app_; } + + // Set overrides for the initial window bounds and maximized state. + void set_override_bounds(const gfx::Rect& bounds) { + override_bounds_ = bounds; + } + void set_maximized_state(MaximizedState state) { + maximized_state_ = state; + } + // Return true if the initial window bounds have been overridden. + bool bounds_overridden() const { + return !override_bounds_.IsEmpty(); + } + + // Creates the Browser Window. Prefer to use the static helpers above where + // possible. This does not show the window. You need to call window()->Show() + // to show it. + void CreateBrowserWindow(); + + // Accessors //////////////////////////////////////////////////////////////// + + Type type() const { return type_; } + Profile* profile() const { return profile_; } + const std::vector& user_data_dir_profiles() const; + + // Returns the InstantController or NULL if there is no InstantController for + // this Browser. + InstantController* instant() const { return instant_.get(); } + +#if defined(UNIT_TEST) + // Sets the BrowserWindow. This is intended for testing and generally not + // useful outside of testing. Use CreateBrowserWindow outside of testing, or + // the static convenience methods that create a BrowserWindow for you. + void set_window(BrowserWindow* window) { + DCHECK(!window_); + window_ = window; + } +#endif + + BrowserWindow* window() const { return window_; } + ToolbarModel* toolbar_model() { return &toolbar_model_; } + const SessionID& session_id() const { return session_id_; } + CommandUpdater* command_updater() { return &command_updater_; } + + // Get the FindBarController for this browser, creating it if it does not + // yet exist. + FindBarController* GetFindBarController(); + + // Returns true if a FindBarController exists for this browser. + bool HasFindBarController() const; + + // Setters ///////////////////////////////////////////////////////////////// + + void set_user_data_dir_profiles(const std::vector& profiles); + + // Browser Creation Helpers ///////////////////////////////////////////////// + + // Opens a new window with the default blank tab. + static void OpenEmptyWindow(Profile* profile); + + // Opens a new window with the tabs from |profile|'s TabRestoreService. + static void OpenWindowWithRestoredTabs(Profile* profile); + + // Opens the specified URL in a new browser window in an incognito session. + // If there is already an existing active incognito session for the specified + // |profile|, that session is re-used. + static void OpenURLOffTheRecord(Profile* profile, const GURL& url); + + // Open an application specified by |app_id| in the appropriate launch + // container. |existing_tab| is reused if it is not NULL and the launch + // container is a tab. Returns NULL if the app_id is invalid or if + // ExtensionsService isn't ready/available. + static TabContents* OpenApplication(Profile* profile, + const std::string& app_id, + TabContents* existing_tab); + + // Open |extension| in |container|, using |existing_tab| if not NULL and if + // the correct container type. Returns the TabContents* that was created or + // NULL. + static TabContents* OpenApplication( + Profile* profile, + const Extension* extension, + extension_misc::LaunchContainer container, + TabContents* existing_tab); + + // Opens a new application window for the specified url. If |as_panel| + // is true, the application will be opened as a Browser::Type::APP_PANEL in + // app panel window, otherwise it will be opened as as either + // Browser::Type::APP a.k.a. "thin frame" (if |extension| is NULL) or + // Browser::Type::EXTENSION_APP (if |extension| is non-NULL). + static TabContents* OpenApplicationWindow( + Profile* profile, + const Extension* extension, + extension_misc::LaunchContainer container, + const GURL& url); + + // Open an application for |extension| in a new application window or panel. + static TabContents* OpenApplicationWindow(Profile* profile, GURL& url); + + // Open an application for |extension| in a new application tab, or + // |existing_tab| if not NULL. Returns NULL if there are no appropriate + // existing browser windows for |profile|. + static TabContents* OpenApplicationTab(Profile* profile, + const Extension* extension, + TabContents* existing_tab); + + // Opens a new window and opens the bookmark manager. + static void OpenBookmarkManagerWindow(Profile* profile); + +#if defined(OS_MACOSX) + // Open a new window with history/downloads/help/options (needed on Mac when + // there are no windows). + static void OpenHistoryWindow(Profile* profile); + static void OpenDownloadsWindow(Profile* profile); + static void OpenHelpWindow(Profile* profile); + static void OpenOptionsWindow(Profile* profile); +#endif + + // Opens a window with the extensions tab in it - needed by long-lived + // extensions which may run with no windows open. + static void OpenExtensionsWindow(Profile* profile); + + // State Storage and Retrieval for UI /////////////////////////////////////// + + // Save and restore the window position. + std::string GetWindowPlacementKey() const; + bool ShouldSaveWindowPlacement() const; + void SaveWindowPlacement(const gfx::Rect& bounds, bool maximized); + gfx::Rect GetSavedWindowBounds() const; + bool GetSavedMaximizedState() const; + + // Gets the FavIcon of the page in the selected tab. + SkBitmap GetCurrentPageIcon() const; + + // Gets the title of the window based on the selected tab's title. + string16 GetWindowTitleForCurrentTab() const; + + // Prepares a title string for display (removes embedded newlines, etc). + static void FormatTitleForDisplay(string16* title); + + // OnBeforeUnload handling ////////////////////////////////////////////////// + + // Gives beforeunload handlers the chance to cancel the close. + bool ShouldCloseWindow(); + + bool IsAttemptingToCloseBrowser() const { + return is_attempting_to_close_browser_; + } + + // Invoked when the window containing us is closing. Performs the necessary + // cleanup. + void OnWindowClosing(); + + // In-progress download termination handling ///////////////////////////////// + + // Called when the user has decided whether to proceed or not with the browser + // closure. |cancel_downloads| is true if the downloads should be canceled + // and the browser closed, false if the browser should stay open and the + // downloads running. + void InProgressDownloadResponse(bool cancel_downloads); + + // TabStripModel pass-thrus ///////////////////////////////////////////////// + + TabStripModel* tabstrip_model() const { + // TODO(beng): remove this accessor. It violates google style. + return tab_handler_->GetTabStripModel(); + } + + int tab_count() const; + int selected_index() const; + int GetIndexOfController(const NavigationController* controller) const; + TabContents* GetTabContentsAt(int index) const; + TabContents* GetSelectedTabContents() const; + void SelectTabContentsAt(int index, bool user_gesture); + void CloseAllTabs(); + + // Tab adding/showing functions ///////////////////////////////////////////// + + // Returns the index to insert a tab at during session restore and startup. + // |relative_index| gives the index of the url into the number of tabs that + // are going to be opened. For example, if three urls are passed in on the + // command line this is invoked three times with the values 0, 1 and 2. + int GetIndexForInsertionDuringRestore(int relative_index); + + // Adds a selected tab with the specified URL and transition, returns the + // created TabContents. + TabContents* AddSelectedTabWithURL(const GURL& url, + PageTransition::Type transition); + + // Add a new tab, given a TabContents. A TabContents appropriate to + // display the last committed entry is created and returned. + TabContents* AddTab(TabContents* tab_contents, PageTransition::Type type); + + // Add a tab with its session history restored from the SessionRestore + // system. If select is true, the tab is selected. |tab_index| gives the index + // to insert the tab at. |selected_navigation| is the index of the + // TabNavigation in |navigations| to select. If |extension_app_id| is + // non-empty the tab is an app tab and |extension_app_id| is the id of the + // extension. If |pin| is true and |tab_index|/ is the last pinned tab, then + // the newly created tab is pinned. If |from_last_session| is true, + // |navigations| are from the previous session. + TabContents* AddRestoredTab(const std::vector& navigations, + int tab_index, + int selected_navigation, + const std::string& extension_app_id, + bool select, + bool pin, + bool from_last_session, + SessionStorageNamespace* storage_namespace); + // Creates a new tab with the already-created TabContents 'new_contents'. + // The window for the added contents will be reparented correctly when this + // method returns. If |disposition| is NEW_POPUP, |pos| should hold the + // initial position. + void AddTabContents(TabContents* new_contents, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture); + void CloseTabContents(TabContents* contents); + + // Show a dialog with HTML content. |delegate| contains a pointer to the + // delegate who knows how to display the dialog (which file URL and JSON + // string input to use during initialization). |parent_window| is the window + // that should be parent of the dialog, or NULL for the default. + void BrowserShowHtmlDialog(HtmlDialogUIDelegate* delegate, + gfx::NativeWindow parent_window); + + // Called when a popup select is about to be displayed. + void BrowserRenderWidgetShowing(); + + // Notification that some of our content has changed size as + // part of an animation. + void ToolbarSizeChanged(bool is_animating); + + // Replaces the state of the currently selected tab with the session + // history restored from the SessionRestore system. + void ReplaceRestoredTab( + const std::vector& navigations, + int selected_navigation, + bool from_last_session, + const std::string& extension_app_id, + SessionStorageNamespace* session_storage_namespace); + + // Navigate to an index in the tab history, opening a new tab depending on the + // disposition. + bool NavigateToIndexWithDisposition(int index, WindowOpenDisposition disp); + + // Show a given a URL. If a tab with the same URL (ignoring the ref) is + // already visible in this browser, it becomes selected. Otherwise a new tab + // is created. + void ShowSingletonTab(const GURL& url); + + // Update commands whose state depends on whether the window is in fullscreen + // mode. This is a public function because on Linux, fullscreen mode is an + // async call to X. Once we get the fullscreen callback, the browser window + // will call this method. + void UpdateCommandsForFullscreenMode(bool is_fullscreen); + + // Assorted browser commands //////////////////////////////////////////////// + + // NOTE: Within each of the following sections, the IDs are ordered roughly by + // how they appear in the GUI/menus (left to right, top to bottom, etc.). + + // Navigation commands + void GoBack(WindowOpenDisposition disposition); + void GoForward(WindowOpenDisposition disposition); + void Reload(WindowOpenDisposition disposition); + void ReloadIgnoringCache(WindowOpenDisposition disposition); // Shift-reload. + void Home(WindowOpenDisposition disposition); + void OpenCurrentURL(); + void Stop(); + // Window management commands + void NewWindow(); + void NewIncognitoWindow(); + void CloseWindow(); + void NewTab(); + void CloseTab(); + void SelectNextTab(); + void SelectPreviousTab(); + void OpenTabpose(); + void MoveTabNext(); + void MoveTabPrevious(); + void SelectNumberedTab(int index); + void SelectLastTab(); + void DuplicateTab(); + void WriteCurrentURLToClipboard(); + void ConvertPopupToTabbedBrowser(); + // In kiosk mode, the first toggle is valid, the rest is discarded. + void ToggleFullscreenMode(); + void Exit(); +#if defined(OS_CHROMEOS) + void ToggleCompactNavigationBar(); + void Search(); +#endif + + // Page-related commands + void BookmarkCurrentPage(); + void SavePage(); + void ViewSource(); + void ShowFindBar(); + + // Returns true if the Browser supports the specified feature. The value of + // this varies during the lifetime of the browser. For example, if the window + // is fullscreen this may return a different value. If you only care about + // whether or not it's possible for the browser to support a particular + // feature use |CanSupportWindowFeature|. + bool SupportsWindowFeature(WindowFeature feature) const; + + // Returns true if the Browser can support the specified feature. See comment + // in |SupportsWindowFeature| for details on this. + bool CanSupportWindowFeature(WindowFeature feature) const; + +// TODO(port): port these, and re-merge the two function declaration lists. + // Page-related commands. + void Print(); + void EmailPageLocation(); + void ToggleEncodingAutoDetect(); + void OverrideEncoding(int encoding_id); + + // Clipboard commands + void Cut(); + void Copy(); + void Paste(); + + // Find-in-page + void Find(); + void FindNext(); + void FindPrevious(); + + // Zoom + void Zoom(PageZoom::Function zoom_function); + + // Focus various bits of UI + void FocusToolbar(); + void FocusLocationBar(); // Also selects any existing text. + void FocusSearch(); + void FocusAppMenu(); + void FocusBookmarksToolbar(); + void FocusChromeOSStatus(); + void FocusNextPane(); + void FocusPreviousPane(); + + // Show various bits of UI + void OpenFile(); + void OpenCreateShortcutsDialog(); + void ToggleDevToolsWindow(DevToolsToggleAction action); + void OpenTaskManager(); + void OpenBugReportDialog(); + + void ToggleBookmarkBar(); + + void OpenBookmarkManager(); + void ShowAppMenu(); + void ShowBookmarkManagerTab(); + void ShowHistoryTab(); + void ShowDownloadsTab(); + void ShowExtensionsTab(); + void ShowAboutConflictsTab(); + void ShowBrokenPageTab(TabContents* contents); + void ShowOptionsTab(const std::string& sub_page); + void OpenClearBrowsingDataDialog(); + void OpenOptionsDialog(); + void OpenKeywordEditor(); + void OpenPasswordManager(); + void OpenSyncMyBookmarksDialog(); +#if defined(ENABLE_REMOTING) + void OpenRemotingSetupDialog(); +#endif + void OpenImportSettingsDialog(); + void OpenAboutChromeDialog(); + void OpenUpdateChromeDialog(); + void OpenHelpTab(); + // Used by the "Get themes" link in the options dialog. + void OpenThemeGalleryTabAndActivate(); + void OpenAutoFillHelpTabAndActivate(); + void OpenPrivacyDashboardTabAndActivate(); + void OpenSearchEngineOptionsDialog(); +#if defined(OS_CHROMEOS) + void OpenSystemOptionsDialog(); + void OpenInternetOptionsDialog(); + void OpenLanguageOptionsDialog(); + void OpenSystemTabAndActivate(); + void OpenMobilePlanTabAndActivate(); +#endif + void OpenPluginsTabAndActivate(); + + virtual void UpdateDownloadShelfVisibility(bool visible); + + // Overridden from TabStripModelDelegate: + virtual bool UseVerticalTabs() const; + + ///////////////////////////////////////////////////////////////////////////// + + // Sets the value of homepage related prefs to new values. Since we do not + // want to change these values for existing users, we can not change the + // default values under RegisterUserPrefs. Also if user already has an + // existing profile we do not want to override those preferences so we only + // set new values if they have not been set already. This method gets called + // during First Run. + static void SetNewHomePagePrefs(PrefService* prefs); + + static void RegisterPrefs(PrefService* prefs); + static void RegisterUserPrefs(PrefService* prefs); + + // Helper function to run unload listeners on a TabContents. + static bool RunUnloadEventsHelper(TabContents* contents); + + // Returns the Browser which contains the tab with the given + // NavigationController, also filling in |index| (if valid) with the tab's + // index in the tab strip. + // Returns NULL if not found. + // This call is O(N) in the number of tabs. + static Browser* GetBrowserForController( + const NavigationController* controller, int* index); + + // Retrieve the last active tabbed browser with a profile matching |profile|. + static Browser* GetTabbedBrowser(Profile* profile, bool match_incognito); + + // Retrieve the last active tabbed browser with a profile matching |profile|. + // Creates a new Browser if none are available. + static Browser* GetOrCreateTabbedBrowser(Profile* profile); + + // Calls ExecuteCommandWithDisposition with the given disposition. + void ExecuteCommandWithDisposition(int id, WindowOpenDisposition); + + // Returns whether the |id| is a reserved command, whose keyboard shortcuts + // should not be sent to the renderer. + bool IsReservedCommand(int id); + + // Sets if command execution shall be blocked. If |block| is true then + // following calls to ExecuteCommand() or ExecuteCommandWithDisposition() + // method will not execute the command, and the last blocked command will be + // recorded for retrieval. + void SetBlockCommandExecution(bool block); + + // Gets the last blocked command after calling SetBlockCommandExecution(true). + // Returns the command id or -1 if there is no command blocked. The + // disposition type of the command will be stored in |*disposition| if it's + // not null. + int GetLastBlockedCommand(WindowOpenDisposition* disposition); + + // Called by browser::Navigate() when a navigation has occurred in a tab in + // this Browser. Updates the UI for the start of this navigation. + void UpdateUIForNavigationInTab(TabContents* contents, + PageTransition::Type transition, + bool user_initiated); + + // Called by browser::Navigate() to retrieve the home page if no URL is + // specified. + GURL GetHomePage() const; + + // Interface implementations //////////////////////////////////////////////// + + // Overridden from PageNavigator: + virtual void OpenURL(const GURL& url, const GURL& referrer, + WindowOpenDisposition disposition, + PageTransition::Type transition); + + // Overridden from CommandUpdater::CommandUpdaterDelegate: + virtual void ExecuteCommand(int id); + + // Overridden from TabRestoreServiceObserver: + virtual void TabRestoreServiceChanged(TabRestoreService* service); + virtual void TabRestoreServiceDestroyed(TabRestoreService* service); + + + // Overridden from TabHandlerDelegate: + virtual Profile* GetProfile() const; + virtual Browser* AsBrowser(); + + // Overridden from TabStripModelDelegate: + virtual TabContents* AddBlankTab(bool foreground); + virtual TabContents* AddBlankTabAt(int index, bool foreground); + virtual Browser* CreateNewStripWithContents(TabContents* detached_contents, + const gfx::Rect& window_bounds, + const DockInfo& dock_info, + bool maximize); + virtual void ContinueDraggingDetachedTab(TabContents* contents, + const gfx::Rect& window_bounds, + const gfx::Rect& tab_bounds); + virtual int GetDragActions() const; + // Construct a TabContents for a given URL, profile and transition type. + // If instance is not null, its process will be used to render the tab. + virtual TabContents* CreateTabContentsForURL(const GURL& url, + const GURL& referrer, + Profile* profile, + PageTransition::Type transition, + bool defer_load, + SiteInstance* instance) const; + virtual bool CanDuplicateContentsAt(int index); + virtual void DuplicateContentsAt(int index); + virtual void CloseFrameAfterDragSession(); + virtual void CreateHistoricalTab(TabContents* contents); + virtual bool RunUnloadListenerBeforeClosing(TabContents* contents); + virtual bool CanCloseContentsAt(int index); + virtual bool CanBookmarkAllTabs() const; + virtual void BookmarkAllTabs(); + virtual bool CanCloseTab() const; + virtual void ToggleUseVerticalTabs(); + virtual bool CanRestoreTab(); + virtual void RestoreTab(); + virtual bool LargeIconsPermitted() const; + + // Overridden from TabStripModelObserver: + virtual void TabInsertedAt(TabContents* contents, + int index, + bool foreground); + virtual void TabClosingAt(TabStripModel* tab_strip_model, + TabContents* contents, + int index); + virtual void TabDetachedAt(TabContents* contents, int index); + virtual void TabDeselectedAt(TabContents* contents, int index); + virtual void TabSelectedAt(TabContents* old_contents, + TabContents* new_contents, + int index, + bool user_gesture); + virtual void TabMoved(TabContents* contents, + int from_index, + int to_index); + virtual void TabReplacedAt(TabContents* old_contents, + TabContents* new_contents, + int index); + virtual void TabPinnedStateChanged(TabContents* contents, int index); + virtual void TabStripEmpty(); + + private: + FRIEND_TEST_ALL_PREFIXES(BrowserTest, NoTabsInPopups); + + // Used to describe why a tab is being detached. This is used by + // TabDetachedAtImpl. + enum DetachType { + // Result of TabDetachedAt. + DETACH_TYPE_DETACH, + + // Result of TabReplacedAt. + DETACH_TYPE_REPLACE, + + // Result of the tab strip not having any significant tabs. + DETACH_TYPE_EMPTY + }; + + // Overridden from TabContentsDelegate: + virtual void OpenURLFromTab(TabContents* source, + const GURL& url, + const GURL& referrer, + WindowOpenDisposition disposition, + PageTransition::Type transition); + virtual void NavigationStateChanged(const TabContents* source, + unsigned changed_flags); + virtual void AddNewContents(TabContents* source, + TabContents* new_contents, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture); + virtual void ActivateContents(TabContents* contents); + virtual void DeactivateContents(TabContents* contents); + virtual void LoadingStateChanged(TabContents* source); + virtual void CloseContents(TabContents* source); + virtual void MoveContents(TabContents* source, const gfx::Rect& pos); + virtual void DetachContents(TabContents* source); + virtual bool IsPopup(const TabContents* source) const; + virtual bool CanReloadContents(TabContents* source) const; + virtual void ToolbarSizeChanged(TabContents* source, bool is_animating); + virtual void URLStarredChanged(TabContents* source, bool starred); + virtual void UpdateTargetURL(TabContents* source, const GURL& url); + virtual void ContentsMouseEvent( + TabContents* source, const gfx::Point& location, bool motion); + virtual void ContentsZoomChange(bool zoom_in); + virtual void OnContentSettingsChange(TabContents* source); + virtual void SetTabContentBlocked(TabContents* contents, bool blocked); + virtual void TabContentsFocused(TabContents* tab_content); + virtual bool TakeFocus(bool reverse); + virtual bool IsApplication() const; + virtual void ConvertContentsToApplication(TabContents* source); + virtual bool ShouldDisplayURLField(); + virtual gfx::Rect GetRootWindowResizerRect() const; + virtual void ShowHtmlDialog(HtmlDialogUIDelegate* delegate, + gfx::NativeWindow parent_window); + virtual void BeforeUnloadFired(TabContents* source, + bool proceed, + bool* proceed_to_fire_unload); + virtual void SetFocusToLocationBar(bool select_all); + virtual void RenderWidgetShowing(); + virtual int GetExtraRenderViewHeight() const; + virtual void OnStartDownload(DownloadItem* download, TabContents* tab); + virtual void ConfirmSetDefaultSearchProvider( + TabContents* tab_contents, + TemplateURL* template_url, + TemplateURLModel* template_url_model); + virtual void ConfirmAddSearchProvider(const TemplateURL* template_url, + Profile* profile); + virtual void ShowPageInfo(Profile* profile, + const GURL& url, + const NavigationEntry::SSLStatus& ssl, + bool show_history); + virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, + bool* is_keyboard_shortcut); + virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event); + virtual void ShowRepostFormWarningDialog(TabContents* tab_contents); + virtual void ShowContentSettingsWindow(ContentSettingsType content_type); + virtual void ShowCollectedCookiesDialog(TabContents* tab_contents); + virtual bool ShouldAddNavigationToHistory( + const history::HistoryAddPageArgs& add_page_args, + NavigationType::Type navigation_type); + virtual void OnDidGetApplicationInfo(TabContents* tab_contents, + int32 page_id); + virtual void ContentRestrictionsChanged(TabContents* source); + + // Overridden from SelectFileDialog::Listener: + virtual void FileSelected(const FilePath& path, int index, void* params); + + // Overridden from NotificationObserver: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // Overridden from ProfileSyncServiceObserver: + virtual void OnStateChanged(); + + // Overriden from InstantDelegate: + virtual void ShowInstant(TabContents* preview_contents); + virtual void HideInstant(); + virtual void CommitInstant(TabContents* preview_contents); + virtual void SetSuggestedText(const string16& text); + virtual gfx::Rect GetInstantBounds(); + + // Command and state updating /////////////////////////////////////////////// + + // Initialize state for all browser commands. + void InitCommandState(); + + // Update commands whose state depends on the tab's state. + void UpdateCommandsForTabState(); + + // Updates commands when the content's restrictions change. + void UpdateCommandsForContentRestrictionState(); + + // Updates commands for enabling developer tools. + void UpdateCommandsForDevTools(); + + // Updates the printing command state. + void UpdatePrintingState(int content_restrictions); + + // Ask the Reload/Stop button to change its icon, and update the Stop command + // state. |is_loading| is true if the current TabContents is loading. + // |force| is true if the button should change its icon immediately. + void UpdateReloadStopState(bool is_loading, bool force); + + // UI update coalescing and handling //////////////////////////////////////// + + // Asks the toolbar (and as such the location bar) to update its state to + // reflect the current tab's current URL, security state, etc. + // If |should_restore_state| is true, we're switching (back?) to this tab and + // should restore any previous location bar state (such as user editing) as + // well. + void UpdateToolbar(bool should_restore_state); + + // Does one or both of the following for each bit in |changed_flags|: + // . If the update should be processed immediately, it is. + // . If the update should processed asynchronously (to avoid lots of ui + // updates), then scheduled_updates_ is updated for the |source| and update + // pair and a task is scheduled (assuming it isn't running already) + // that invokes ProcessPendingUIUpdates. + void ScheduleUIUpdate(const TabContents* source, unsigned changed_flags); + + // Processes all pending updates to the UI that have been scheduled by + // ScheduleUIUpdate in scheduled_updates_. + void ProcessPendingUIUpdates(); + + // Removes all entries from scheduled_updates_ whose source is contents. + void RemoveScheduledUpdatesFor(TabContents* contents); + + // Getters for UI /////////////////////////////////////////////////////////// + + // TODO(beng): remove, and provide AutomationProvider a better way to access + // the LocationBarView's edit. + friend class AutomationProvider; + friend class TestingAutomationProvider; + + // Returns the StatusBubble from the current toolbar. It is possible for + // this to return NULL if called before the toolbar has initialized. + // TODO(beng): remove this. + StatusBubble* GetStatusBubble(); + + // Session restore functions //////////////////////////////////////////////// + + // Notifies the history database of the index for all tabs whose index is + // >= index. + void SyncHistoryWithTabs(int index); + + // OnBeforeUnload handling ////////////////////////////////////////////////// + + typedef std::set UnloadListenerSet; + + // Processes the next tab that needs it's beforeunload/unload event fired. + void ProcessPendingTabs(); + + // Whether we've completed firing all the tabs' beforeunload/unload events. + bool HasCompletedUnloadProcessing() const; + + // Clears all the state associated with processing tabs' beforeunload/unload + // events since the user cancelled closing the window. + void CancelWindowClose(); + + // Removes |tab| from the passed |set|. + // Returns whether the tab was in the set in the first place. + // TODO(beng): this method needs a better name! + bool RemoveFromSet(UnloadListenerSet* set, TabContents* tab); + + // Cleans up state appropriately when we are trying to close the browser and + // the tab has finished firing its unload handler. We also use this in the + // cases where a tab crashes or hangs even if the beforeunload/unload haven't + // successfully fired. + void ClearUnloadState(TabContents* tab); + + // In-progress download termination handling ///////////////////////////////// + + // Called when the window is closing to check if potential in-progress + // downloads should prevent it from closing. + // Returns true if the window can close, false otherwise. + bool CanCloseWithInProgressDownloads(); + + // Assorted utility functions /////////////////////////////////////////////// + + // Checks whether |source| is about to navigate across extension extents, and + // if so, navigates in the correct window. For example if this is a normal + // browser and we're about to navigate into an extent, this method will + // navigate the app's window instead. If we're in an app window and + // navigating out of the app, this method will find and navigate a normal + // browser instead. + // + // Returns true if the navigation was handled, eg, it was opened in some other + // browser. + // + // Returns false if it was not handled. In this case, the method may also + // modify |disposition| to a more suitable value. + bool HandleCrossAppNavigation(TabContents* source, + const GURL& url, + const GURL& referrer, + WindowOpenDisposition *disposition, + PageTransition::Type transition); + + // Shows the Find Bar, optionally selecting the next entry that matches the + // existing search string for that Tab. |forward_direction| controls the + // search direction. + void FindInPage(bool find_next, bool forward_direction); + + // Closes the frame. + // TODO(beng): figure out if we need this now that the frame itself closes + // after a return to the message loop. + void CloseFrame(); + + void TabDetachedAtImpl(TabContents* contents, int index, DetachType type); + + // Create a preference dictionary for the provided application name. This is + // done only once per application name / per session. + static void RegisterAppPrefs(const std::string& app_name); + + // Shared code between Reload() and ReloadIgnoringCache(). + void ReloadInternal(WindowOpenDisposition disposition, bool ignore_cache); + + // Return true if the window dispositions means opening a new tab. + bool ShouldOpenNewTabForWindowDisposition(WindowOpenDisposition disposition); + + // Depending on the disposition, return the current tab or a clone of the + // current tab. + TabContents* GetOrCloneTabForDisposition(WindowOpenDisposition disposition); + + // Sets the insertion policy of the tabstrip based on whether vertical tabs + // are enabled. + void UpdateTabStripModelInsertionPolicy(); + + // Invoked when the use vertical tabs preference changes. Resets the insertion + // policy of the tab strip model and notifies the window. + void UseVerticalTabsChanged(); + + // Implementation of SupportsWindowFeature and CanSupportWindowFeature. If + // |check_fullscreen| is true, the set of features reflect the actual state of + // the browser, otherwise the set of features reflect the possible state of + // the browser. + bool SupportsWindowFeatureImpl(WindowFeature feature, + bool check_fullscreen) const; + + // Determines if closing of browser can really be permitted after normal + // sequence of downloads and unload handlers have given the go-ahead to close. + // It is called from ShouldCloseWindow. It checks with + // TabCloseableStateWatcher to confirm if browser can really be closed. + // Appropriate action is taken by watcher as it sees fit. + // If watcher denies closing of browser, CancelWindowClose is called to + // cancel closing of window. + bool IsClosingPermitted(); + + // Commits the current instant, returning true on success. This is intended + // for use from OpenCurrentURL. + bool OpenInstant(WindowOpenDisposition disposition); + + // If this browser should have instant one is created, otherwise does nothing. + void CreateInstantIfNecessary(); + + // Data members ///////////////////////////////////////////////////////////// + + NotificationRegistrar registrar_; + + // This Browser's type. + const Type type_; + + // This Browser's profile. + Profile* const profile_; + + // This Browser's window. + BrowserWindow* window_; + + // This Browser's current TabHandler. + scoped_ptr tab_handler_; + + // The CommandUpdater that manages the browser window commands. + CommandUpdater command_updater_; + + // An optional application name which is used to retrieve and save window + // positions. + std::string app_name_; + + // Unique identifier of this browser for session restore. This id is only + // unique within the current session, and is not guaranteed to be unique + // across sessions. + const SessionID session_id_; + + // The model for the toolbar view. + ToolbarModel toolbar_model_; + + // UI update coalescing and handling //////////////////////////////////////// + + typedef std::map UpdateMap; + + // Maps from TabContents to pending UI updates that need to be processed. + // We don't update things like the URL or tab title right away to avoid + // flickering and extra painting. + // See ScheduleUIUpdate and ProcessPendingUIUpdates. + UpdateMap scheduled_updates_; + + // The following factory is used for chrome update coalescing. + ScopedRunnableMethodFactory chrome_updater_factory_; + + // OnBeforeUnload handling ////////////////////////////////////////////////// + + // Tracks tabs that need there beforeunload event fired before we can + // close the browser. Only gets populated when we try to close the browser. + UnloadListenerSet tabs_needing_before_unload_fired_; + + // Tracks tabs that need there unload event fired before we can + // close the browser. Only gets populated when we try to close the browser. + UnloadListenerSet tabs_needing_unload_fired_; + + // Whether we are processing the beforeunload and unload events of each tab + // in preparation for closing the browser. + bool is_attempting_to_close_browser_; + + // In-progress download termination handling ///////////////////////////////// + + enum CancelDownloadConfirmationState { + NOT_PROMPTED, // We have not asked the user. + WAITING_FOR_RESPONSE, // We have asked the user and have not received a + // reponse yet. + RESPONSE_RECEIVED // The user was prompted and made a decision already. + }; + + // State used to figure-out whether we should prompt the user for confirmation + // when the browser is closed with in-progress downloads. + CancelDownloadConfirmationState cancel_download_confirmation_state_; + + ///////////////////////////////////////////////////////////////////////////// + + // Override values for the bounds of the window and its maximized state. + // These are supplied by callers that don't want to use the default values. + // The default values are typically loaded from local state (last session), + // obtained from the last window of the same type, or obtained from the + // shell shortcut's startup info. + gfx::Rect override_bounds_; + MaximizedState maximized_state_; + + // The following factory is used to close the frame at a later time. + ScopedRunnableMethodFactory method_factory_; + + // The Find Bar. This may be NULL if there is no Find Bar, and if it is + // non-NULL, it may or may not be visible. + scoped_ptr find_bar_controller_; + + // Dialog box used for opening and saving files. + scoped_refptr select_file_dialog_; + + // Keep track of the encoding auto detect pref. + BooleanPrefMember encoding_auto_detect_; + + // Keep track of the printing enabled pref. + BooleanPrefMember printing_enabled_; + + // Keep track of the development tools disabled pref. + BooleanPrefMember dev_tools_disabled_; + + // Keep track of when instant enabled changes. + BooleanPrefMember instant_enabled_; + + // Indicates if command execution is blocked. + bool block_command_execution_; + + // Stores the last blocked command id when |block_command_execution_| is true. + int last_blocked_command_id_; + + // Stores the disposition type of the last blocked command. + WindowOpenDisposition last_blocked_command_disposition_; + + // Different types of action when web app info is available. + // OnDidGetApplicationInfo uses this to dispatch calls. + enum WebAppAction { + NONE, // No action at all. + CREATE_SHORTCUT, // Bring up create application shortcut dialog. + UPDATE_SHORTCUT // Update icon for app shortcut. + }; + + // Which deferred action to perform when OnDidGetApplicationInfo is notified + // from a TabContents. Currently, only one pending action is allowed. + WebAppAction pending_web_app_action_; + + // The extension app associated with this window, if any. + const Extension* extension_app_; + + // Tracks the display mode of the tabstrip. + mutable BooleanPrefMember use_vertical_tabs_; + + // The profile's tab restore service. The service is owned by the profile, + // and we install ourselves as an observer. + TabRestoreService* tab_restore_service_; + + scoped_ptr instant_; + + DISALLOW_COPY_AND_ASSIGN(Browser); +}; + +#endif // CHROME_BROWSER_UI_BROWSER_H_ diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h new file mode 100644 index 0000000..c365a27 --- /dev/null +++ b/chrome/browser/ui/browser_window.h @@ -0,0 +1,384 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_BROWSER_WINDOW_H_ +#define CHROME_BROWSER_UI_BROWSER_WINDOW_H_ +#pragma once + +#include "chrome/browser/tab_contents/navigation_entry.h" +#include "chrome/common/content_settings_types.h" +#include "gfx/native_widget_types.h" + +class Browser; +class BrowserWindowTesting; +class DownloadShelf; +class FindBar; +class GURL; +class HtmlDialogUIDelegate; +class LocationBar; +class Profile; +class StatusBubble; +class TabContents; +class TemplateURL; +class TemplateURLModel; +#if !defined(OS_MACOSX) +class ToolbarView; +#endif +struct NativeWebKeyboardEvent; + +namespace gfx { +class Rect; +} + +namespace views { +class Window; +} + +//////////////////////////////////////////////////////////////////////////////// +// BrowserWindow interface +// An interface implemented by the "view" of the Browser window. +// +// NOTE: All getters may return NULL. +class BrowserWindow { + public: + // Show the window, or activates it if it's already visible. + virtual void Show() = 0; + + // Sets the window's size and position to the specified values. + virtual void SetBounds(const gfx::Rect& bounds) = 0; + + // Closes the frame as soon as possible. If the frame is not in a drag + // session, it will close immediately; otherwise, it will move offscreen (so + // events are still fired) until the drag ends, then close. This assumes + // that the Browser is not immediately destroyed, but will be eventually + // destroyed by other means (eg, the tab strip going to zero elements). + // Bad things happen if the Browser dtor is called directly as a result of + // invoking this method. + virtual void Close() = 0; + + // Activates (brings to front) the window. Restores the window from minimized + // state if necessary. + virtual void Activate() = 0; + + // Deactivates the window, making the next window in the Z order the active + // window. + virtual void Deactivate() = 0; + + // Returns true if the window is currently the active/focused window. + virtual bool IsActive() const = 0; + + // Flashes the taskbar item associated with this frame. + virtual void FlashFrame() = 0; + + // Return a platform dependent identifier for this frame. On Windows, this + // returns an HWND. + virtual gfx::NativeWindow GetNativeHandle() = 0; + + // Returns a pointer to the testing interface to the Browser window, or NULL + // if there is none. + virtual BrowserWindowTesting* GetBrowserWindowTesting() = 0; + + // Return the status bubble associated with the frame + virtual StatusBubble* GetStatusBubble() = 0; + + // Inform the receiving frame that an animation has progressed in the + // selected tab. + // TODO(beng): Remove. Infobars/Boomarks bars should talk directly to + // BrowserView. + virtual void SelectedTabToolbarSizeChanged(bool is_animating) = 0; + + // Inform the frame that the selected tab favicon or title has changed. Some + // frames may need to refresh their title bar. + virtual void UpdateTitleBar() = 0; + + // Invoked when the visibility of the bookmark bar. + // NOTE: this is NOT sent when the user toggles the visibility of this, + // but rather when the user transitions from a page that forces + // it to be visibile to one that doesn't have it visible (or + // vice-versa). + // TODO(sky): see about routing visibility pref changing through here too. + virtual void ShelfVisibilityChanged() = 0; + + // Inform the frame that the dev tools window for the selected tab has + // changed. + virtual void UpdateDevTools() = 0; + + // Update any loading animations running in the window. |should_animate| is + // true if there are tabs loading and the animations should continue, false + // if there are no active loads and the animations should end. + virtual void UpdateLoadingAnimations(bool should_animate) = 0; + + // Sets the starred state for the current tab. + virtual void SetStarredState(bool is_starred) = 0; + + // Returns the nonmaximized bounds of the frame (even if the frame is + // currently maximized or minimized) in terms of the screen coordinates. + virtual gfx::Rect GetRestoredBounds() const = 0; + + // TODO(beng): REMOVE? + // Returns true if the frame is maximized (aka zoomed). + virtual bool IsMaximized() const = 0; + + // Accessors for fullscreen mode state. + virtual void SetFullscreen(bool fullscreen) = 0; + virtual bool IsFullscreen() const = 0; + + // Returns true if the fullscreen bubble is visible. + virtual bool IsFullscreenBubbleVisible() const = 0; + + // Returns the location bar. + virtual LocationBar* GetLocationBar() const = 0; + + // Tries to focus the location bar. Clears the window focus (to avoid + // inconsistent state) if this fails. + virtual void SetFocusToLocationBar(bool select_all) = 0; + + // Informs the view whether or not a load is in progress for the current tab. + // The view can use this notification to update the reload/stop button. + virtual void UpdateReloadStopState(bool is_loading, bool force) = 0; + + // Updates the toolbar with the state for the specified |contents|. + virtual void UpdateToolbar(TabContents* contents, + bool should_restore_state) = 0; + + // Focuses the toolbar (for accessibility). + virtual void FocusToolbar() = 0; + + // Focuses the app menu like it was a menu bar. + // + // Not used on the Mac, which has a "normal" menu bar. + virtual void FocusAppMenu() = 0; + + // Focuses the bookmarks toolbar (for accessibility). + virtual void FocusBookmarksToolbar() = 0; + + // Focuses the Chrome OS status view (for accessibility). + virtual void FocusChromeOSStatus() = 0; + + // Moves keyboard focus to the next pane. + virtual void RotatePaneFocus(bool forwards) = 0; + + // Returns whether the bookmark bar is visible or not. + virtual bool IsBookmarkBarVisible() const = 0; + + // Returns whether the bookmark bar is animating or not. + virtual bool IsBookmarkBarAnimating() const = 0; + + // Returns whether the tool bar is visible or not. + virtual bool IsToolbarVisible() const = 0; + + // Returns the rect where the resize corner should be drawn by the render + // widget host view (on top of what the renderer returns). We return an empty + // rect to identify that there shouldn't be a resize corner (in the cases + // where we take care of it ourselves at the browser level). + virtual gfx::Rect GetRootWindowResizerRect() const = 0; + + // Tells the frame not to render as inactive until the next activation change. + // This is required on Windows when dropdown selects are shown to prevent the + // select from deactivating the browser frame. A stub implementation is + // provided here since the functionality is Windows-specific. + virtual void DisableInactiveFrame() {} + + // Shows a confirmation dialog box for setting the default search engine + // described by |template_url|. Takes ownership of |template_url|. + virtual void ConfirmSetDefaultSearchProvider( + TabContents* tab_contents, + TemplateURL* template_url, + TemplateURLModel* template_url_model) { + // TODO(levin): Implement this for non-Windows platforms and make it pure. + } + + // Shows a confirmation dialog box for adding a search engine described by + // |template_url|. Takes ownership of |template_url|. + virtual void ConfirmAddSearchProvider(const TemplateURL* template_url, + Profile* profile) = 0; + + // Shows or hides the bookmark bar depending on its current visibility. + virtual void ToggleBookmarkBar() = 0; + + // Shows the About Chrome dialog box. + virtual views::Window* ShowAboutChromeDialog() = 0; + + // Shows the Update Recommended dialog box. + virtual void ShowUpdateChromeDialog() = 0; + + // Shows the Task manager. + virtual void ShowTaskManager() = 0; + + // Shows the Bookmark bubble. |url| is the URL being bookmarked, + // |already_bookmarked| is true if the url is already bookmarked. + virtual void ShowBookmarkBubble(const GURL& url, bool already_bookmarked) = 0; + + // Whether or not the shelf view is visible. + virtual bool IsDownloadShelfVisible() const = 0; + + // Returns the DownloadShelf. + virtual DownloadShelf* GetDownloadShelf() = 0; + + // Shows the Report a Bug dialog box. + virtual void ShowReportBugDialog() = 0; + + // Shows the Clear Browsing Data dialog box. + virtual void ShowClearBrowsingDataDialog() = 0; + + // Shows the Import Bookmarks & Settings dialog box. + virtual void ShowImportDialog() = 0; + + // Shows the Search Engines dialog box. + virtual void ShowSearchEnginesDialog() = 0; + + // Shows the Password Manager dialog box. + virtual void ShowPasswordManager() = 0; + + // Shows the repost form confirmation dialog box. + virtual void ShowRepostFormWarningDialog(TabContents* tab_contents) = 0; + + // Shows the Content Settings dialog box. + virtual void ShowContentSettingsWindow(ContentSettingsType content_type, + Profile* profile) = 0; + + // Shows the collected cookies dialog box. + virtual void ShowCollectedCookiesDialog(TabContents* tab_contents) = 0; + + // Shows a dialog to the user that something is wrong with the profile. + // |message_id| is the ID for a string in the string table which will be + // displayed in the dialog. + virtual void ShowProfileErrorDialog(int message_id) = 0; + + // Show the bubble that indicates to the user that a theme is being installed. + virtual void ShowThemeInstallBubble() = 0; + + // Shows the confirmation dialog box warning that the browser is closing with + // in-progress downloads. + // This method should call Browser::InProgressDownloadResponse once the user + // has confirmed. + virtual void ConfirmBrowserCloseWithPendingDownloads() = 0; + + // Shows a dialog box with HTML content, e.g. for Gears. |parent_window| is + // the window the dialog should be opened modal to and is a native window + // handle. + virtual void ShowHTMLDialog(HtmlDialogUIDelegate* delegate, + gfx::NativeWindow parent_window) = 0; + + // Asks the window to continue a drag operation begun in a different browser + // window. |tab_bounds| are the bounds of the Tab view that was dragged from + // the source window, in screen coordinates. The corresponding Tab view in + // this new window will be positioned at these bounds for a seamless + // appearance. + virtual void ContinueDraggingDetachedTab(const gfx::Rect& tab_bounds) {} + + // BrowserThemeProvider calls this when a user has changed his or her theme, + // indicating that it's time to redraw everything. + virtual void UserChangedTheme() = 0; + + // Get extra vertical height that the render view should add to its requests + // to webkit. This can help prevent sending extraneous layout/repaint requests + // when the delegate is in the process of resizing the tab contents view (e.g. + // during infobar animations). + virtual int GetExtraRenderViewHeight() const = 0; + + // Notification that |tab_contents| got the focus through user action (click + // on the page). + virtual void TabContentsFocused(TabContents* tab_contents) = 0; + + // Shows the page info using the specified information. + // |url| is the url of the page/frame the info applies to, |ssl| is the SSL + // information for that page/frame. If |show_history| is true, a section + // showing how many times that URL has been visited is added to the page info. + virtual void ShowPageInfo(Profile* profile, + const GURL& url, + const NavigationEntry::SSLStatus& ssl, + bool show_history) = 0; + + // Shows the app menu (for accessibility). + virtual void ShowAppMenu() = 0; + + // Allows the BrowserWindow object to handle the specified keyboard event + // before sending it to the renderer. + // Returns true if the |event| was handled. Otherwise, if the |event| would + // be handled in HandleKeyboardEvent() method as a normal keyboard shortcut, + // |*is_keyboard_shortcut| should be set to true. + virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, + bool* is_keyboard_shortcut) = 0; + + // Allows the BrowserWindow object to handle the specified keyboard event, + // if the renderer did not process it. + virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) = 0; + + // Shows the create web app shortcut dialog box. + virtual void ShowCreateShortcutsDialog(TabContents* tab_contents) = 0; + + // Clipboard commands applied to the whole browser window. + virtual void Cut() = 0; + virtual void Copy() = 0; + virtual void Paste() = 0; + + // Switches between available tabstrip display modes. + virtual void ToggleTabStripMode() = 0; + +#if defined(OS_MACOSX) + // Opens the tabpose view. + virtual void OpenTabpose() = 0; +#endif + + // Invoked when instant's tab contents should be shown. + virtual void ShowInstant(TabContents* preview_contents) = 0; + + // Invoked when the instant's tab contents should be hidden. + virtual void HideInstant() = 0; + + // Returns the desired bounds for instant in screen coordinates. Note that if + // instant isn't currently visible this returns the bounds instant would be + // placed at. + virtual gfx::Rect GetInstantBounds() = 0; + + // Construct a BrowserWindow implementation for the specified |browser|. + static BrowserWindow* CreateBrowserWindow(Browser* browser); + + // Construct a FindBar implementation for the specified |browser|. + static FindBar* CreateFindBar(Browser* browser_window); + + protected: + friend class BrowserList; + friend class BrowserView; + virtual void DestroyBrowser() = 0; + + virtual ~BrowserWindow() {} +}; + +#if defined(OS_WIN) || defined(TOOLKIT_VIEWS) +class BookmarkBarView; +class LocationBarView; + +namespace views { +class View; +} +#endif // defined(OS_WIN) + +// A BrowserWindow utility interface used for accessing elements of the browser +// UI used only by UI test automation. +class BrowserWindowTesting { + public: +#if defined(OS_WIN) || defined(TOOLKIT_VIEWS) + // Returns the BookmarkBarView. + virtual BookmarkBarView* GetBookmarkBarView() const = 0; + + // Returns the LocationBarView. + virtual LocationBarView* GetLocationBarView() const = 0; + + // Returns the TabContentsContainer. + virtual views::View* GetTabContentsContainerView() const = 0; + + // Returns the TabContentsContainer. + virtual views::View* GetSidebarContainerView() const = 0; + + // Returns the ToolbarView. + virtual ToolbarView* GetToolbarView() const = 0; +#endif + + protected: + virtual ~BrowserWindowTesting() {} +}; + +#endif // CHROME_BROWSER_UI_BROWSER_WINDOW_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index bfc8853..cc7d5ae 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -299,8 +299,6 @@ 'browser/bookmarks/bookmark_utils.h', 'browser/bookmarks/recently_used_folders_combo_model.cc', 'browser/bookmarks/recently_used_folders_combo_model.h', - 'browser/browser.cc', - 'browser/browser.h', 'browser/browser_about_handler.cc', 'browser/browser_about_handler.h', 'browser/browser_child_process_host.cc', @@ -339,7 +337,6 @@ 'browser/browser_trial.h', 'browser/browser_url_handler.cc', 'browser/browser_url_handler.h', - 'browser/browser_window.h', 'browser/browsing_data_appcache_helper.cc', 'browser/browsing_data_appcache_helper.h', 'browser/browsing_data_database_helper.cc', @@ -2963,6 +2960,9 @@ 'browser/ui_thread_helpers_linux.cc', 'browser/ui_thread_helpers_mac.mm', 'browser/ui_thread_helpers_win.cc', + 'browser/ui/browser.cc', + 'browser/ui/browser.h', + 'browser/ui/browser_window.h', 'browser/upgrade_detector.cc', 'browser/upgrade_detector.h', 'browser/user_style_sheet_watcher.cc', -- cgit v1.1