Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(569)

Side by Side Diff: chrome/browser/ui/browser_command_controller.cc

Issue 10677009: Move command handling and updating off Browser and onto a helper object. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/ui/browser_command_controller.h ('k') | chrome/browser/ui/browser_commands.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/browser.h" 5 #include "chrome/browser/ui/browser_command_controller.h"
6 6
7 #if defined(OS_WIN)
8 #include <windows.h>
9 #include <shellapi.h>
10 #endif // OS_WIN
11
12 #include <algorithm>
13 #include <string>
14
15 #include "base/base_paths.h"
16 #include "base/bind.h"
17 #include "base/command_line.h"
18 #include "base/logging.h"
19 #include "base/metrics/field_trial.h"
20 #include "base/metrics/histogram.h"
21 #include "base/path_service.h"
22 #include "base/string_number_conversions.h"
23 #include "base/string_util.h"
24 #include "base/stringprintf.h"
25 #include "base/threading/thread.h"
26 #include "base/threading/thread_restrictions.h"
27 #include "base/time.h"
28 #include "base/utf_string_conversions.h"
29 #include "chrome/app/chrome_command_ids.h" 7 #include "chrome/app/chrome_command_ids.h"
30 #include "chrome/browser/autofill/personal_data_manager_factory.h"
31 #include "chrome/browser/background/background_contents_service.h"
32 #include "chrome/browser/background/background_contents_service_factory.h"
33 #include "chrome/browser/bookmarks/bookmark_model.h"
34 #include "chrome/browser/bookmarks/bookmark_utils.h"
35 #include "chrome/browser/browser_process.h" 8 #include "chrome/browser/browser_process.h"
36 #include "chrome/browser/browser_shutdown.h" 9 #include "chrome/browser/defaults.h"
37 #include "chrome/browser/character_encoding.h"
38 #include "chrome/browser/chrome_page_zoom.h"
39 #include "chrome/browser/content_settings/host_content_settings_map.h"
40 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
41 #include "chrome/browser/custom_handlers/register_protocol_handler_infobar_deleg ate.h"
42 #include "chrome/browser/debugger/devtools_toggle_action.h"
43 #include "chrome/browser/debugger/devtools_window.h"
44 #include "chrome/browser/download/download_crx_util.h"
45 #include "chrome/browser/download/download_item_model.h"
46 #include "chrome/browser/download/download_service.h"
47 #include "chrome/browser/download/download_service_factory.h"
48 #include "chrome/browser/download/download_shelf.h"
49 #include "chrome/browser/download/download_started_animation.h"
50 #include "chrome/browser/download/download_util.h"
51 #include "chrome/browser/extensions/browser_extension_window_controller.h"
52 #include "chrome/browser/extensions/crx_installer.h"
53 #include "chrome/browser/extensions/default_apps_trial.h"
54 #include "chrome/browser/extensions/extension_prefs.h"
55 #include "chrome/browser/extensions/extension_service.h" 10 #include "chrome/browser/extensions/extension_service.h"
56 #include "chrome/browser/extensions/extension_tab_helper.h"
57 #include "chrome/browser/favicon/favicon_tab_helper.h"
58 #include "chrome/browser/file_select_helper.h"
59 #include "chrome/browser/first_run/first_run.h"
60 #include "chrome/browser/google/google_url_tracker.h"
61 #include "chrome/browser/infobars/infobar_tab_helper.h"
62 #include "chrome/browser/instant/instant_controller.h"
63 #include "chrome/browser/instant/instant_unload_handler.h"
64 #include "chrome/browser/intents/register_intent_handler_infobar_delegate.h"
65 #include "chrome/browser/intents/web_intents_util.h"
66 #include "chrome/browser/lifetime/application_lifetime.h"
67 #include "chrome/browser/media/media_stream_devices_controller.h"
68 #include "chrome/browser/net/url_fixer_upper.h"
69 #include "chrome/browser/notifications/notification_ui_manager.h"
70 #include "chrome/browser/platform_util.h"
71 #include "chrome/browser/prefs/incognito_mode_prefs.h" 11 #include "chrome/browser/prefs/incognito_mode_prefs.h"
72 #include "chrome/browser/prefs/pref_service.h" 12 #include "chrome/browser/prefs/pref_service.h"
73 #include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h"
74 #include "chrome/browser/printing/print_preview_tab_controller.h" 13 #include "chrome/browser/printing/print_preview_tab_controller.h"
75 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/profiles/profile.h"
76 #include "chrome/browser/profiles/profile_destroyer.h"
77 #include "chrome/browser/profiles/profile_manager.h" 15 #include "chrome/browser/profiles/profile_manager.h"
78 #include "chrome/browser/profiles/profile_metrics.h"
79 #include "chrome/browser/repost_form_warning_controller.h"
80 #include "chrome/browser/sessions/restore_tab_helper.h"
81 #include "chrome/browser/sessions/session_service.h"
82 #include "chrome/browser/sessions/session_service_factory.h"
83 #include "chrome/browser/sessions/session_types.h"
84 #include "chrome/browser/sessions/tab_restore_service.h" 16 #include "chrome/browser/sessions/tab_restore_service.h"
85 #include "chrome/browser/sessions/tab_restore_service_factory.h" 17 #include "chrome/browser/sessions/tab_restore_service_factory.h"
86 #include "chrome/browser/sync/profile_sync_service.h" 18 #include "chrome/browser/sync/profile_sync_service.h"
87 #include "chrome/browser/sync/profile_sync_service_factory.h" 19 #include "chrome/browser/sync/profile_sync_service_factory.h"
88 #include "chrome/browser/sync/sync_ui_util.h"
89 #include "chrome/browser/tab_contents/background_contents.h"
90 #include "chrome/browser/tab_contents/retargeting_details.h"
91 #include "chrome/browser/tab_contents/simple_alert_infobar_delegate.h"
92 #include "chrome/browser/tab_contents/tab_util.h"
93 #include "chrome/browser/themes/theme_service.h"
94 #include "chrome/browser/themes/theme_service_factory.h"
95 #include "chrome/browser/ui/app_modal_dialogs/javascript_dialog_creator.h"
96 #include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h"
97 #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h" 20 #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
21 #include "chrome/browser/ui/browser.h"
98 #include "chrome/browser/ui/browser_commands.h" 22 #include "chrome/browser/ui/browser_commands.h"
99 #include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h"
100 #include "chrome/browser/ui/browser_dialogs.h"
101 #include "chrome/browser/ui/browser_finder.h"
102 #include "chrome/browser/ui/browser_list.h"
103 #include "chrome/browser/ui/browser_navigator.h"
104 #include "chrome/browser/ui/browser_tab_restore_service_delegate.h"
105 #include "chrome/browser/ui/browser_toolbar_model_delegate.h"
106 #include "chrome/browser/ui/browser_ui_prefs.h"
107 #include "chrome/browser/ui/browser_window.h" 23 #include "chrome/browser/ui/browser_window.h"
108 #include "chrome/browser/ui/chrome_pages.h" 24 #include "chrome/browser/ui/chrome_pages.h"
109 #include "chrome/browser/ui/constrained_window_tab_helper.h"
110 #include "chrome/browser/ui/extensions/shell_window.h"
111 #include "chrome/browser/ui/find_bar/find_bar.h"
112 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
113 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
114 #include "chrome/browser/ui/fullscreen_controller.h"
115 #include "chrome/browser/ui/global_error.h"
116 #include "chrome/browser/ui/global_error_service.h"
117 #include "chrome/browser/ui/global_error_service_factory.h"
118 #include "chrome/browser/ui/hung_plugin_tab_helper.h"
119 #include "chrome/browser/ui/intents/web_intent_picker_controller.h"
120 #include "chrome/browser/ui/media_stream_infobar_delegate.h"
121 #include "chrome/browser/ui/omnibox/location_bar.h"
122 #include "chrome/browser/ui/panels/panel.h"
123 #include "chrome/browser/ui/panels/panel_manager.h"
124 #include "chrome/browser/ui/search/search.h"
125 #include "chrome/browser/ui/search/search_delegate.h"
126 #include "chrome/browser/ui/search/search_model.h"
127 #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
128 #include "chrome/browser/ui/singleton_tabs.h"
129 #include "chrome/browser/ui/status_bubble.h"
130 #include "chrome/browser/ui/sync/browser_synced_window_delegate.h"
131 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
132 #include "chrome/browser/ui/tab_contents/tab_contents.h" 25 #include "chrome/browser/ui/tab_contents/tab_contents.h"
133 #include "chrome/browser/ui/tabs/dock_info.h"
134 #include "chrome/browser/ui/tabs/tab_menu_model.h"
135 #include "chrome/browser/ui/tabs/tab_strip_model.h" 26 #include "chrome/browser/ui/tabs/tab_strip_model.h"
136 #include "chrome/browser/ui/web_applications/web_app_ui.h" 27 #include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
137 #include "chrome/browser/ui/webui/feedback_ui.h"
138 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
139 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
140 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
141 #include "chrome/browser/ui/window_sizer.h"
142 #include "chrome/browser/upgrade_detector.h"
143 #include "chrome/browser/web_applications/web_app.h"
144 #include "chrome/common/chrome_constants.h"
145 #include "chrome/common/chrome_notification_types.h" 28 #include "chrome/common/chrome_notification_types.h"
146 #include "chrome/common/chrome_switches.h"
147 #include "chrome/common/custom_handlers/protocol_handler.h"
148 #include "chrome/common/extensions/extension.h"
149 #include "chrome/common/extensions/extension_constants.h"
150 #include "chrome/common/pref_names.h" 29 #include "chrome/common/pref_names.h"
151 #include "chrome/common/profiling.h" 30 #include "chrome/common/profiling.h"
152 #include "chrome/common/url_constants.h" 31 #include "content/public/browser/native_web_keyboard_event.h"
153 #include "chrome/common/web_apps.h"
154 #include "content/public/browser/color_chooser.h"
155 #include "content/public/browser/devtools_manager.h"
156 #include "content/public/browser/download_item.h"
157 #include "content/public/browser/download_manager.h"
158 #include "content/public/browser/interstitial_page.h"
159 #include "content/public/browser/invalidate_type.h"
160 #include "content/public/browser/navigation_controller.h" 32 #include "content/public/browser/navigation_controller.h"
161 #include "content/public/browser/navigation_entry.h" 33 #include "content/public/browser/navigation_entry.h"
162 #include "content/public/browser/notification_details.h" 34 #include "content/public/browser/notification_details.h"
163 #include "content/public/browser/notification_service.h" 35 #include "content/public/browser/notification_source.h"
164 #include "content/public/browser/plugin_service.h"
165 #include "content/public/browser/render_process_host.h"
166 #include "content/public/browser/render_view_host.h"
167 #include "content/public/browser/site_instance.h"
168 #include "content/public/browser/user_metrics.h"
169 #include "content/public/browser/web_contents.h" 36 #include "content/public/browser/web_contents.h"
170 #include "content/public/browser/web_contents_view.h"
171 #include "content/public/browser/web_intents_dispatcher.h"
172 #include "content/public/common/content_restriction.h" 37 #include "content/public/common/content_restriction.h"
173 #include "content/public/common/content_switches.h" 38 #include "content/public/common/url_constants.h"
174 #include "content/public/common/page_zoom.h" 39 #include "ui/base/keycodes/keyboard_codes.h"
175 #include "content/public/common/renderer_preferences.h"
176 #include "grit/chromium_strings.h"
177 #include "grit/generated_resources.h"
178 #include "grit/locale_settings.h"
179 #include "grit/theme_resources_standard.h"
180 #include "net/base/net_util.h"
181 #include "net/base/registry_controlled_domain.h"
182 #include "net/cookies/cookie_monster.h"
183 #include "net/url_request/url_request_context.h"
184 #include "ui/base/animation/animation.h"
185 #include "ui/base/l10n/l10n_util.h"
186 #include "ui/gfx/point.h"
187 #include "webkit/glue/web_intent_data.h"
188 #include "webkit/glue/web_intent_service_data.h"
189 #include "webkit/glue/webkit_glue.h"
190 #include "webkit/glue/window_open_disposition.h"
191 #include "webkit/plugins/webplugininfo.h"
192 40
193 #if defined(OS_WIN) 41 #if defined(OS_WIN)
194 #include "base/win/metro.h" 42 #include "base/win/metro.h"
195 #include "chrome/browser/autofill/autofill_ie_toolbar_import_win.h"
196 #include "chrome/browser/shell_integration.h"
197 #include "chrome/browser/ssl/ssl_error_info.h"
198 #include "chrome/browser/task_manager/task_manager.h"
199 #include "chrome/browser/ui/view_ids.h"
200 #include "ui/base/win/shell.h"
201 #endif // OS_WIN
202
203 #if defined(OS_CHROMEOS)
204 #include "chrome/browser/chromeos/gdata/gdata_util.h"
205 #endif 43 #endif
206 44
207 #if defined(USE_ASH) 45 using content::WebContents;
208 #include "ash/ash_switches.h" 46 using content::NavigationEntry;
209 #endif
210
211 using base::TimeDelta;
212 using content::NativeWebKeyboardEvent;
213 using content::NavigationController; 47 using content::NavigationController;
214 using content::NavigationEntry;
215 using content::OpenURLParams;
216 using content::PluginService;
217 using content::Referrer;
218 using content::SiteInstance;
219 using content::UserMetricsAction;
220 using content::WebContents; 48 using content::WebContents;
221 using extensions::Extension;
222 using ui::WebDialogDelegate;
223
224 ///////////////////////////////////////////////////////////////////////////////
225 49
226 namespace { 50 namespace {
227 51
228 // The URL to be loaded to display the "Report a broken page" form.
229 const char kBrokenPageUrl[] =
230 "https://www.google.com/support/chrome/bin/request.py?contact_type="
231 "broken_website&format=inproduct&p.page_title=$1&p.page_url=$2";
232
233 // The URL for the privacy dashboard.
234 const char kPrivacyDashboardUrl[] = "https://www.google.com/dashboard";
235
236 // How long we wait before updating the browser chrome while loading a page.
237 const int kUIUpdateCoalescingTimeMS = 200;
238
239 // Returns |true| if entry has an internal chrome:// URL, |false| otherwise. 52 // Returns |true| if entry has an internal chrome:// URL, |false| otherwise.
240 bool HasInternalURL(const NavigationEntry* entry) { 53 bool HasInternalURL(const NavigationEntry* entry) {
241 if (!entry) 54 if (!entry)
242 return false; 55 return false;
243 56
244 // Check the |virtual_url()| first. This catches regular chrome:// URLs 57 // Check the |virtual_url()| first. This catches regular chrome:// URLs
245 // including URLs that were rewritten (such as chrome://bookmarks). 58 // including URLs that were rewritten (such as chrome://bookmarks).
246 if (entry->GetVirtualURL().SchemeIs(chrome::kChromeUIScheme)) 59 if (entry->GetVirtualURL().SchemeIs(chrome::kChromeUIScheme))
247 return true; 60 return true;
248 61
249 // If the |virtual_url()| isn't a chrome:// URL, check if it's actually 62 // If the |virtual_url()| isn't a chrome:// URL, check if it's actually
250 // view-source: of a chrome:// URL. 63 // view-source: of a chrome:// URL.
251 if (entry->GetVirtualURL().SchemeIs(chrome::kViewSourceScheme)) 64 if (entry->GetVirtualURL().SchemeIs(chrome::kViewSourceScheme))
252 return entry->GetURL().SchemeIs(chrome::kChromeUIScheme); 65 return entry->GetURL().SchemeIs(chrome::kChromeUIScheme);
253 66
254 return false; 67 return false;
255 } 68 }
256 69
257 bool AllowPanels(const std::string& app_name) {
258 return PanelManager::ShouldUsePanels(
259 web_app::GetExtensionIdFromApplicationName(app_name));
260 }
261
262 } // namespace 70 } // namespace
263 71
264 //////////////////////////////////////////////////////////////////////////////// 72 namespace chrome {
265 // Browser, CreateParams:
266
267 Browser::CreateParams::CreateParams()
268 : type(TYPE_TABBED),
269 profile(NULL),
270 initial_show_state(ui::SHOW_STATE_DEFAULT),
271 is_session_restore(false) {
272 }
273
274 Browser::CreateParams::CreateParams(Type type, Profile* profile)
275 : type(type),
276 profile(profile),
277 app_type(APP_TYPE_HOST),
278 initial_show_state(ui::SHOW_STATE_DEFAULT),
279 is_session_restore(false) {
280 }
281
282 // static
283 Browser::CreateParams Browser::CreateParams::CreateForApp(
284 Type type,
285 const std::string& app_name,
286 const gfx::Rect& window_bounds,
287 Profile* profile) {
288 DCHECK(type != TYPE_TABBED);
289 DCHECK(!app_name.empty());
290
291 if (type == TYPE_PANEL && !AllowPanels(app_name))
292 type = TYPE_POPUP;
293
294 CreateParams params(type, profile);
295 params.app_name = app_name;
296 params.app_type = APP_TYPE_CHILD;
297 params.initial_bounds = window_bounds;
298
299 return params;
300 }
301
302 // static
303 Browser::CreateParams Browser::CreateParams::CreateForDevTools(
304 Profile* profile) {
305 CreateParams params(TYPE_POPUP, profile);
306 params.app_name = DevToolsWindow::kDevToolsApp;
307 return params;
308 }
309 73
310 /////////////////////////////////////////////////////////////////////////////// 74 ///////////////////////////////////////////////////////////////////////////////
311 // Browser, Constructors, Creation, Showing: 75 // BrowserCommandController, public:
312 76
313 Browser::Browser(Type type, Profile* profile) 77 BrowserCommandController::BrowserCommandController(Browser* browser)
314 : type_(type), 78 : browser_(browser),
315 profile_(profile), 79 ALLOW_THIS_IN_INITIALIZER_LIST(command_updater_(this)),
316 window_(NULL),
317 ALLOW_THIS_IN_INITIALIZER_LIST(
318 tab_strip_model_(new TabStripModel(this, profile))),
319 command_updater_(this),
320 app_type_(APP_TYPE_HOST),
321 chrome_updater_factory_(this),
322 is_attempting_to_close_browser_(false),
323 cancel_download_confirmation_state_(NOT_PROMPTED),
324 initial_show_state_(ui::SHOW_STATE_DEFAULT),
325 is_session_restore_(false),
326 weak_factory_(this),
327 block_command_execution_(false), 80 block_command_execution_(false),
328 last_blocked_command_id_(-1), 81 last_blocked_command_id_(-1),
329 last_blocked_command_disposition_(CURRENT_TAB), 82 last_blocked_command_disposition_(CURRENT_TAB) {
330 pending_web_app_action_(NONE), 83 browser_->tab_strip_model()->AddObserver(this);
331 ALLOW_THIS_IN_INITIALIZER_LIST(
332 content_setting_bubble_model_delegate_(
333 new BrowserContentSettingBubbleModelDelegate(this))),
334 ALLOW_THIS_IN_INITIALIZER_LIST(
335 toolbar_model_delegate_(
336 new BrowserToolbarModelDelegate(this))),
337 ALLOW_THIS_IN_INITIALIZER_LIST(
338 tab_restore_service_delegate_(
339 new BrowserTabRestoreServiceDelegate(this))),
340 ALLOW_THIS_IN_INITIALIZER_LIST(
341 synced_window_delegate_(
342 new BrowserSyncedWindowDelegate(this))),
343 bookmark_bar_state_(BookmarkBar::HIDDEN),
344 window_has_shown_(false) {
345 tab_strip_model_->AddObserver(this);
346
347 toolbar_model_.reset(new ToolbarModel(toolbar_model_delegate_.get()));
348 search_model_.reset(new chrome::search::SearchModel(NULL));
349 search_delegate_.reset(
350 new chrome::search::SearchDelegate(search_model_.get()));
351
352 registrar_.Add(this, content::NOTIFICATION_SSL_VISIBLE_STATE_CHANGED,
353 content::NotificationService::AllSources());
354 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
355 content::Source<Profile>(profile_->GetOriginalProfile()));
356 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
357 content::Source<Profile>(profile_->GetOriginalProfile()));
358 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
359 content::Source<Profile>(profile_->GetOriginalProfile()));
360 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
361 content::NotificationService::AllSources());
362 #if defined(ENABLE_THEMES)
363 registrar_.Add(
364 this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
365 content::Source<ThemeService>(
366 ThemeServiceFactory::GetForProfile(profile_)));
367 #endif
368 registrar_.Add(this, chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
369 content::NotificationService::AllSources());
370
371 PrefService* local_state = g_browser_process->local_state(); 84 PrefService* local_state = g_browser_process->local_state();
372 if (local_state) { 85 if (local_state) {
373 local_pref_registrar_.Init(local_state); 86 local_pref_registrar_.Init(local_state);
374 local_pref_registrar_.Add(prefs::kPrintingEnabled, this); 87 local_pref_registrar_.Add(prefs::kPrintingEnabled, this);
375 local_pref_registrar_.Add(prefs::kAllowFileSelectionDialogs, this); 88 local_pref_registrar_.Add(prefs::kAllowFileSelectionDialogs, this);
376 local_pref_registrar_.Add(prefs::kInManagedMode, this); 89 local_pref_registrar_.Add(prefs::kInManagedMode, this);
377 } 90 }
378 91
379 profile_pref_registrar_.Init(profile_->GetPrefs()); 92 profile_pref_registrar_.Init(profile()->GetPrefs());
380 profile_pref_registrar_.Add(prefs::kDevToolsDisabled, this); 93 profile_pref_registrar_.Add(prefs::kDevToolsDisabled, this);
381 profile_pref_registrar_.Add(prefs::kEditBookmarksEnabled, this); 94 profile_pref_registrar_.Add(prefs::kEditBookmarksEnabled, this);
382 profile_pref_registrar_.Add(prefs::kShowBookmarkBar, this); 95 profile_pref_registrar_.Add(prefs::kShowBookmarkBar, this);
383 profile_pref_registrar_.Add(prefs::kHomePage, this);
384 profile_pref_registrar_.Add(prefs::kInstantEnabled, this);
385 profile_pref_registrar_.Add(prefs::kIncognitoModeAvailability, this); 96 profile_pref_registrar_.Add(prefs::kIncognitoModeAvailability, this);
386 97
387 InitCommandState(); 98 InitCommandState();
388 BrowserList::AddBrowser(this);
389 99
390 // NOTE: These prefs all need to be explicitly destroyed in the destructor 100 TabRestoreService* tab_restore_service =
391 // or you'll get a nasty surprise when you run the incognito tests. 101 TabRestoreServiceFactory::GetForProfile(profile());
392 encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector, 102 if (tab_restore_service) {
393 profile_->GetPrefs(), NULL); 103 tab_restore_service->AddObserver(this);
394 104 TabRestoreServiceChanged(tab_restore_service);
395 tab_restore_service_ = TabRestoreServiceFactory::GetForProfile(profile);
396 if (tab_restore_service_) {
397 tab_restore_service_->AddObserver(this);
398 TabRestoreServiceChanged(tab_restore_service_);
399 } 105 }
400 106
401 ProfileSyncService* service = 107 ProfileSyncService* service =
402 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_); 108 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile());
403 if (service) 109 if (service)
404 service->AddObserver(this); 110 service->AddObserver(this);
405
406 CreateInstantIfNecessary();
407
408 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_INIT);
409
410 FilePath profile_path = profile->GetPath();
411 ProfileMetrics::LogProfileLaunch(profile_path);
412 } 111 }
413 112
414 Browser::~Browser() { 113 BrowserCommandController::~BrowserCommandController() {
415 ProfileSyncService* service = 114 ProfileSyncService* service =
416 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_); 115 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile());
417 if (service) 116 if (service)
418 service->RemoveObserver(this); 117 service->RemoveObserver(this);
419 118
420 // The tab strip should not have any tabs at this point.
421 if (!browser_shutdown::ShuttingDownWithoutClosingBrowsers())
422 DCHECK(tab_strip_model_->empty());
423 tab_strip_model_->RemoveObserver(this);
424
425 BrowserList::RemoveBrowser(this);
426
427 SessionService* session_service =
428 SessionServiceFactory::GetForProfile(profile_);
429 if (session_service)
430 session_service->WindowClosed(session_id_);
431
432 TabRestoreService* tab_restore_service = 119 TabRestoreService* tab_restore_service =
433 TabRestoreServiceFactory::GetForProfile(profile()); 120 TabRestoreServiceFactory::GetForProfile(profile());
434 if (tab_restore_service) 121 if (tab_restore_service)
435 tab_restore_service->BrowserClosed(tab_restore_service_delegate()); 122 tab_restore_service->RemoveObserver(this);
436
437 #if !defined(OS_MACOSX)
438 if (!browser::GetBrowserCount(profile_)) {
439 // We're the last browser window with this profile. We need to nuke the
440 // TabRestoreService, which will start the shutdown of the
441 // NavigationControllers and allow for proper shutdown. If we don't do this
442 // chrome won't shutdown cleanly, and may end up crashing when some
443 // thread tries to use the IO thread (or another thread) that is no longer
444 // valid.
445 // This isn't a valid assumption for Mac OS, as it stays running after
446 // the last browser has closed. The Mac equivalent is in its app
447 // controller.
448 TabRestoreServiceFactory::ResetForProfile(profile_);
449 }
450 #endif
451
452 profile_pref_registrar_.RemoveAll(); 123 profile_pref_registrar_.RemoveAll();
453 local_pref_registrar_.RemoveAll(); 124 local_pref_registrar_.RemoveAll();
454 125 browser_->tab_strip_model()->RemoveObserver(this);
455 encoding_auto_detect_.Destroy();
456
457 if (profile_->IsOffTheRecord() &&
458 !BrowserList::IsOffTheRecordSessionActiveForProfile(profile_)) {
459 // An incognito profile is no longer needed, this indirectly frees
460 // its cache and cookies once it gets destroyed at the appropriate time.
461 ProfileDestroyer::DestroyProfileWhenAppropriate(profile_);
462 }
463
464 // There may be pending file dialogs, we need to tell them that we've gone
465 // away so they don't try and call back to us.
466 if (select_file_dialog_.get())
467 select_file_dialog_->ListenerDestroyed();
468
469 TabRestoreServiceDestroyed(tab_restore_service_);
470 } 126 }
471 127
472 // static 128 bool BrowserCommandController::IsReservedCommandOrKey(
473 Browser* Browser::Create(Profile* profile) { 129 int command_id,
474 Browser* browser = new Browser(TYPE_TABBED, profile); 130 const content::NativeWebKeyboardEvent& event) {
475 browser->InitBrowserWindow();
476 return browser;
477 }
478
479 // static
480 Browser* Browser::CreateWithParams(const CreateParams& params) {
481 if (!params.app_name.empty())
482 chrome::RegisterAppPrefs(params.app_name, params.profile);
483
484 Browser* browser = new Browser(params.type, params.profile);
485 browser->app_name_ = params.app_name;
486 browser->app_type_ = params.app_type;
487 browser->set_override_bounds(params.initial_bounds);
488 browser->set_initial_show_state(params.initial_show_state);
489 browser->set_is_session_restore(params.is_session_restore);
490
491 browser->InitBrowserWindow();
492 return browser;
493 }
494
495 void Browser::InitBrowserWindow() {
496 DCHECK(!window_);
497
498 window_ = CreateBrowserWindow();
499 fullscreen_controller_ = new FullscreenController(window_, profile_, this);
500
501 #if defined(OS_WIN) && !defined(USE_AURA)
502 // Set the app user model id for this application to that of the application
503 // name. See http://crbug.com/7028.
504 ui::win::SetAppIdForWindow(
505 is_app() && !is_type_panel() ?
506 ShellIntegration::GetAppModelIdForProfile(UTF8ToWide(app_name_),
507 profile_->GetPath()) :
508 ShellIntegration::GetChromiumModelIdForProfile(profile_->GetPath()),
509 window()->GetNativeWindow());
510
511 if (is_type_panel()) {
512 ui::win::SetAppIconForWindow(ShellIntegration::GetChromiumIconPath(),
513 window()->GetNativeWindow());
514 }
515 #endif
516
517 // Create the extension window controller before sending notifications.
518 extension_window_controller_.reset(
519 new BrowserExtensionWindowController(this));
520
521 content::NotificationService::current()->Notify(
522 chrome::NOTIFICATION_BROWSER_WINDOW_READY,
523 content::Source<Browser>(this),
524 content::NotificationService::NoDetails());
525
526 PrefService* local_state = g_browser_process->local_state();
527 if (local_state && local_state->FindPreference(
528 prefs::kAutofillPersonalDataManagerFirstRun) &&
529 local_state->GetBoolean(prefs::kAutofillPersonalDataManagerFirstRun)) {
530 // Notify PDM that this is a first run.
531 #if defined(OS_WIN)
532 ImportAutofillDataWin(PersonalDataManagerFactory::GetForProfile(profile_));
533 #endif // defined(OS_WIN)
534 // Reset the preference so we don't call it again for subsequent windows.
535 local_state->ClearPref(prefs::kAutofillPersonalDataManagerFirstRun);
536 }
537 }
538
539 void Browser::SetWindowForTesting(BrowserWindow* window) {
540 DCHECK(!window_);
541 window_ = window;
542 fullscreen_controller_ = new FullscreenController(window_, profile_, this);
543 }
544
545 ///////////////////////////////////////////////////////////////////////////////
546 // Getters & Setters
547
548 FindBarController* Browser::GetFindBarController() {
549 if (!find_bar_controller_.get()) {
550 FindBar* find_bar = window_->CreateFindBar();
551 find_bar_controller_.reset(new FindBarController(find_bar));
552 find_bar->SetFindBarController(find_bar_controller_.get());
553 find_bar_controller_->ChangeTabContents(GetActiveTabContents());
554 find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true);
555 }
556 return find_bar_controller_.get();
557 }
558
559 bool Browser::HasFindBarController() const {
560 return find_bar_controller_.get() != NULL;
561 }
562
563 bool Browser::is_app() const {
564 return !app_name_.empty();
565 }
566
567 bool Browser::is_devtools() const {
568 return app_name_ == DevToolsWindow::kDevToolsApp;
569 }
570
571 ///////////////////////////////////////////////////////////////////////////////
572 // Browser, State Storage and Retrieval for UI:
573
574 SkBitmap Browser::GetCurrentPageIcon() const {
575 TabContents* contents = GetActiveTabContents();
576 // |contents| can be NULL since GetCurrentPageIcon() is called by the window
577 // during the window's creation (before tabs have been added).
578 return contents ? contents->favicon_tab_helper()->GetFavicon() : SkBitmap();
579 }
580
581 string16 Browser::GetWindowTitleForCurrentTab() const {
582 WebContents* contents = GetActiveWebContents();
583 string16 title;
584
585 // |contents| can be NULL because GetWindowTitleForCurrentTab is called by the
586 // window during the window's creation (before tabs have been added).
587 if (contents) {
588 title = contents->GetTitle();
589 FormatTitleForDisplay(&title);
590 }
591 if (title.empty())
592 title = CoreTabHelper::GetDefaultTitle();
593
594 #if defined(OS_MACOSX) || defined(USE_ASH)
595 // On Mac or Ash, we don't want to suffix the page title with
596 // the application name.
597 return title;
598 #else
599 int string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT;
600 // Don't append the app name to window titles on app frames and app popups
601 if (is_app())
602 string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT_NO_LOGO;
603 return l10n_util::GetStringFUTF16(string_id, title);
604 #endif
605 }
606
607 // static
608 void Browser::FormatTitleForDisplay(string16* title) {
609 size_t current_index = 0;
610 size_t match_index;
611 while ((match_index = title->find(L'\n', current_index)) != string16::npos) {
612 title->replace(match_index, 1, string16());
613 current_index = match_index;
614 }
615 }
616
617 ///////////////////////////////////////////////////////////////////////////////
618 // Browser, OnBeforeUnload handling:
619
620 bool Browser::ShouldCloseWindow() {
621 if (!CanCloseWithInProgressDownloads())
622 return false;
623
624 if (HasCompletedUnloadProcessing())
625 return true;
626
627 is_attempting_to_close_browser_ = true;
628
629 if (!TabsNeedBeforeUnloadFired())
630 return true;
631
632 ProcessPendingTabs();
633 return false;
634 }
635
636 void Browser::OnWindowClosing() {
637 if (!ShouldCloseWindow())
638 return;
639
640 bool exiting = false;
641
642 // Application should shutdown on last window close if the user is explicitly
643 // trying to quit, or if there is nothing keeping the browser alive (such as
644 // AppController on the Mac, or BackgroundContentsService for background
645 // pages).
646 bool should_quit_if_last_browser =
647 browser_shutdown::IsTryingToQuit() || !browser::WillKeepAlive();
648
649 if (should_quit_if_last_browser && BrowserList::size() == 1) {
650 browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE);
651 exiting = true;
652 }
653
654 // Don't use GetForProfileIfExisting here, we want to force creation of the
655 // session service so that user can restore what was open.
656 SessionService* session_service =
657 SessionServiceFactory::GetForProfile(profile());
658 if (session_service)
659 session_service->WindowClosing(session_id());
660
661 TabRestoreService* tab_restore_service =
662 TabRestoreServiceFactory::GetForProfile(profile());
663
664 #if defined(USE_AURA)
665 if (tab_restore_service && is_app())
666 tab_restore_service->BrowserClosing(tab_restore_service_delegate());
667 #endif
668
669 if (tab_restore_service && is_type_tabbed() && tab_count())
670 tab_restore_service->BrowserClosing(tab_restore_service_delegate());
671
672 // TODO(sky): convert session/tab restore to use notification.
673 content::NotificationService::current()->Notify(
674 chrome::NOTIFICATION_BROWSER_CLOSING,
675 content::Source<Browser>(this),
676 content::Details<bool>(&exiting));
677
678 CloseAllTabs();
679 }
680
681 void Browser::OnWindowActivated() {
682 // On some platforms we want to automatically reload tabs that are
683 // killed when the user selects them.
684 WebContents* contents = GetActiveWebContents();
685 if (contents && contents->GetCrashedStatus() ==
686 base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
687 if (CommandLine::ForCurrentProcess()->HasSwitch(
688 switches::kReloadKilledTabs)) {
689 chrome::Reload(this, CURRENT_TAB);
690 }
691 }
692 }
693
694 ////////////////////////////////////////////////////////////////////////////////
695 // In-progress download termination handling:
696
697 void Browser::InProgressDownloadResponse(bool cancel_downloads) {
698 if (cancel_downloads) {
699 cancel_download_confirmation_state_ = RESPONSE_RECEIVED;
700 chrome::CloseWindow(this);
701 return;
702 }
703
704 // Sets the confirmation state to NOT_PROMPTED so that if the user tries to
705 // close again we'll show the warning again.
706 cancel_download_confirmation_state_ = NOT_PROMPTED;
707
708 // Show the download page so the user can figure-out what downloads are still
709 // in-progress.
710 chrome::ShowDownloads(this);
711 }
712
713 Browser::DownloadClosePreventionType Browser::OkToCloseWithInProgressDownloads(
714 int* num_downloads_blocking) const {
715 DCHECK(num_downloads_blocking);
716 *num_downloads_blocking = 0;
717
718 if (is_attempting_to_close_browser_)
719 return DOWNLOAD_CLOSE_OK;
720
721 // If we're not running a full browser process with a profile manager
722 // (testing), it's ok to close the browser.
723 if (!g_browser_process->profile_manager())
724 return DOWNLOAD_CLOSE_OK;
725
726 int total_download_count = DownloadService::DownloadCountAllProfiles();
727 if (total_download_count == 0)
728 return DOWNLOAD_CLOSE_OK; // No downloads; can definitely close.
729
730 // Figure out how many windows are open total, and associated with this
731 // profile, that are relevant for the ok-to-close decision.
732 int profile_window_count = 0;
733 int total_window_count = 0;
734 for (BrowserList::const_iterator iter = BrowserList::begin();
735 iter != BrowserList::end(); ++iter) {
736 // Don't count this browser window or any other in the process of closing.
737 Browser* const browser = *iter;
738 // Check is_attempting_to_close_browser_ as window closing may be
739 // delayed, and windows that are in the process of closing don't
740 // count against our totals.
741 if (browser == this || browser->is_attempting_to_close_browser_)
742 continue;
743
744 if ((*iter)->profile() == profile())
745 profile_window_count++;
746 total_window_count++;
747 }
748
749 // If there aren't any other windows, we're at browser shutdown,
750 // which would cancel all current downloads.
751 if (total_window_count == 0) {
752 *num_downloads_blocking = total_download_count;
753 return DOWNLOAD_CLOSE_BROWSER_SHUTDOWN;
754 }
755
756 // If there aren't any other windows on our profile, and we're an incognito
757 // profile, and there are downloads associated with that profile,
758 // those downloads would be cancelled by our window (-> profile) close.
759 DownloadService* download_service =
760 DownloadServiceFactory::GetForProfile(profile());
761 if (profile_window_count == 0 && download_service->DownloadCount() > 0 &&
762 profile()->IsOffTheRecord()) {
763 *num_downloads_blocking = download_service->DownloadCount();
764 return DOWNLOAD_CLOSE_LAST_WINDOW_IN_INCOGNITO_PROFILE;
765 }
766
767 // Those are the only conditions under which we will block shutdown.
768 return DOWNLOAD_CLOSE_OK;
769 }
770
771 ////////////////////////////////////////////////////////////////////////////////
772 // Browser, TabStripModel pass-thrus:
773
774 int Browser::tab_count() const {
775 return tab_strip_model_->count();
776 }
777
778 int Browser::active_index() const {
779 return tab_strip_model_->active_index();
780 }
781
782 int Browser::GetIndexOfController(
783 const NavigationController* controller) const {
784 return tab_strip_model_->GetIndexOfController(controller);
785 }
786
787 TabContents* Browser::GetActiveTabContents() const {
788 return tab_strip_model_->GetActiveTabContents();
789 }
790
791 WebContents* Browser::GetActiveWebContents() const {
792 TabContents* tab_contents = GetActiveTabContents();
793 return tab_contents ? tab_contents->web_contents() : NULL;
794 }
795
796 TabContents* Browser::GetTabContentsAt(int index) const {
797 return tab_strip_model_->GetTabContentsAt(index);
798 }
799
800 WebContents* Browser::GetWebContentsAt(int index) const {
801 TabContents* tab_contents = GetTabContentsAt(index);
802 if (tab_contents)
803 return tab_contents->web_contents();
804 return NULL;
805 }
806
807 void Browser::ActivateTabAt(int index, bool user_gesture) {
808 tab_strip_model_->ActivateTabAt(index, user_gesture);
809 }
810
811 bool Browser::IsTabPinned(int index) const {
812 return tab_strip_model_->IsTabPinned(index);
813 }
814
815 bool Browser::IsTabDiscarded(int index) const {
816 return tab_strip_model_->IsTabDiscarded(index);
817 }
818
819 void Browser::CloseAllTabs() {
820 tab_strip_model_->CloseAllTabs();
821 }
822
823 ////////////////////////////////////////////////////////////////////////////////
824 // Browser, Tab adding/showing functions:
825
826 bool Browser::IsTabStripEditable() const {
827 return window()->IsTabStripEditable();
828 }
829
830 int Browser::GetIndexForInsertionDuringRestore(int relative_index) {
831 return (tab_strip_model_->insertion_policy() == TabStripModel::INSERT_AFTER) ?
832 tab_count() : relative_index;
833 }
834
835 TabContents* Browser::AddSelectedTabWithURL(
836 const GURL& url,
837 content::PageTransition transition) {
838 browser::NavigateParams params(this, url, transition);
839 params.disposition = NEW_FOREGROUND_TAB;
840 browser::Navigate(&params);
841 return params.target_contents;
842 }
843
844 WebContents* Browser::AddTab(TabContents* tab_contents,
845 content::PageTransition type) {
846 tab_strip_model_->AddTabContents(tab_contents, -1, type,
847 TabStripModel::ADD_ACTIVE);
848 return tab_contents->web_contents();
849 }
850
851 WebContents* Browser::AddRestoredTab(
852 const std::vector<TabNavigation>& navigations,
853 int tab_index,
854 int selected_navigation,
855 const std::string& extension_app_id,
856 bool select,
857 bool pin,
858 bool from_last_session,
859 content::SessionStorageNamespace* session_storage_namespace) {
860 GURL restore_url = navigations.at(selected_navigation).virtual_url();
861 TabContents* tab_contents = TabContentsFactory(
862 profile(),
863 tab_util::GetSiteInstanceForNewTab(profile_, restore_url),
864 MSG_ROUTING_NONE,
865 GetActiveWebContents(),
866 session_storage_namespace);
867 WebContents* new_tab = tab_contents->web_contents();
868 tab_contents->extension_tab_helper()->SetExtensionAppById(extension_app_id);
869 std::vector<NavigationEntry*> entries;
870 TabNavigation::CreateNavigationEntriesFromTabNavigations(
871 profile_, navigations, &entries);
872 new_tab->GetController().Restore(
873 selected_navigation, from_last_session, &entries);
874 DCHECK_EQ(0u, entries.size());
875
876 int add_types = select ? TabStripModel::ADD_ACTIVE :
877 TabStripModel::ADD_NONE;
878 if (pin) {
879 int first_mini_tab_idx = tab_strip_model_->IndexOfFirstNonMiniTab();
880 tab_index = std::min(tab_index, first_mini_tab_idx);
881 add_types |= TabStripModel::ADD_PINNED;
882 }
883 tab_strip_model_->InsertTabContentsAt(tab_index, tab_contents, add_types);
884 if (select) {
885 window_->Activate();
886 } else {
887 // We set the size of the view here, before WebKit does its initial
888 // layout. If we don't, the initial layout of background tabs will be
889 // performed with a view width of 0, which may cause script outputs and
890 // anchor link location calculations to be incorrect even after a new
891 // layout with proper view dimensions. TabStripModel::AddTabContents()
892 // contains similar logic.
893 new_tab->GetView()->SizeContents(window_->GetRestoredBounds().size());
894 new_tab->WasHidden();
895 }
896 SessionService* session_service =
897 SessionServiceFactory::GetForProfileIfExisting(profile_);
898 if (session_service)
899 session_service->TabRestored(tab_contents, pin);
900 return new_tab;
901 }
902
903 void Browser::AddWebContents(WebContents* new_contents,
904 WindowOpenDisposition disposition,
905 const gfx::Rect& initial_pos,
906 bool user_gesture) {
907 AddNewContents(NULL, new_contents, disposition, initial_pos, user_gesture);
908 }
909
910 void Browser::CloseTabContents(WebContents* contents) {
911 CloseContents(contents);
912 }
913
914 void Browser::ReplaceRestoredTab(
915 const std::vector<TabNavigation>& navigations,
916 int selected_navigation,
917 bool from_last_session,
918 const std::string& extension_app_id,
919 content::SessionStorageNamespace* session_storage_namespace) {
920 GURL restore_url = navigations.at(selected_navigation).virtual_url();
921 TabContents* tab_contents = TabContentsFactory(
922 profile(),
923 tab_util::GetSiteInstanceForNewTab(profile_, restore_url),
924 MSG_ROUTING_NONE,
925 GetActiveWebContents(),
926 session_storage_namespace);
927 tab_contents->extension_tab_helper()->SetExtensionAppById(extension_app_id);
928 WebContents* replacement = tab_contents->web_contents();
929 std::vector<NavigationEntry*> entries;
930 TabNavigation::CreateNavigationEntriesFromTabNavigations(
931 profile_, navigations, &entries);
932 replacement->GetController().Restore(
933 selected_navigation, from_last_session, &entries);
934 DCHECK_EQ(0u, entries.size());
935
936 tab_strip_model_->ReplaceNavigationControllerAt(active_index(), tab_contents);
937 }
938
939 void Browser::WindowFullscreenStateChanged() {
940 fullscreen_controller_->WindowFullscreenStateChanged();
941 FullScreenMode fullscreen_mode = FULLSCREEN_DISABLED;
942 if (window_->IsFullscreen()) {
943 #if defined(OS_WIN)
944 fullscreen_mode = window_->IsInMetroSnapMode() ? FULLSCREEN_METRO_SNAP :
945 FULLSCREEN_NORMAL;
946 #else
947 fullscreen_mode = FULLSCREEN_NORMAL;
948 #endif
949 }
950 UpdateCommandsForFullscreenMode(fullscreen_mode);
951 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TOGGLE_FULLSCREEN);
952 }
953
954 ///////////////////////////////////////////////////////////////////////////////
955 // Browser, Assorted browser commands:
956
957 void Browser::ToggleFullscreenMode() {
958 fullscreen_controller_->ToggleFullscreenMode();
959 }
960
961 void Browser::ToggleFullscreenModeWithExtension(const GURL& extension_url) {
962 fullscreen_controller_->ToggleFullscreenModeWithExtension(extension_url);
963 }
964
965 #if defined(OS_MACOSX)
966 void Browser::TogglePresentationMode() {
967 fullscreen_controller_->TogglePresentationMode();
968 }
969 #endif
970
971 bool Browser::SupportsWindowFeature(WindowFeature feature) const {
972 return SupportsWindowFeatureImpl(feature, true);
973 }
974
975 bool Browser::CanSupportWindowFeature(WindowFeature feature) const {
976 return SupportsWindowFeatureImpl(feature, false);
977 }
978
979 void Browser::ToggleEncodingAutoDetect() {
980 content::RecordAction(UserMetricsAction("AutoDetectChange"));
981 encoding_auto_detect_.SetValue(!encoding_auto_detect_.GetValue());
982 // If "auto detect" is turned on, then any current override encoding
983 // is cleared. This also implicitly performs a reload.
984 // OTOH, if "auto detect" is turned off, we don't change the currently
985 // active encoding.
986 if (encoding_auto_detect_.GetValue()) {
987 WebContents* contents = GetActiveWebContents();
988 if (contents)
989 contents->ResetOverrideEncoding();
990 }
991 }
992
993 void Browser::OverrideEncoding(int encoding_id) {
994 content::RecordAction(UserMetricsAction("OverrideEncoding"));
995 const std::string selected_encoding =
996 CharacterEncoding::GetCanonicalEncodingNameByCommandId(encoding_id);
997 WebContents* contents = GetActiveWebContents();
998 if (!selected_encoding.empty() && contents)
999 contents->SetOverrideEncoding(selected_encoding);
1000 // Update the list of recently selected encodings.
1001 std::string new_selected_encoding_list;
1002 if (CharacterEncoding::UpdateRecentlySelectedEncoding(
1003 profile_->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding),
1004 encoding_id,
1005 &new_selected_encoding_list)) {
1006 profile_->GetPrefs()->SetString(prefs::kRecentlySelectedEncoding,
1007 new_selected_encoding_list);
1008 }
1009 }
1010
1011 void Browser::OpenFile() {
1012 content::RecordAction(UserMetricsAction("OpenFile"));
1013 if (!select_file_dialog_.get())
1014 select_file_dialog_ = SelectFileDialog::Create(this);
1015
1016 const FilePath directory = profile_->last_selected_directory();
1017
1018 // TODO(beng): figure out how to juggle this.
1019 gfx::NativeWindow parent_window = window_->GetNativeWindow();
1020 select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE,
1021 string16(), directory,
1022 NULL, 0, FILE_PATH_LITERAL(""),
1023 GetActiveWebContents(),
1024 parent_window, NULL);
1025 }
1026
1027 void Browser::OpenCreateShortcutsDialog() {
1028 content::RecordAction(UserMetricsAction("CreateShortcut"));
1029 #if !defined(OS_MACOSX)
1030 TabContents* current_tab = GetActiveTabContents();
1031 DCHECK(current_tab &&
1032 web_app::IsValidUrl(current_tab->web_contents()->GetURL())) <<
1033 "Menu item should be disabled.";
1034
1035 NavigationEntry* entry =
1036 current_tab->web_contents()->GetController().GetLastCommittedEntry();
1037 if (!entry)
1038 return;
1039
1040 // RVH's GetApplicationInfo should not be called before it returns.
1041 DCHECK(pending_web_app_action_ == NONE);
1042 pending_web_app_action_ = CREATE_SHORTCUT;
1043
1044 // Start fetching web app info for CreateApplicationShortcut dialog and show
1045 // the dialog when the data is available in OnDidGetApplicationInfo.
1046 current_tab->extension_tab_helper()->GetApplicationInfo(entry->GetPageID());
1047 #else
1048 NOTIMPLEMENTED();
1049 #endif
1050 }
1051
1052 void Browser::UpdateDownloadShelfVisibility(bool visible) {
1053 if (GetStatusBubble())
1054 GetStatusBubble()->UpdateDownloadShelfVisibility(visible);
1055 }
1056
1057 bool Browser::OpenInstant(WindowOpenDisposition disposition) {
1058 if (!instant() || !instant()->PrepareForCommit() ||
1059 disposition == NEW_BACKGROUND_TAB) {
1060 // NEW_BACKGROUND_TAB results in leaving the omnibox open, so we don't
1061 // attempt to use the instant preview.
1062 return false;
1063 }
1064
1065 if (disposition == CURRENT_TAB) {
1066 content::NotificationService::current()->Notify(
1067 chrome::NOTIFICATION_INSTANT_COMMITTED,
1068 content::Source<TabContents>(instant()->CommitCurrentPreview(
1069 INSTANT_COMMIT_PRESSED_ENTER)),
1070 content::NotificationService::NoDetails());
1071 return true;
1072 }
1073 if (disposition == NEW_FOREGROUND_TAB) {
1074 TabContents* preview_contents = instant()->ReleasePreviewContents(
1075 INSTANT_COMMIT_PRESSED_ENTER, NULL);
1076 // HideInstant is invoked after release so that InstantController is not
1077 // active when HideInstant asks it for its state.
1078 HideInstant();
1079 preview_contents->web_contents()->GetController().PruneAllButActive();
1080 tab_strip_model_->AddTabContents(
1081 preview_contents,
1082 -1,
1083 instant()->last_transition_type(),
1084 TabStripModel::ADD_ACTIVE);
1085 instant()->CompleteRelease(preview_contents);
1086 content::NotificationService::current()->Notify(
1087 chrome::NOTIFICATION_INSTANT_COMMITTED,
1088 content::Source<TabContents>(preview_contents),
1089 content::NotificationService::NoDetails());
1090 return true;
1091 }
1092 // The omnibox currently doesn't use other dispositions, so we don't attempt
1093 // to handle them. If you hit this NOTREACHED file a bug and I'll (sky) add
1094 // support for the new disposition.
1095 NOTREACHED();
1096 return false;
1097 }
1098
1099 ///////////////////////////////////////////////////////////////////////////////
1100
1101 // static
1102 bool Browser::RunUnloadEventsHelper(WebContents* contents) {
1103 // If the WebContents is not connected yet, then there's no unload
1104 // handler we can fire even if the WebContents has an unload listener.
1105 // One case where we hit this is in a tab that has an infinite loop
1106 // before load.
1107 if (contents->NeedToFireBeforeUnload()) {
1108 // If the page has unload listeners, then we tell the renderer to fire
1109 // them. Once they have fired, we'll get a message back saying whether
1110 // to proceed closing the page or not, which sends us back to this method
1111 // with the NeedToFireBeforeUnload bit cleared.
1112 contents->GetRenderViewHost()->FirePageBeforeUnload(false);
1113 return true;
1114 }
1115 return false;
1116 }
1117
1118 // static
1119 void Browser::JSOutOfMemoryHelper(WebContents* web_contents) {
1120 TabContents* tab_contents = TabContents::FromWebContents(web_contents);
1121 if (!tab_contents)
1122 return;
1123
1124 InfoBarTabHelper* infobar_helper = tab_contents->infobar_tab_helper();
1125 infobar_helper->AddInfoBar(new SimpleAlertInfoBarDelegate(
1126 infobar_helper,
1127 NULL,
1128 l10n_util::GetStringUTF16(IDS_JS_OUT_OF_MEMORY_PROMPT),
1129 true));
1130 }
1131
1132 // static
1133 void Browser::RegisterProtocolHandlerHelper(WebContents* web_contents,
1134 const std::string& protocol,
1135 const GURL& url,
1136 const string16& title,
1137 bool user_gesture) {
1138 TabContents* tab_contents = TabContents::FromWebContents(web_contents);
1139 if (!tab_contents || tab_contents->profile()->IsOffTheRecord())
1140 return;
1141
1142 ProtocolHandler handler =
1143 ProtocolHandler::CreateProtocolHandler(protocol, url, title);
1144
1145 ProtocolHandlerRegistry* registry =
1146 tab_contents->profile()->GetProtocolHandlerRegistry();
1147
1148 if (!registry->SilentlyHandleRegisterHandlerRequest(handler)) {
1149 content::RecordAction(
1150 UserMetricsAction("RegisterProtocolHandler.InfoBar_Shown"));
1151 InfoBarTabHelper* infobar_helper = tab_contents->infobar_tab_helper();
1152
1153 RegisterProtocolHandlerInfoBarDelegate* rph_delegate =
1154 new RegisterProtocolHandlerInfoBarDelegate(infobar_helper,
1155 registry,
1156 handler);
1157
1158 for (size_t i = 0; i < infobar_helper->infobar_count(); i++) {
1159 InfoBarDelegate* delegate = infobar_helper->GetInfoBarDelegateAt(i);
1160 RegisterProtocolHandlerInfoBarDelegate* cast_delegate =
1161 delegate->AsRegisterProtocolHandlerInfoBarDelegate();
1162 if (cast_delegate != NULL && cast_delegate->IsReplacedBy(rph_delegate)) {
1163 infobar_helper->ReplaceInfoBar(cast_delegate, rph_delegate);
1164 rph_delegate = NULL;
1165 break;
1166 }
1167 }
1168
1169 if (rph_delegate != NULL)
1170 infobar_helper->AddInfoBar(rph_delegate);
1171 }
1172 }
1173
1174 // static
1175 void Browser::FindReplyHelper(WebContents* web_contents,
1176 int request_id,
1177 int number_of_matches,
1178 const gfx::Rect& selection_rect,
1179 int active_match_ordinal,
1180 bool final_update) {
1181 TabContents* tab_contents = TabContents::FromWebContents(web_contents);
1182 if (!tab_contents || !tab_contents->find_tab_helper())
1183 return;
1184
1185 tab_contents->find_tab_helper()->HandleFindReply(request_id,
1186 number_of_matches,
1187 selection_rect,
1188 active_match_ordinal,
1189 final_update);
1190 }
1191
1192 void Browser::ExecuteCommand(int id) {
1193 ExecuteCommandWithDisposition(id, CURRENT_TAB);
1194 }
1195
1196 void Browser::ExecuteCommand(int id, int event_flags) {
1197 ExecuteCommandWithDisposition(
1198 id, browser::DispositionFromEventFlags(event_flags));
1199 }
1200
1201 bool Browser::ExecuteCommandIfEnabled(int id) {
1202 if (command_updater_.SupportsCommand(id) &&
1203 command_updater_.IsCommandEnabled(id)) {
1204 ExecuteCommand(id);
1205 return true;
1206 }
1207 return false;
1208 }
1209
1210 bool Browser::IsReservedCommandOrKey(int command_id,
1211 const NativeWebKeyboardEvent& event) {
1212 // In Apps mode, no keys are reserved. 131 // In Apps mode, no keys are reserved.
1213 if (is_app()) 132 if (browser_->is_app())
1214 return false; 133 return false;
1215 134
1216 #if defined(OS_CHROMEOS) 135 #if defined(OS_CHROMEOS)
1217 // Chrome OS's top row of keys produces F1-10. Make sure that web pages 136 // Chrome OS's top row of keys produces F1-10. Make sure that web pages
1218 // aren't able to block Chrome from performing the standard actions for F1-F4. 137 // aren't able to block Chrome from performing the standard actions for F1-F4.
1219 // We should not handle F5-10 here since they are processed by Ash. See also: 138 // We should not handle F5-10 here since they are processed by Ash. See also:
1220 // crbug.com/127333#c8 139 // crbug.com/127333#c8
1221 ui::KeyboardCode key_code = 140 ui::KeyboardCode key_code =
1222 static_cast<ui::KeyboardCode>(event.windowsKeyCode); 141 static_cast<ui::KeyboardCode>(event.windowsKeyCode);
1223 if ((key_code == ui::VKEY_F1 || 142 if ((key_code == ui::VKEY_F1 ||
1224 key_code == ui::VKEY_F2 || 143 key_code == ui::VKEY_F2 ||
1225 key_code == ui::VKEY_F3 || 144 key_code == ui::VKEY_F3 ||
1226 key_code == ui::VKEY_F4) && 145 key_code == ui::VKEY_F4) &&
1227 // Make sure it's a browser shortcut (i.e. not an Ash one like Alt+F4). 146 // Make sure it's a browser shortcut (i.e. not an Ash one like Alt+F4).
1228 command_id != -1) { 147 command_id != -1) {
1229 return true; 148 return true;
1230 } 149 }
1231 #endif 150 #endif
1232 151
1233 if (window_->IsFullscreen() && command_id == IDC_FULLSCREEN) 152 if (window()->IsFullscreen() && command_id == IDC_FULLSCREEN)
1234 return true; 153 return true;
1235 return command_id == IDC_CLOSE_TAB || 154 return command_id == IDC_CLOSE_TAB ||
1236 command_id == IDC_CLOSE_WINDOW || 155 command_id == IDC_CLOSE_WINDOW ||
1237 command_id == IDC_NEW_INCOGNITO_WINDOW || 156 command_id == IDC_NEW_INCOGNITO_WINDOW ||
1238 command_id == IDC_NEW_TAB || 157 command_id == IDC_NEW_TAB ||
1239 command_id == IDC_NEW_WINDOW || 158 command_id == IDC_NEW_WINDOW ||
1240 command_id == IDC_RESTORE_TAB || 159 command_id == IDC_RESTORE_TAB ||
1241 command_id == IDC_SELECT_NEXT_TAB || 160 command_id == IDC_SELECT_NEXT_TAB ||
1242 command_id == IDC_SELECT_PREVIOUS_TAB || 161 command_id == IDC_SELECT_PREVIOUS_TAB ||
1243 command_id == IDC_TABPOSE || 162 command_id == IDC_TABPOSE ||
1244 command_id == IDC_EXIT || 163 command_id == IDC_EXIT ||
1245 command_id == IDC_SEARCH; 164 command_id == IDC_SEARCH;
1246 } 165 }
1247 166
1248 void Browser::SetBlockCommandExecution(bool block) { 167 void BrowserCommandController::SetBlockCommandExecution(bool block) {
1249 block_command_execution_ = block; 168 block_command_execution_ = block;
1250 if (block) { 169 if (block) {
1251 last_blocked_command_id_ = -1; 170 last_blocked_command_id_ = -1;
1252 last_blocked_command_disposition_ = CURRENT_TAB; 171 last_blocked_command_disposition_ = CURRENT_TAB;
1253 } 172 }
1254 } 173 }
1255 174
1256 int Browser::GetLastBlockedCommand(WindowOpenDisposition* disposition) { 175 int BrowserCommandController::GetLastBlockedCommand(
176 WindowOpenDisposition* disposition) {
1257 if (disposition) 177 if (disposition)
1258 *disposition = last_blocked_command_disposition_; 178 *disposition = last_blocked_command_disposition_;
1259 return last_blocked_command_id_; 179 return last_blocked_command_id_;
1260 } 180 }
1261 181
1262 void Browser::UpdateUIForNavigationInTab(TabContents* contents, 182 void BrowserCommandController::TabStateChanged() {
1263 content::PageTransition transition, 183 UpdateCommandsForTabState();
1264 bool user_initiated) {
1265 tab_strip_model_->TabNavigating(contents, transition);
1266
1267 bool contents_is_selected = contents == GetActiveTabContents();
1268 if (user_initiated && contents_is_selected && window()->GetLocationBar()) {
1269 // Forcibly reset the location bar if the url is going to change in the
1270 // current tab, since otherwise it won't discard any ongoing user edits,
1271 // since it doesn't realize this is a user-initiated action.
1272 window()->GetLocationBar()->Revert();
1273 }
1274
1275 if (GetStatusBubble())
1276 GetStatusBubble()->Hide();
1277
1278 // Update the location bar. This is synchronous. We specifically don't
1279 // update the load state since the load hasn't started yet and updating it
1280 // will put it out of sync with the actual state like whether we're
1281 // displaying a favicon, which controls the throbber. If we updated it here,
1282 // the throbber will show the default favicon for a split second when
1283 // navigating away from the new tab page.
1284 ScheduleUIUpdate(contents->web_contents(), content::INVALIDATE_TYPE_URL);
1285
1286 if (contents_is_selected)
1287 contents->web_contents()->Focus();
1288 } 184 }
1289 185
1290 /////////////////////////////////////////////////////////////////////////////// 186 void BrowserCommandController::ContentRestrictionsChanged() {
1291 // Browser, PageNavigator implementation: 187 UpdateCommandsForContentRestrictionState();
1292
1293 WebContents* Browser::OpenURL(const OpenURLParams& params) {
1294 return OpenURLFromTab(NULL, params);
1295 } 188 }
1296 189
1297 /////////////////////////////////////////////////////////////////////////////// 190 void BrowserCommandController::FullscreenStateChanged() {
1298 // Browser, CommandUpdater::CommandUpdaterDelegate implementation: 191 FullScreenMode fullscreen_mode = FULLSCREEN_DISABLED;
192 if (window()->IsFullscreen()) {
193 #if defined(OS_WIN)
194 fullscreen_mode = window()->IsInMetroSnapMode() ? FULLSCREEN_METRO_SNAP :
195 FULLSCREEN_NORMAL;
196 #else
197 fullscreen_mode = FULLSCREEN_NORMAL;
198 #endif
199 }
200 UpdateCommandsForFullscreenMode(fullscreen_mode);
201 }
1299 202
1300 void Browser::ExecuteCommandWithDisposition( 203 void BrowserCommandController::PrintingStateChanged() {
204 UpdatePrintingState();
205 }
206
207 void BrowserCommandController::LoadingStateChanged(bool is_loading,
208 bool force) {
209 UpdateReloadStopState(is_loading, force);
210 }
211
212 void BrowserCommandController::SendToMobileStateChanged(
213 bool send_to_mobile_available) {
214 command_updater_.UpdateCommandEnabled(IDC_CHROME_TO_MOBILE_PAGE,
215 send_to_mobile_available);
216 }
217
218 ////////////////////////////////////////////////////////////////////////////////
219 // BrowserCommandController,
220 // CommandUpdater::CommandUpdaterDelegate implementation:
221
222 void BrowserCommandController::ExecuteCommandWithDisposition(
1301 int id, WindowOpenDisposition disposition) { 223 int id, WindowOpenDisposition disposition) {
1302 // No commands are enabled if there is not yet any selected tab. 224 // No commands are enabled if there is not yet any selected tab.
1303 // TODO(pkasting): It seems like we should not need this, because either 225 // TODO(pkasting): It seems like we should not need this, because either
1304 // most/all commands should not have been enabled yet anyway or the ones that 226 // most/all commands should not have been enabled yet anyway or the ones that
1305 // are enabled should be global, or safe themselves against having no selected 227 // are enabled should be global, or safe themselves against having no selected
1306 // tab. However, Ben says he tried removing this before and got lots of 228 // tab. However, Ben says he tried removing this before and got lots of
1307 // crashes, e.g. from Windows sending WM_COMMANDs at random times during 229 // crashes, e.g. from Windows sending WM_COMMANDs at random times during
1308 // window construction. This probably could use closer examination someday. 230 // window construction. This probably could use closer examination someday.
1309 if (!GetActiveTabContents()) 231 if (!browser_->GetActiveTabContents())
1310 return; 232 return;
1311 233
1312 DCHECK(command_updater_.IsCommandEnabled(id)) << "Invalid/disabled command " 234 DCHECK(command_updater_.IsCommandEnabled(id)) << "Invalid/disabled command "
1313 << id; 235 << id;
1314 236
1315 // If command execution is blocked then just record the command and return. 237 // If command execution is blocked then just record the command and return.
1316 if (block_command_execution_) { 238 if (block_command_execution_) {
1317 // We actually only allow no more than one blocked command, otherwise some 239 // We actually only allow no more than one blocked command, otherwise some
1318 // commands maybe lost. 240 // commands maybe lost.
1319 DCHECK_EQ(last_blocked_command_id_, -1); 241 DCHECK_EQ(last_blocked_command_id_, -1);
1320 last_blocked_command_id_ = id; 242 last_blocked_command_id_ = id;
1321 last_blocked_command_disposition_ = disposition; 243 last_blocked_command_disposition_ = disposition;
1322 return; 244 return;
1323 } 245 }
1324 246
1325 // The order of commands in this switch statement must match the function 247 // The order of commands in this switch statement must match the function
1326 // declaration order in browser.h! 248 // declaration order in browser.h!
1327 switch (id) { 249 switch (id) {
1328 // Navigation commands 250 // Navigation commands
1329 case IDC_BACK: chrome::GoBack(this, disposition);break; 251 case IDC_BACK:
252 GoBack(browser_, disposition);
253 break;
1330 case IDC_FORWARD: 254 case IDC_FORWARD:
1331 chrome::GoForward(this, disposition); 255 GoForward(browser_, disposition);
1332 break; 256 break;
1333 case IDC_RELOAD: chrome::Reload(this, disposition);break; 257 case IDC_RELOAD:
258 Reload(browser_, disposition);
259 break;
1334 case IDC_RELOAD_IGNORING_CACHE: 260 case IDC_RELOAD_IGNORING_CACHE:
1335 chrome::ReloadIgnoringCache(this, disposition); 261 ReloadIgnoringCache(browser_, disposition);
1336 break; 262 break;
1337 case IDC_HOME: chrome::Home(this, disposition); break; 263 case IDC_HOME:
1338 case IDC_OPEN_CURRENT_URL: chrome::OpenCurrentURL(this); break; 264 Home(browser_, disposition);
1339 case IDC_STOP: chrome::Stop(this); break; 265 break;
266 case IDC_OPEN_CURRENT_URL:
267 OpenCurrentURL(browser_);
268 break;
269 case IDC_STOP:
270 Stop(browser_);
271 break;
1340 272
1341 // Window management commands 273 // Window management commands
1342 case IDC_NEW_WINDOW: chrome::NewWindow(this); break; 274 case IDC_NEW_WINDOW:
1343 case IDC_NEW_INCOGNITO_WINDOW: chrome::NewIncognitoWindow(this); break; 275 NewWindow(browser_);
1344 case IDC_CLOSE_WINDOW: chrome::CloseWindow(this); break; 276 break;
1345 case IDC_NEW_TAB: chrome::NewTab(this); break; 277 case IDC_NEW_INCOGNITO_WINDOW:
1346 case IDC_CLOSE_TAB: chrome::CloseTab(this); break; 278 NewIncognitoWindow(browser_);
1347 case IDC_SELECT_NEXT_TAB: chrome::SelectNextTab(this); break; 279 break;
1348 case IDC_SELECT_PREVIOUS_TAB: chrome::SelectPreviousTab(this); break; 280 case IDC_CLOSE_WINDOW:
1349 case IDC_TABPOSE: chrome::OpenTabpose(this); break; 281 CloseWindow(browser_);
1350 case IDC_MOVE_TAB_NEXT: chrome::MoveTabNext(this); break; 282 break;
1351 case IDC_MOVE_TAB_PREVIOUS: chrome::MoveTabPrevious(this); break; 283 case IDC_NEW_TAB:
284 NewTab(browser_);
285 break;
286 case IDC_CLOSE_TAB:
287 CloseTab(browser_);
288 break;
289 case IDC_SELECT_NEXT_TAB:
290 SelectNextTab(browser_);
291 break;
292 case IDC_SELECT_PREVIOUS_TAB:
293 SelectPreviousTab(browser_);
294 break;
295 case IDC_TABPOSE:
296 OpenTabpose(browser_);
297 break;
298 case IDC_MOVE_TAB_NEXT:
299 MoveTabNext(browser_);
300 break;
301 case IDC_MOVE_TAB_PREVIOUS:
302 MoveTabPrevious(browser_);
303 break;
1352 case IDC_SELECT_TAB_0: 304 case IDC_SELECT_TAB_0:
1353 case IDC_SELECT_TAB_1: 305 case IDC_SELECT_TAB_1:
1354 case IDC_SELECT_TAB_2: 306 case IDC_SELECT_TAB_2:
1355 case IDC_SELECT_TAB_3: 307 case IDC_SELECT_TAB_3:
1356 case IDC_SELECT_TAB_4: 308 case IDC_SELECT_TAB_4:
1357 case IDC_SELECT_TAB_5: 309 case IDC_SELECT_TAB_5:
1358 case IDC_SELECT_TAB_6: 310 case IDC_SELECT_TAB_6:
1359 case IDC_SELECT_TAB_7: 311 case IDC_SELECT_TAB_7:
1360 chrome::SelectNumberedTab(this, id - IDC_SELECT_TAB_0); 312 SelectNumberedTab(browser_, id - IDC_SELECT_TAB_0);
1361 break; 313 break;
1362 case IDC_SELECT_LAST_TAB: chrome::SelectLastTab(this); break; 314 case IDC_SELECT_LAST_TAB:
1363 case IDC_DUPLICATE_TAB: chrome::DuplicateTab(this); break; 315 SelectLastTab(browser_);
1364 case IDC_RESTORE_TAB: RestoreTab(); break; 316 break;
317 case IDC_DUPLICATE_TAB:
318 DuplicateTab(browser_);
319 break;
320 case IDC_RESTORE_TAB:
321 RestoreTab(browser_);
322 break;
1365 case IDC_COPY_URL: 323 case IDC_COPY_URL:
1366 chrome::WriteCurrentURLToClipboard(this); 324 WriteCurrentURLToClipboard(browser_);
1367 break; 325 break;
1368 case IDC_SHOW_AS_TAB: 326 case IDC_SHOW_AS_TAB:
1369 chrome::ConvertPopupToTabbedBrowser(this); 327 ConvertPopupToTabbedBrowser(browser_);
1370 break; 328 break;
1371 case IDC_FULLSCREEN: ToggleFullscreenMode(); break; 329 case IDC_FULLSCREEN:
330 browser_->ToggleFullscreenMode();
331 break;
1372 #if defined(OS_WIN) 332 #if defined(OS_WIN)
1373 case IDC_METRO_SNAP_ENABLE: SetMetroSnapMode(true); break; 333 case IDC_METRO_SNAP_ENABLE:
1374 case IDC_METRO_SNAP_DISABLE: SetMetroSnapMode(false); break; 334 browser_->SetMetroSnapMode(true);
335 break;
336 case IDC_METRO_SNAP_DISABLE:
337 browser_->SetMetroSnapMode(false);
338 break;
1375 #endif 339 #endif
1376 #if defined(OS_MACOSX) 340 #if defined(OS_MACOSX)
1377 case IDC_PRESENTATION_MODE: TogglePresentationMode(); break; 341 case IDC_PRESENTATION_MODE:
342 browser_->TogglePresentationMode();
343 break;
1378 #endif 344 #endif
1379 case IDC_EXIT: chrome::Exit(); break; 345 case IDC_EXIT:
346 Exit();
347 break;
1380 348
1381 // Page-related commands 349 // Page-related commands
1382 case IDC_SAVE_PAGE: chrome::SavePage(this); break; 350 case IDC_SAVE_PAGE:
1383 case IDC_BOOKMARK_PAGE: chrome::BookmarkCurrentPage(this);break; 351 SavePage(browser_);
352 break;
353 case IDC_BOOKMARK_PAGE:
354 BookmarkCurrentPage(browser_);
355 break;
1384 case IDC_PIN_TO_START_SCREEN: 356 case IDC_PIN_TO_START_SCREEN:
1385 chrome::PinCurrentPageToStartScreen(this); 357 PinCurrentPageToStartScreen(browser_);
1386 break; 358 break;
1387 case IDC_BOOKMARK_ALL_TABS: BookmarkAllTabs(); break; 359 case IDC_BOOKMARK_ALL_TABS:
1388 case IDC_VIEW_SOURCE: chrome::ViewSelectedSource(this); break; 360 BookmarkAllTabs(browser_);
1389 case IDC_EMAIL_PAGE_LOCATION: chrome::EmailPageLocation(this); break; 361 break;
1390 case IDC_PRINT: chrome::Print(this); break; 362 case IDC_VIEW_SOURCE:
1391 case IDC_ADVANCED_PRINT: chrome::AdvancedPrint(this); break; 363 ViewSelectedSource(browser_);
364 break;
365 case IDC_EMAIL_PAGE_LOCATION:
366 EmailPageLocation(browser_);
367 break;
368 case IDC_PRINT:
369 Print(browser_);
370 break;
371 case IDC_ADVANCED_PRINT:
372 AdvancedPrint(browser_);
373 break;
1392 case IDC_CHROME_TO_MOBILE_PAGE: 374 case IDC_CHROME_TO_MOBILE_PAGE:
1393 chrome::ShowChromeToMobileBubble(this); 375 ShowChromeToMobileBubble(browser_);
1394 break; 376 break;
1395 case IDC_ENCODING_AUTO_DETECT: ToggleEncodingAutoDetect(); break; 377 case IDC_ENCODING_AUTO_DETECT:
378 browser_->ToggleEncodingAutoDetect();
379 break;
1396 case IDC_ENCODING_UTF8: 380 case IDC_ENCODING_UTF8:
1397 case IDC_ENCODING_UTF16LE: 381 case IDC_ENCODING_UTF16LE:
1398 case IDC_ENCODING_ISO88591: 382 case IDC_ENCODING_ISO88591:
1399 case IDC_ENCODING_WINDOWS1252: 383 case IDC_ENCODING_WINDOWS1252:
1400 case IDC_ENCODING_GBK: 384 case IDC_ENCODING_GBK:
1401 case IDC_ENCODING_GB18030: 385 case IDC_ENCODING_GB18030:
1402 case IDC_ENCODING_BIG5HKSCS: 386 case IDC_ENCODING_BIG5HKSCS:
1403 case IDC_ENCODING_BIG5: 387 case IDC_ENCODING_BIG5:
1404 case IDC_ENCODING_KOREAN: 388 case IDC_ENCODING_KOREAN:
1405 case IDC_ENCODING_SHIFTJIS: 389 case IDC_ENCODING_SHIFTJIS:
(...skipping 16 matching lines...) Expand all
1422 case IDC_ENCODING_ISO88593: 406 case IDC_ENCODING_ISO88593:
1423 case IDC_ENCODING_ISO885910: 407 case IDC_ENCODING_ISO885910:
1424 case IDC_ENCODING_ISO885914: 408 case IDC_ENCODING_ISO885914:
1425 case IDC_ENCODING_ISO885916: 409 case IDC_ENCODING_ISO885916:
1426 case IDC_ENCODING_WINDOWS1254: 410 case IDC_ENCODING_WINDOWS1254:
1427 case IDC_ENCODING_ISO88596: 411 case IDC_ENCODING_ISO88596:
1428 case IDC_ENCODING_WINDOWS1256: 412 case IDC_ENCODING_WINDOWS1256:
1429 case IDC_ENCODING_ISO88598: 413 case IDC_ENCODING_ISO88598:
1430 case IDC_ENCODING_ISO88598I: 414 case IDC_ENCODING_ISO88598I:
1431 case IDC_ENCODING_WINDOWS1255: 415 case IDC_ENCODING_WINDOWS1255:
1432 case IDC_ENCODING_WINDOWS1258: OverrideEncoding(id); break; 416 case IDC_ENCODING_WINDOWS1258:
417 browser_->OverrideEncoding(id);
418 break;
1433 419
1434 // Clipboard commands 420 // Clipboard commands
1435 case IDC_CUT: chrome::Cut(this); break; 421 case IDC_CUT:
1436 case IDC_COPY: chrome::Copy(this); break; 422 Cut(browser_);
1437 case IDC_PASTE: chrome::Paste(this); break; 423 break;
424 case IDC_COPY:
425 Copy(browser_);
426 break;
427 case IDC_PASTE:
428 Paste(browser_);
429 break;
1438 430
1439 // Find-in-page 431 // Find-in-page
1440 case IDC_FIND: chrome::Find(this); break; 432 case IDC_FIND:
1441 case IDC_FIND_NEXT: chrome::FindNext(this); break; 433 Find(browser_);
1442 case IDC_FIND_PREVIOUS: chrome::FindPrevious(this); break; 434 break;
435 case IDC_FIND_NEXT:
436 FindNext(browser_);
437 break;
438 case IDC_FIND_PREVIOUS:
439 FindPrevious(browser_);
440 break;
1443 441
1444 // Zoom 442 // Zoom
1445 case IDC_ZOOM_PLUS: 443 case IDC_ZOOM_PLUS:
1446 chrome::Zoom(this, content::PAGE_ZOOM_IN); 444 Zoom(browser_, content::PAGE_ZOOM_IN);
1447 break; 445 break;
1448 case IDC_ZOOM_NORMAL: 446 case IDC_ZOOM_NORMAL:
1449 chrome::Zoom(this, content::PAGE_ZOOM_RESET); 447 Zoom(browser_, content::PAGE_ZOOM_RESET);
1450 break; 448 break;
1451 case IDC_ZOOM_MINUS: 449 case IDC_ZOOM_MINUS:
1452 chrome::Zoom(this, content::PAGE_ZOOM_OUT); 450 Zoom(browser_, content::PAGE_ZOOM_OUT);
1453 break; 451 break;
1454 452
1455 // Focus various bits of UI 453 // Focus various bits of UI
1456 case IDC_FOCUS_TOOLBAR: chrome::FocusToolbar(this); break; 454 case IDC_FOCUS_TOOLBAR:
1457 case IDC_FOCUS_LOCATION: chrome::FocusLocationBar(this); break; 455 FocusToolbar(browser_);
1458 case IDC_FOCUS_SEARCH: chrome::FocusSearch(this); break; 456 break;
1459 case IDC_FOCUS_MENU_BAR: chrome::FocusAppMenu(this); break; 457 case IDC_FOCUS_LOCATION:
458 FocusLocationBar(browser_);
459 break;
460 case IDC_FOCUS_SEARCH:
461 FocusSearch(browser_);
462 break;
463 case IDC_FOCUS_MENU_BAR:
464 FocusAppMenu(browser_);
465 break;
1460 case IDC_FOCUS_BOOKMARKS: 466 case IDC_FOCUS_BOOKMARKS:
1461 chrome::FocusBookmarksToolbar(this); 467 FocusBookmarksToolbar(browser_);
1462 break; 468 break;
1463 case IDC_FOCUS_NEXT_PANE: chrome::FocusNextPane(this); break; 469 case IDC_FOCUS_NEXT_PANE:
1464 case IDC_FOCUS_PREVIOUS_PANE: chrome::FocusPreviousPane(this); break; 470 FocusNextPane(browser_);
471 break;
472 case IDC_FOCUS_PREVIOUS_PANE:
473 FocusPreviousPane(browser_);
474 break;
1465 475
1466 // Show various bits of UI 476 // Show various bits of UI
1467 case IDC_OPEN_FILE: OpenFile(); break; 477 case IDC_OPEN_FILE:
1468 case IDC_CREATE_SHORTCUTS: OpenCreateShortcutsDialog(); break; 478 browser_->OpenFile();
479 break;
480 case IDC_CREATE_SHORTCUTS:
481 browser_->OpenCreateShortcutsDialog();
482 break;
1469 case IDC_DEV_TOOLS: 483 case IDC_DEV_TOOLS:
1470 chrome::ToggleDevToolsWindow(this, DEVTOOLS_TOGGLE_ACTION_NONE); 484 ToggleDevToolsWindow(browser_, DEVTOOLS_TOGGLE_ACTION_NONE);
1471 break; 485 break;
1472 case IDC_DEV_TOOLS_CONSOLE: 486 case IDC_DEV_TOOLS_CONSOLE:
1473 chrome::ToggleDevToolsWindow(this, DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE); 487 ToggleDevToolsWindow(browser_, DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE);
1474 break; 488 break;
1475 case IDC_DEV_TOOLS_INSPECT: 489 case IDC_DEV_TOOLS_INSPECT:
1476 chrome::ToggleDevToolsWindow(this, DEVTOOLS_TOGGLE_ACTION_INSPECT); 490 ToggleDevToolsWindow(browser_, DEVTOOLS_TOGGLE_ACTION_INSPECT);
1477 break; 491 break;
1478 case IDC_TASK_MANAGER: 492 case IDC_TASK_MANAGER:
1479 chrome::OpenTaskManager(this, false); 493 OpenTaskManager(browser_, false);
1480 break; 494 break;
1481 case IDC_VIEW_BACKGROUND_PAGES: 495 case IDC_VIEW_BACKGROUND_PAGES:
1482 chrome::OpenTaskManager(this, true); 496 OpenTaskManager(browser_, true);
1483 break; 497 break;
1484 case IDC_FEEDBACK: 498 case IDC_FEEDBACK:
1485 chrome::OpenFeedbackDialog(this); 499 OpenFeedbackDialog(browser_);
1486 break; 500 break;
1487 501
1488 case IDC_SHOW_BOOKMARK_BAR: chrome::ToggleBookmarkBar(this); break; 502 case IDC_SHOW_BOOKMARK_BAR:
1489 case IDC_PROFILING_ENABLED: Profiling::Toggle(); break; 503 ToggleBookmarkBar(browser_);
504 break;
505 case IDC_PROFILING_ENABLED:
506 Profiling::Toggle();
507 break;
1490 508
1491 case IDC_SHOW_BOOKMARK_MANAGER: chrome::ShowBookmarkManager(this);break; 509 case IDC_SHOW_BOOKMARK_MANAGER:
1492 case IDC_SHOW_APP_MENU: chrome::ShowAppMenu(this); break; 510 ShowBookmarkManager(browser_);
1493 case IDC_SHOW_AVATAR_MENU: chrome::ShowAvatarMenu(this); break; 511 break;
1494 case IDC_SHOW_HISTORY: chrome::ShowHistory(this); break; 512 case IDC_SHOW_APP_MENU:
1495 case IDC_SHOW_DOWNLOADS: chrome::ShowDownloads(this); break; 513 ShowAppMenu(browser_);
1496 case IDC_MANAGE_EXTENSIONS: chrome::ShowExtensions(this); break; 514 break;
1497 case IDC_OPTIONS: chrome::ShowSettings(this); break; 515 case IDC_SHOW_AVATAR_MENU:
516 ShowAvatarMenu(browser_);
517 break;
518 case IDC_SHOW_HISTORY:
519 ShowHistory(browser_);
520 break;
521 case IDC_SHOW_DOWNLOADS:
522 ShowDownloads(browser_);
523 break;
524 case IDC_MANAGE_EXTENSIONS:
525 ShowExtensions(browser_);
526 break;
527 case IDC_OPTIONS:
528 ShowSettings(browser_);
529 break;
1498 case IDC_EDIT_SEARCH_ENGINES: 530 case IDC_EDIT_SEARCH_ENGINES:
1499 chrome::ShowSearchEngineSettings(this); 531 ShowSearchEngineSettings(browser_);
1500 break; 532 break;
1501 case IDC_VIEW_PASSWORDS: chrome::ShowPasswordManager(this);break; 533 case IDC_VIEW_PASSWORDS:
534 ShowPasswordManager(browser_);
535 break;
1502 case IDC_CLEAR_BROWSING_DATA: 536 case IDC_CLEAR_BROWSING_DATA:
1503 chrome::ShowClearBrowsingDataDialog(this); 537 ShowClearBrowsingDataDialog(browser_);
1504 break; 538 break;
1505 case IDC_IMPORT_SETTINGS: chrome::ShowImportDialog(this); break; 539 case IDC_IMPORT_SETTINGS:
1506 case IDC_ABOUT: chrome::ShowAboutChrome(this); break; 540 ShowImportDialog(browser_);
541 break;
542 case IDC_ABOUT:
543 ShowAboutChrome(browser_);
544 break;
1507 case IDC_UPGRADE_DIALOG: 545 case IDC_UPGRADE_DIALOG:
1508 chrome::OpenUpdateChromeDialog(this); 546 OpenUpdateChromeDialog(browser_);
1509 break; 547 break;
1510 case IDC_VIEW_INCOMPATIBILITIES: 548 case IDC_VIEW_INCOMPATIBILITIES:
1511 chrome::ShowConflicts(this); 549 ShowConflicts(browser_);
1512 break; 550 break;
1513 case IDC_HELP_PAGE_VIA_KEYBOARD: 551 case IDC_HELP_PAGE_VIA_KEYBOARD:
1514 chrome::ShowHelp(this, chrome::HELP_SOURCE_KEYBOARD); 552 ShowHelp(browser_, HELP_SOURCE_KEYBOARD);
1515 break; 553 break;
1516 case IDC_HELP_PAGE_VIA_MENU: 554 case IDC_HELP_PAGE_VIA_MENU:
1517 chrome::ShowHelp(this, chrome::HELP_SOURCE_MENU); 555 ShowHelp(browser_, HELP_SOURCE_MENU);
1518 break; 556 break;
1519 case IDC_SHOW_SYNC_SETUP: 557 case IDC_SHOW_SYNC_SETUP:
1520 chrome::ShowSyncSetup(this, SyncPromoUI::SOURCE_MENU); 558 ShowSyncSetup(browser_, SyncPromoUI::SOURCE_MENU);
1521 break; 559 break;
1522 case IDC_TOGGLE_SPEECH_INPUT: chrome::ToggleSpeechInput(this); break; 560 case IDC_TOGGLE_SPEECH_INPUT:
561 ToggleSpeechInput(browser_);
562 break;
1523 563
1524 default: 564 default:
1525 LOG(WARNING) << "Received Unimplemented Command: " << id; 565 LOG(WARNING) << "Received Unimplemented Command: " << id;
1526 break; 566 break;
1527 } 567 }
1528 } 568 }
1529 569
1530 //////////////////////////////////////////////////////////////////////////////// 570 ////////////////////////////////////////////////////////////////////////////////
1531 // Browser, TabRestoreServiceObserver: 571 // BrowserCommandController, content::NotificationObserver implementation:
1532 572
1533 void Browser::TabRestoreServiceChanged(TabRestoreService* service) { 573 void BrowserCommandController::Observe(
1534 command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB, 574 int type,
1535 !service->entries().empty()); 575 const content::NotificationSource& source,
1536 } 576 const content::NotificationDetails& details) {
1537
1538 void Browser::TabRestoreServiceDestroyed(TabRestoreService* service) {
1539 if (!tab_restore_service_)
1540 return;
1541
1542 DCHECK_EQ(tab_restore_service_, service);
1543 tab_restore_service_->RemoveObserver(this);
1544 tab_restore_service_ = NULL;
1545 }
1546
1547 // Centralized method for creating a TabContents, configuring and
1548 // installing all its supporting objects and observers.
1549 TabContents* Browser::TabContentsFactory(
1550 Profile* profile,
1551 SiteInstance* site_instance,
1552 int routing_id,
1553 const WebContents* base_web_contents,
1554 content::SessionStorageNamespace* session_storage_namespace) {
1555 WebContents* new_contents = WebContents::Create(
1556 profile, site_instance, routing_id, base_web_contents,
1557 session_storage_namespace);
1558 TabContents* tab_contents = new TabContents(new_contents);
1559 return tab_contents;
1560 }
1561
1562 ///////////////////////////////////////////////////////////////////////////////
1563 // Browser, TabStripModelDelegate implementation:
1564
1565 TabContents* Browser::AddBlankTab(bool foreground) {
1566 return AddBlankTabAt(-1, foreground);
1567 }
1568
1569 TabContents* Browser::AddBlankTabAt(int index, bool foreground) {
1570 // Time new tab page creation time. We keep track of the timing data in
1571 // WebContents, but we want to include the time it takes to create the
1572 // WebContents object too.
1573 base::TimeTicks new_tab_start_time = base::TimeTicks::Now();
1574 browser::NavigateParams params(this, GURL(chrome::kChromeUINewTabURL),
1575 content::PAGE_TRANSITION_TYPED);
1576 params.disposition = foreground ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
1577 params.tabstrip_index = index;
1578 browser::Navigate(&params);
1579 params.target_contents->web_contents()->SetNewTabStartTime(
1580 new_tab_start_time);
1581 return params.target_contents;
1582 }
1583
1584 Browser* Browser::CreateNewStripWithContents(
1585 TabContents* detached_contents,
1586 const gfx::Rect& window_bounds,
1587 const DockInfo& dock_info,
1588 bool maximize) {
1589 DCHECK(CanSupportWindowFeature(FEATURE_TABSTRIP));
1590
1591 gfx::Rect new_window_bounds = window_bounds;
1592 if (dock_info.GetNewWindowBounds(&new_window_bounds, &maximize))
1593 dock_info.AdjustOtherWindowBounds();
1594
1595 // Create an empty new browser window the same size as the old one.
1596 Browser* browser = new Browser(TYPE_TABBED, profile_);
1597 browser->set_override_bounds(new_window_bounds);
1598 browser->set_initial_show_state(
1599 maximize ? ui::SHOW_STATE_MAXIMIZED : ui::SHOW_STATE_NORMAL);
1600 browser->InitBrowserWindow();
1601 browser->tab_strip_model()->AppendTabContents(detached_contents, true);
1602 // Make sure the loading state is updated correctly, otherwise the throbber
1603 // won't start if the page is loading.
1604 browser->LoadingStateChanged(detached_contents->web_contents());
1605 return browser;
1606 }
1607
1608 int Browser::GetDragActions() const {
1609 return TabStripModelDelegate::TAB_TEAROFF_ACTION | (tab_count() > 1 ?
1610 TabStripModelDelegate::TAB_MOVE_ACTION : 0);
1611 }
1612
1613 TabContents* Browser::CreateTabContentsForURL(
1614 const GURL& url, const content::Referrer& referrer, Profile* profile,
1615 content::PageTransition transition, bool defer_load,
1616 SiteInstance* instance) const {
1617 TabContents* contents = TabContentsFactory(profile, instance,
1618 MSG_ROUTING_NONE, GetActiveWebContents(), NULL);
1619 if (!defer_load) {
1620 // Load the initial URL before adding the new tab contents to the tab strip
1621 // so that the tab contents has navigation state.
1622 contents->web_contents()->GetController().LoadURL(
1623 url, referrer, transition, std::string());
1624 }
1625
1626 return contents;
1627 }
1628
1629 bool Browser::CanDuplicateContentsAt(int index) {
1630 NavigationController& nc = GetWebContentsAt(index)->GetController();
1631 return nc.GetWebContents() && nc.GetLastCommittedEntry();
1632 }
1633
1634 void Browser::DuplicateContentsAt(int index) {
1635 TabContents* contents = GetTabContentsAt(index);
1636 CHECK(contents);
1637 TabContents* contents_dupe = contents->Clone();
1638
1639 bool pinned = false;
1640 if (CanSupportWindowFeature(FEATURE_TABSTRIP)) {
1641 // If this is a tabbed browser, just create a duplicate tab inside the same
1642 // window next to the tab being duplicated.
1643 int index = tab_strip_model_->GetIndexOfTabContents(contents);
1644 pinned = IsTabPinned(index);
1645 int add_types = TabStripModel::ADD_ACTIVE |
1646 TabStripModel::ADD_INHERIT_GROUP |
1647 (pinned ? TabStripModel::ADD_PINNED : 0);
1648 tab_strip_model_->InsertTabContentsAt(index + 1, contents_dupe, add_types);
1649 } else {
1650 Browser* browser = NULL;
1651 if (is_app()) {
1652 CHECK(!is_type_popup());
1653 CHECK(!is_type_panel());
1654 browser = Browser::CreateWithParams(
1655 Browser::CreateParams::CreateForApp(
1656 TYPE_POPUP, app_name_, gfx::Rect(),profile_));
1657 } else if (is_type_popup()) {
1658 browser = Browser::CreateWithParams(
1659 Browser::CreateParams(TYPE_POPUP, profile_));
1660 }
1661
1662 // Preserve the size of the original window. The new window has already
1663 // been given an offset by the OS, so we shouldn't copy the old bounds.
1664 BrowserWindow* new_window = browser->window();
1665 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
1666 window()->GetRestoredBounds().size()));
1667
1668 // We need to show the browser now. Otherwise ContainerWin assumes the
1669 // WebContents is invisible and won't size it.
1670 browser->window()->Show();
1671
1672 // The page transition below is only for the purpose of inserting the tab.
1673 browser->AddTab(contents_dupe, content::PAGE_TRANSITION_LINK);
1674 }
1675
1676 SessionService* session_service =
1677 SessionServiceFactory::GetForProfileIfExisting(profile_);
1678 if (session_service)
1679 session_service->TabRestored(contents_dupe, pinned);
1680 }
1681
1682 void Browser::CloseFrameAfterDragSession() {
1683 #if !defined(OS_MACOSX)
1684 // This is scheduled to run after we return to the message loop because
1685 // otherwise the frame will think the drag session is still active and ignore
1686 // the request.
1687 // TODO(port): figure out what is required here in a cross-platform world
1688 MessageLoop::current()->PostTask(
1689 FROM_HERE, base::Bind(&Browser::CloseFrame, weak_factory_.GetWeakPtr()));
1690 #endif
1691 }
1692
1693 void Browser::CreateHistoricalTab(TabContents* contents) {
1694 // We don't create historical tabs for incognito windows or windows without
1695 // profiles.
1696 if (!profile() || profile()->IsOffTheRecord())
1697 return;
1698
1699 // We don't create historical tabs for print preview tabs.
1700 if (contents->web_contents()->GetURL() == GURL(chrome::kChromeUIPrintURL))
1701 return;
1702
1703 TabRestoreService* service =
1704 TabRestoreServiceFactory::GetForProfile(profile());
1705
1706 // We only create historical tab entries for tabbed browser windows.
1707 if (service && CanSupportWindowFeature(FEATURE_TABSTRIP)) {
1708 service->CreateHistoricalTab(contents->web_contents(),
1709 tab_strip_model_->GetIndexOfTabContents(contents));
1710 }
1711 }
1712
1713 bool Browser::RunUnloadListenerBeforeClosing(TabContents* contents) {
1714 return Browser::RunUnloadEventsHelper(contents->web_contents());
1715 }
1716
1717 bool Browser::CanBookmarkAllTabs() const {
1718 BookmarkModel* model = profile()->GetBookmarkModel();
1719 return (model && model->IsLoaded()) &&
1720 tab_count() > 1 &&
1721 profile()->GetPrefs()->GetBoolean(prefs::kEditBookmarksEnabled);
1722 }
1723
1724 void Browser::BookmarkAllTabs() {
1725 BookmarkEditor::ShowBookmarkAllTabsDialog(this);
1726 }
1727
1728 bool Browser::CanRestoreTab() {
1729 return command_updater_.IsCommandEnabled(IDC_RESTORE_TAB);
1730 }
1731
1732 void Browser::RestoreTab() {
1733 content::RecordAction(UserMetricsAction("RestoreTab"));
1734 TabRestoreService* service =
1735 TabRestoreServiceFactory::GetForProfile(profile_);
1736 if (!service)
1737 return;
1738
1739 service->RestoreMostRecentEntry(tab_restore_service_delegate());
1740 }
1741
1742 ///////////////////////////////////////////////////////////////////////////////
1743 // Browser, TabStripModelObserver implementation:
1744
1745 void Browser::TabInsertedAt(TabContents* contents,
1746 int index,
1747 bool foreground) {
1748 SetAsDelegate(contents, this);
1749 contents->restore_tab_helper()->SetWindowID(session_id());
1750
1751 SyncHistoryWithTabs(index);
1752
1753 // Make sure the loading state is updated correctly, otherwise the throbber
1754 // won't start if the page is loading.
1755 LoadingStateChanged(contents->web_contents());
1756
1757 // If the tab crashes in the beforeunload or unload handler, it won't be
1758 // able to ack. But we know we can close it.
1759 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
1760 content::Source<WebContents>(contents->web_contents()));
1761
1762 registrar_.Add(this, content::NOTIFICATION_INTERSTITIAL_ATTACHED,
1763 content::Source<WebContents>(contents->web_contents()));
1764
1765 registrar_.Add(this, content::NOTIFICATION_INTERSTITIAL_DETACHED,
1766 content::Source<WebContents>(contents->web_contents()));
1767 }
1768
1769 void Browser::TabClosingAt(TabStripModel* tab_strip_model,
1770 TabContents* contents,
1771 int index) {
1772 fullscreen_controller_->OnTabClosing(contents->web_contents());
1773 content::NotificationService::current()->Notify(
1774 chrome::NOTIFICATION_TAB_CLOSING,
1775 content::Source<NavigationController>(
1776 &contents->web_contents()->GetController()),
1777 content::NotificationService::NoDetails());
1778
1779 // Sever the WebContents' connection back to us.
1780 SetAsDelegate(contents, NULL);
1781 }
1782
1783 void Browser::TabDetachedAt(TabContents* contents, int index) {
1784 TabDetachedAtImpl(contents, index, DETACH_TYPE_DETACH);
1785 }
1786
1787 void Browser::TabDeactivated(TabContents* contents) {
1788 fullscreen_controller_->OnTabDeactivated(contents);
1789 search_delegate_->OnTabDeactivated(contents);
1790
1791 if (instant())
1792 instant()->Hide();
1793
1794 // Save what the user's currently typing, so it can be restored when we
1795 // switch back to this tab.
1796 window_->GetLocationBar()->SaveStateToContents(contents->web_contents());
1797 }
1798
1799 void Browser::ActiveTabChanged(TabContents* old_contents,
1800 TabContents* new_contents,
1801 int index,
1802 bool user_gesture) {
1803 // On some platforms we want to automatically reload tabs that are
1804 // killed when the user selects them.
1805 bool did_reload = false;
1806 if (user_gesture && new_contents->web_contents()->GetCrashedStatus() ==
1807 base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
1808 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
1809 if (parsed_command_line.HasSwitch(switches::kReloadKilledTabs)) {
1810 LOG(WARNING) << "Reloading killed tab at " << index;
1811 static int reload_count = 0;
1812 UMA_HISTOGRAM_CUSTOM_COUNTS(
1813 "Tabs.SadTab.ReloadCount", ++reload_count, 1, 1000, 50);
1814 chrome::Reload(this, CURRENT_TAB);
1815 did_reload = true;
1816 }
1817 }
1818
1819 // Discarded tabs always get reloaded.
1820 if (!did_reload && IsTabDiscarded(index)) {
1821 LOG(WARNING) << "Reloading discarded tab at " << index;
1822 static int reload_count = 0;
1823 UMA_HISTOGRAM_CUSTOM_COUNTS(
1824 "Tabs.Discard.ReloadCount", ++reload_count, 1, 1000, 50);
1825 chrome::Reload(this, CURRENT_TAB);
1826 }
1827
1828 // If we have any update pending, do it now.
1829 if (chrome_updater_factory_.HasWeakPtrs() && old_contents)
1830 ProcessPendingUIUpdates();
1831
1832 // Propagate the profile to the location bar.
1833 UpdateToolbar(true);
1834
1835 // Propagate tab state to toolbar, tab-strip, etc.
1836 UpdateSearchState(new_contents);
1837
1838 // Update reload/stop state.
1839 UpdateReloadStopState(new_contents->web_contents()->IsLoading(), true);
1840
1841 // Update commands to reflect current state.
1842 UpdateCommandsForTabState();
1843
1844 // Reset the status bubble.
1845 StatusBubble* status_bubble = GetStatusBubble();
1846 if (status_bubble) {
1847 status_bubble->Hide();
1848
1849 // Show the loading state (if any).
1850 status_bubble->SetStatus(
1851 GetActiveTabContents()->core_tab_helper()->GetStatusText());
1852 }
1853
1854 if (HasFindBarController()) {
1855 find_bar_controller_->ChangeTabContents(new_contents);
1856 find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true);
1857 }
1858
1859 // Update sessions. Don't force creation of sessions. If sessions doesn't
1860 // exist, the change will be picked up by sessions when created.
1861 SessionService* session_service =
1862 SessionServiceFactory::GetForProfileIfExisting(profile_);
1863 if (session_service && !tab_strip_model_->closing_all()) {
1864 session_service->SetSelectedTabInWindow(session_id(), active_index());
1865 }
1866
1867 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_SWITCH);
1868 }
1869
1870 void Browser::TabMoved(TabContents* contents,
1871 int from_index,
1872 int to_index) {
1873 DCHECK(from_index >= 0 && to_index >= 0);
1874 // Notify the history service.
1875 SyncHistoryWithTabs(std::min(from_index, to_index));
1876 }
1877
1878 void Browser::TabReplacedAt(TabStripModel* tab_strip_model,
1879 TabContents* old_contents,
1880 TabContents* new_contents,
1881 int index) {
1882 TabDetachedAtImpl(old_contents, index, DETACH_TYPE_REPLACE);
1883 TabInsertedAt(new_contents, index, (index == active_index()));
1884
1885 int entry_count =
1886 new_contents->web_contents()->GetController().GetEntryCount();
1887 if (entry_count > 0) {
1888 // Send out notification so that observers are updated appropriately.
1889 new_contents->web_contents()->GetController().NotifyEntryChanged(
1890 new_contents->web_contents()->GetController().GetEntryAtIndex(
1891 entry_count - 1),
1892 entry_count - 1);
1893 }
1894
1895 SessionService* session_service =
1896 SessionServiceFactory::GetForProfile(profile());
1897 if (session_service) {
1898 // The new_contents may end up with a different navigation stack. Force
1899 // the session service to update itself.
1900 session_service->TabRestored(new_contents, IsTabPinned(index));
1901 }
1902
1903 content::DevToolsManager::GetInstance()->ContentsReplaced(
1904 old_contents->web_contents(), new_contents->web_contents());
1905 }
1906
1907 void Browser::TabPinnedStateChanged(TabContents* contents, int index) {
1908 SessionService* session_service =
1909 SessionServiceFactory::GetForProfileIfExisting(profile());
1910 if (session_service) {
1911 session_service->SetPinnedState(
1912 session_id(),
1913 GetTabContentsAt(index)->restore_tab_helper()->session_id(),
1914 IsTabPinned(index));
1915 }
1916 }
1917
1918 void Browser::TabStripEmpty() {
1919 // Close the frame after we return to the message loop (not immediately,
1920 // otherwise it will destroy this object before the stack has a chance to
1921 // cleanly unwind.)
1922 // Note: This will be called several times if TabStripEmpty is called several
1923 // times. This is because it does not close the window if tabs are
1924 // still present.
1925 MessageLoop::current()->PostTask(
1926 FROM_HERE, base::Bind(&Browser::CloseFrame, weak_factory_.GetWeakPtr()));
1927 // Set is_attempting_to_close_browser_ here, so that extensions, etc, do not
1928 // attempt to add tabs to the browser before it closes.
1929 is_attempting_to_close_browser_ = true;
1930 }
1931
1932 bool Browser::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
1933 bool* is_keyboard_shortcut) {
1934 // Escape exits tabbed fullscreen mode.
1935 // TODO(koz): Write a test for this http://crbug.com/100441.
1936 if (event.windowsKeyCode == 27 &&
1937 fullscreen_controller_->HandleUserPressedEscape()) {
1938 return true;
1939 }
1940 return window()->PreHandleKeyboardEvent(event, is_keyboard_shortcut);
1941 }
1942
1943 void Browser::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
1944 window()->HandleKeyboardEvent(event);
1945 }
1946
1947 void Browser::OnAcceptFullscreenPermission(
1948 const GURL& url,
1949 FullscreenExitBubbleType bubble_type) {
1950 fullscreen_controller_->OnAcceptFullscreenPermission(url, bubble_type);
1951 }
1952
1953 void Browser::OnDenyFullscreenPermission(FullscreenExitBubbleType bubble_type) {
1954 fullscreen_controller_->OnDenyFullscreenPermission(bubble_type);
1955 }
1956
1957 bool Browser::TabsNeedBeforeUnloadFired() {
1958 if (tabs_needing_before_unload_fired_.empty()) {
1959 for (int i = 0; i < tab_count(); ++i) {
1960 WebContents* contents = GetTabContentsAt(i)->web_contents();
1961 if (contents->NeedToFireBeforeUnload())
1962 tabs_needing_before_unload_fired_.insert(contents);
1963 }
1964 }
1965 return !tabs_needing_before_unload_fired_.empty();
1966 }
1967
1968 bool Browser::IsFullscreenForTabOrPending() const {
1969 return fullscreen_controller_->IsFullscreenForTabOrPending();
1970 }
1971
1972 bool Browser::IsMouseLocked() const {
1973 return fullscreen_controller_->IsMouseLocked();
1974 }
1975
1976 void Browser::OnWindowDidShow() {
1977 if (window_has_shown_)
1978 return;
1979 window_has_shown_ = true;
1980
1981 // Nothing to do for non-tabbed windows.
1982 if (!is_type_tabbed())
1983 return;
1984
1985 // Show any pending global error bubble.
1986 GlobalErrorService* service =
1987 GlobalErrorServiceFactory::GetForProfile(profile());
1988 GlobalError* error = service->GetFirstGlobalErrorWithBubbleView();
1989 if (error)
1990 error->ShowBubbleView(this);
1991 }
1992
1993 void Browser::ShowFirstRunBubble() {
1994 window()->GetLocationBar()->ShowFirstRunBubble();
1995 }
1996
1997 ///////////////////////////////////////////////////////////////////////////////
1998 // Browser, protected:
1999
2000 BrowserWindow* Browser::CreateBrowserWindow() {
2001 bool create_panel = false;
2002 #if defined(USE_ASH)
2003 if (CommandLine::ForCurrentProcess()->HasSwitch(
2004 ash::switches::kAuraPanelManager))
2005 create_panel = is_type_panel();
2006 #elif !defined(OS_CHROMEOS)
2007 create_panel = is_type_panel();
2008 #endif
2009 if (create_panel)
2010 return PanelManager::GetInstance()->CreatePanel(this)->browser_window();
2011
2012 return BrowserWindow::CreateBrowserWindow(this);
2013 }
2014
2015 ///////////////////////////////////////////////////////////////////////////////
2016 // Browser, content::WebContentsDelegate implementation:
2017
2018 WebContents* Browser::OpenURLFromTab(WebContents* source,
2019 const OpenURLParams& params) {
2020 browser::NavigateParams nav_params(this, params.url, params.transition);
2021 nav_params.source_contents = GetTabContentsAt(
2022 tab_strip_model_->GetIndexOfWebContents(source));
2023 nav_params.referrer = params.referrer;
2024 nav_params.disposition = params.disposition;
2025 nav_params.tabstrip_add_types = TabStripModel::ADD_NONE;
2026 nav_params.window_action = browser::NavigateParams::SHOW_WINDOW;
2027 nav_params.user_gesture = true;
2028 nav_params.override_encoding = params.override_encoding;
2029 nav_params.is_renderer_initiated = params.is_renderer_initiated;
2030 nav_params.transferred_global_request_id =
2031 params.transferred_global_request_id;
2032 browser::Navigate(&nav_params);
2033
2034 return nav_params.target_contents ?
2035 nav_params.target_contents->web_contents() : NULL;
2036 }
2037
2038 void Browser::NavigationStateChanged(const WebContents* source,
2039 unsigned changed_flags) {
2040 // Only update the UI when something visible has changed.
2041 if (changed_flags)
2042 ScheduleUIUpdate(source, changed_flags);
2043
2044 // We can synchronously update commands since they will only change once per
2045 // navigation, so we don't have to worry about flickering. We do, however,
2046 // need to update the command state early on load to always present usable
2047 // actions in the face of slow-to-commit pages.
2048 if (changed_flags & (content::INVALIDATE_TYPE_URL |
2049 content::INVALIDATE_TYPE_LOAD))
2050 UpdateCommandsForTabState();
2051 }
2052
2053 void Browser::AddNewContents(WebContents* source,
2054 WebContents* new_contents,
2055 WindowOpenDisposition disposition,
2056 const gfx::Rect& initial_pos,
2057 bool user_gesture) {
2058 // No code for this yet.
2059 DCHECK(disposition != SAVE_TO_DISK);
2060 // Can't create a new contents for the current tab - invalid case.
2061 DCHECK(disposition != CURRENT_TAB);
2062
2063 TabContents* source_tab_contents = NULL;
2064 BlockedContentTabHelper* source_blocked_content = NULL;
2065 TabContents* new_tab_contents = TabContents::FromWebContents(new_contents);
2066 if (!new_tab_contents) {
2067 new_tab_contents = new TabContents(new_contents);
2068 }
2069 if (source) {
2070 source_tab_contents = TabContents::FromWebContents(source);
2071 source_blocked_content = source_tab_contents->blocked_content_tab_helper();
2072 }
2073
2074 if (source_tab_contents) {
2075 // Handle blocking of all contents.
2076 if (source_blocked_content->all_contents_blocked()) {
2077 source_blocked_content->AddTabContents(new_tab_contents,
2078 disposition,
2079 initial_pos,
2080 user_gesture);
2081 return;
2082 }
2083
2084 // Handle blocking of popups.
2085 if ((disposition == NEW_POPUP) && !user_gesture &&
2086 !CommandLine::ForCurrentProcess()->HasSwitch(
2087 switches::kDisablePopupBlocking)) {
2088 // Unrequested popups from normal pages are constrained unless they're in
2089 // the whitelist. The popup owner will handle checking this.
2090 GetConstrainingTabContents(source_tab_contents)->
2091 blocked_content_tab_helper()->
2092 AddPopup(new_tab_contents, initial_pos, user_gesture);
2093 return;
2094 }
2095
2096 new_contents->GetRenderViewHost()->DisassociateFromPopupCount();
2097 }
2098
2099 browser::NavigateParams params(this, new_tab_contents);
2100 params.source_contents = source ?
2101 GetTabContentsAt(tab_strip_model_->GetIndexOfWebContents(source)): NULL;
2102 params.disposition = disposition;
2103 params.window_bounds = initial_pos;
2104 params.window_action = browser::NavigateParams::SHOW_WINDOW;
2105 params.user_gesture = user_gesture;
2106 browser::Navigate(&params);
2107 }
2108
2109 void Browser::ActivateContents(WebContents* contents) {
2110 ActivateTabAt(tab_strip_model_->GetIndexOfWebContents(contents), false);
2111 window_->Activate();
2112 }
2113
2114 void Browser::DeactivateContents(WebContents* contents) {
2115 window_->Deactivate();
2116 }
2117
2118 void Browser::LoadingStateChanged(WebContents* source) {
2119 window_->UpdateLoadingAnimations(tab_strip_model_->TabsAreLoading());
2120 window_->UpdateTitleBar();
2121
2122 WebContents* selected_contents = GetActiveWebContents();
2123 if (source == selected_contents) {
2124 bool is_loading = source->IsLoading();
2125 UpdateReloadStopState(is_loading, false);
2126 if (GetStatusBubble()) {
2127 GetStatusBubble()->SetStatus(
2128 GetActiveTabContents()->core_tab_helper()->GetStatusText());
2129 }
2130
2131 if (!is_loading && pending_web_app_action_ == UPDATE_SHORTCUT) {
2132 // Schedule a shortcut update when web application info is available if
2133 // last committed entry is not NULL. Last committed entry could be NULL
2134 // when an interstitial page is injected (e.g. bad https certificate,
2135 // malware site etc). When this happens, we abort the shortcut update.
2136 NavigationEntry* entry = source->GetController().GetLastCommittedEntry();
2137 if (entry) {
2138 TabContents::FromWebContents(source)->
2139 extension_tab_helper()->GetApplicationInfo(entry->GetPageID());
2140 } else {
2141 pending_web_app_action_ = NONE;
2142 }
2143 }
2144 }
2145 }
2146
2147 void Browser::CloseContents(WebContents* source) {
2148 if (is_attempting_to_close_browser_) {
2149 // If we're trying to close the browser, just clear the state related to
2150 // waiting for unload to fire. Don't actually try to close the tab as it
2151 // will go down the slow shutdown path instead of the fast path of killing
2152 // all the renderer processes.
2153 ClearUnloadState(source, true);
2154 return;
2155 }
2156
2157 int index = tab_strip_model_->GetIndexOfWebContents(source);
2158 if (index == TabStripModel::kNoTab) {
2159 NOTREACHED() << "CloseContents called for tab not in our strip";
2160 return;
2161 }
2162 tab_strip_model_->CloseTabContentsAt(index,
2163 TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
2164 }
2165
2166 void Browser::MoveContents(WebContents* source, const gfx::Rect& pos) {
2167 if (!IsPopupOrPanel(source)) {
2168 NOTREACHED() << "moving invalid browser type";
2169 return;
2170 }
2171 window_->SetBounds(pos);
2172 }
2173
2174 void Browser::DetachContents(WebContents* source) {
2175 int index = tab_strip_model_->GetIndexOfWebContents(source);
2176 if (index >= 0)
2177 tab_strip_model_->DetachTabContentsAt(index);
2178 }
2179
2180 bool Browser::IsPopupOrPanel(const WebContents* source) const {
2181 // A non-tabbed BROWSER is an unconstrained popup.
2182 return is_type_popup() || is_type_panel();
2183 }
2184
2185 void Browser::UpdateTargetURL(WebContents* source, int32 page_id,
2186 const GURL& url) {
2187 if (!GetStatusBubble())
2188 return;
2189
2190 if (source == GetActiveWebContents()) {
2191 PrefService* prefs = profile_->GetPrefs();
2192 GetStatusBubble()->SetURL(url, prefs->GetString(prefs::kAcceptLanguages));
2193 }
2194 }
2195
2196 void Browser::ContentsMouseEvent(
2197 WebContents* source, const gfx::Point& location, bool motion) {
2198 if (!GetStatusBubble())
2199 return;
2200
2201 if (source == GetActiveWebContents()) {
2202 GetStatusBubble()->MouseMoved(location, !motion);
2203 if (!motion)
2204 GetStatusBubble()->SetURL(GURL(), std::string());
2205 }
2206 }
2207
2208 void Browser::ContentsZoomChange(bool zoom_in) {
2209 ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS);
2210 }
2211
2212 void Browser::WebContentsFocused(WebContents* contents) {
2213 window_->WebContentsFocused(contents);
2214 }
2215
2216 bool Browser::TakeFocus(bool reverse) {
2217 content::NotificationService::current()->Notify(
2218 chrome::NOTIFICATION_FOCUS_RETURNED_TO_BROWSER,
2219 content::Source<Browser>(this),
2220 content::NotificationService::NoDetails());
2221 return false;
2222 }
2223
2224 bool Browser::IsApplication() const {
2225 return is_app();
2226 }
2227
2228 void Browser::ConvertContentsToApplication(WebContents* contents) {
2229 const GURL& url = contents->GetController().GetActiveEntry()->GetURL();
2230 std::string app_name = web_app::GenerateApplicationNameFromURL(url);
2231
2232 DetachContents(contents);
2233 Browser* app_browser = Browser::CreateWithParams(
2234 Browser::CreateParams::CreateForApp(
2235 TYPE_POPUP, app_name, gfx::Rect(), profile_));
2236 TabContents* tab_contents = TabContents::FromWebContents(contents);
2237 if (!tab_contents)
2238 tab_contents = new TabContents(contents);
2239 app_browser->tab_strip_model()->AppendTabContents(tab_contents, true);
2240
2241 contents->GetMutableRendererPrefs()->can_accept_load_drops = false;
2242 contents->GetRenderViewHost()->SyncRendererPrefs();
2243 app_browser->window()->Show();
2244 }
2245
2246 gfx::Rect Browser::GetRootWindowResizerRect() const {
2247 return window_->GetRootWindowResizerRect();
2248 }
2249
2250 void Browser::BeforeUnloadFired(WebContents* web_contents,
2251 bool proceed,
2252 bool* proceed_to_fire_unload) {
2253 if (!is_attempting_to_close_browser_) {
2254 *proceed_to_fire_unload = proceed;
2255 if (!proceed)
2256 web_contents->SetClosedByUserGesture(false);
2257 return;
2258 }
2259
2260 if (!proceed) {
2261 CancelWindowClose();
2262 *proceed_to_fire_unload = false;
2263 web_contents->SetClosedByUserGesture(false);
2264 return;
2265 }
2266
2267 if (RemoveFromSet(&tabs_needing_before_unload_fired_, web_contents)) {
2268 // Now that beforeunload has fired, put the tab on the queue to fire
2269 // unload.
2270 tabs_needing_unload_fired_.insert(web_contents);
2271 ProcessPendingTabs();
2272 // We want to handle firing the unload event ourselves since we want to
2273 // fire all the beforeunload events before attempting to fire the unload
2274 // events should the user cancel closing the browser.
2275 *proceed_to_fire_unload = false;
2276 return;
2277 }
2278
2279 *proceed_to_fire_unload = true;
2280 }
2281
2282 void Browser::SetFocusToLocationBar(bool select_all) {
2283 // Two differences between this and FocusLocationBar():
2284 // (1) This doesn't get recorded in user metrics, since it's called
2285 // internally.
2286 // (2) This checks whether the location bar can be focused, and if not, clears
2287 // the focus. FocusLocationBar() is only reached when the location bar is
2288 // focusable, but this may be reached at other times, e.g. while in
2289 // fullscreen mode, where we need to leave focus in a consistent state.
2290 window_->SetFocusToLocationBar(select_all);
2291 }
2292
2293 void Browser::RenderWidgetShowing() {
2294 window_->DisableInactiveFrame();
2295 }
2296
2297 int Browser::GetExtraRenderViewHeight() const {
2298 return window_->GetExtraRenderViewHeight();
2299 }
2300
2301 void Browser::OnStartDownload(WebContents* source,
2302 content::DownloadItem* download) {
2303 TabContents* tab_contents = TabContents::FromWebContents(source);
2304 TabContents* constrained = GetConstrainingTabContents(tab_contents);
2305 if (constrained != tab_contents) {
2306 // Download in a constrained popup is shown in the tab that opened it.
2307 WebContents* constrained_tab = constrained->web_contents();
2308 constrained_tab->GetDelegate()->OnStartDownload(constrained_tab, download);
2309 return;
2310 }
2311
2312 if (!window())
2313 return;
2314
2315 // GetDownloadShelf creates the download shelf if it was not yet created.
2316 DownloadShelf* shelf = window()->GetDownloadShelf();
2317 shelf->AddDownload(new DownloadItemModel(download));
2318 // Don't show the animation for "Save file" downloads.
2319 // For non-theme extensions, we don't show the download animation.
2320 // Show animation in same window as the download shelf. Download shelf
2321 // may not be in the same window that initiated the download, e.g.
2322 // Panels.
2323 // Don't show the animation if the selected tab is not visible (i.e. the
2324 // window is minimized, we're in a unit test, etc.).
2325 WebContents* shelf_tab = shelf->browser()->GetActiveWebContents();
2326 if ((download->GetTotalBytes() > 0) &&
2327 !download_crx_util::IsExtensionDownload(*download) &&
2328 platform_util::IsVisible(shelf_tab->GetNativeView()) &&
2329 ui::Animation::ShouldRenderRichAnimation()) {
2330 DownloadStartedAnimation::Show(shelf_tab);
2331 }
2332
2333 // If the download occurs in a new tab, close it.
2334 if (source->GetController().IsInitialNavigation() && tab_count() > 1)
2335 CloseContents(source);
2336 }
2337
2338 void Browser::ViewSourceForTab(WebContents* source, const GURL& page_url) {
2339 DCHECK(source);
2340 TabContents* tab_contents = GetTabContentsAt(
2341 tab_strip_model_->GetIndexOfWebContents(source));
2342 chrome::ViewSource(this, tab_contents);
2343 }
2344
2345 void Browser::ViewSourceForFrame(WebContents* source,
2346 const GURL& frame_url,
2347 const std::string& frame_content_state) {
2348 DCHECK(source);
2349 TabContents* tab_contents = GetTabContentsAt(
2350 tab_strip_model_->GetIndexOfWebContents(source));
2351 chrome::ViewSource(this, tab_contents, frame_url, frame_content_state);
2352 }
2353
2354 void Browser::ShowRepostFormWarningDialog(WebContents* source) {
2355 browser::ShowTabModalConfirmDialog(
2356 new RepostFormWarningController(source),
2357 TabContents::FromWebContents(source));
2358 }
2359
2360 bool Browser::ShouldAddNavigationToHistory(
2361 const history::HistoryAddPageArgs& add_page_args,
2362 content::NavigationType navigation_type) {
2363 // Don't update history if running as app.
2364 return !IsApplication();
2365 }
2366
2367 bool Browser::ShouldCreateWebContents(
2368 WebContents* web_contents,
2369 int route_id,
2370 WindowContainerType window_container_type,
2371 const string16& frame_name,
2372 const GURL& target_url) {
2373 if (window_container_type == WINDOW_CONTAINER_TYPE_BACKGROUND) {
2374 // If a BackgroundContents is created, suppress the normal WebContents.
2375 return !MaybeCreateBackgroundContents(
2376 route_id, web_contents, frame_name, target_url);
2377 }
2378
2379 return true;
2380 }
2381
2382 void Browser::WebContentsCreated(WebContents* source_contents,
2383 int64 source_frame_id,
2384 const GURL& target_url,
2385 WebContents* new_contents) {
2386 // Create a TabContents now, so all observers are in place, as the network
2387 // requests for its initial navigation will start immediately. The WebContents
2388 // will later be inserted into this browser using Browser::Navigate via
2389 // AddNewContents. The latter will retrieve the newly created TabContents from
2390 // WebContents object.
2391 new TabContents(new_contents);
2392
2393 // Notify.
2394 RetargetingDetails details;
2395 details.source_web_contents = source_contents;
2396 details.source_frame_id = source_frame_id;
2397 details.target_url = target_url;
2398 details.target_web_contents = new_contents;
2399 details.not_yet_in_tabstrip = true;
2400 content::NotificationService::current()->Notify(
2401 chrome::NOTIFICATION_RETARGETING,
2402 content::Source<Profile>(profile_),
2403 content::Details<RetargetingDetails>(&details));
2404 }
2405
2406 void Browser::ContentRestrictionsChanged(WebContents* source) {
2407 UpdateCommandsForContentRestrictionState();
2408 }
2409
2410 void Browser::RendererUnresponsive(WebContents* source) {
2411 // Ignore hangs if print preview is open.
2412 TabContents* tab_contents = TabContents::FromWebContents(source);
2413 if (tab_contents) {
2414 printing::PrintPreviewTabController* controller =
2415 printing::PrintPreviewTabController::GetInstance();
2416 if (controller) {
2417 TabContents* preview_tab =
2418 controller->GetPrintPreviewForTab(tab_contents);
2419 if (preview_tab && preview_tab != tab_contents) {
2420 return;
2421 }
2422 }
2423 }
2424
2425 browser::ShowHungRendererDialog(source);
2426 }
2427
2428 void Browser::RendererResponsive(WebContents* source) {
2429 browser::HideHungRendererDialog(source);
2430 }
2431
2432 void Browser::WorkerCrashed(WebContents* source) {
2433 TabContents* tab_contents = TabContents::FromWebContents(source);
2434 InfoBarTabHelper* infobar_helper = tab_contents->infobar_tab_helper();
2435 infobar_helper->AddInfoBar(new SimpleAlertInfoBarDelegate(
2436 infobar_helper,
2437 NULL,
2438 l10n_util::GetStringUTF16(IDS_WEBWORKER_CRASHED_PROMPT),
2439 true));
2440 }
2441
2442 void Browser::DidNavigateMainFramePostCommit(WebContents* web_contents) {
2443 if (web_contents == GetActiveWebContents())
2444 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_STATE);
2445 }
2446
2447 void Browser::DidNavigateToPendingEntry(WebContents* web_contents) {
2448 if (web_contents == GetActiveWebContents())
2449 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_STATE);
2450 }
2451
2452 content::JavaScriptDialogCreator* Browser::GetJavaScriptDialogCreator() {
2453 return GetJavaScriptDialogCreatorInstance();
2454 }
2455
2456 content::ColorChooser* Browser::OpenColorChooser(WebContents* web_contents,
2457 int color_chooser_id,
2458 SkColor color) {
2459 #if defined(OS_WIN)
2460 // On Windows, only create a color chooser if one doesn't exist, because we
2461 // can't close the old color chooser dialog.
2462 if (!color_chooser_.get())
2463 color_chooser_.reset(content::ColorChooser::Create(color_chooser_id,
2464 web_contents,
2465 color));
2466 #else
2467 if (color_chooser_.get())
2468 color_chooser_->End();
2469 color_chooser_.reset(content::ColorChooser::Create(color_chooser_id,
2470 web_contents,
2471 color));
2472 #endif
2473 return color_chooser_.get();
2474 }
2475
2476 void Browser::DidEndColorChooser() {
2477 color_chooser_.reset();
2478 }
2479
2480 void Browser::RunFileChooser(WebContents* web_contents,
2481 const content::FileChooserParams& params) {
2482 FileSelectHelper::RunFileChooser(web_contents, params);
2483 }
2484
2485 void Browser::EnumerateDirectory(WebContents* web_contents,
2486 int request_id,
2487 const FilePath& path) {
2488 FileSelectHelper::EnumerateDirectory(web_contents, request_id, path);
2489 }
2490
2491 void Browser::ToggleFullscreenModeForTab(WebContents* web_contents,
2492 bool enter_fullscreen) {
2493 fullscreen_controller_->ToggleFullscreenModeForTab(web_contents,
2494 enter_fullscreen);
2495 }
2496
2497 bool Browser::IsFullscreenForTabOrPending(
2498 const WebContents* web_contents) const {
2499 return fullscreen_controller_->IsFullscreenForTabOrPending(web_contents);
2500 }
2501
2502 void Browser::JSOutOfMemory(WebContents* web_contents) {
2503 JSOutOfMemoryHelper(web_contents);
2504 }
2505
2506 void Browser::RegisterProtocolHandler(WebContents* web_contents,
2507 const std::string& protocol,
2508 const GURL& url,
2509 const string16& title,
2510 bool user_gesture) {
2511 RegisterProtocolHandlerHelper(
2512 web_contents, protocol, url, title, user_gesture);
2513 }
2514
2515 void Browser::RegisterIntentHandler(
2516 WebContents* web_contents,
2517 const webkit_glue::WebIntentServiceData& data,
2518 bool user_gesture) {
2519 RegisterIntentHandlerHelper(web_contents, data, user_gesture);
2520 }
2521
2522 void Browser::WebIntentDispatch(
2523 WebContents* web_contents,
2524 content::WebIntentsDispatcher* intents_dispatcher) {
2525 if (!web_intents::IsWebIntentsEnabledForProfile(profile_))
2526 return;
2527
2528 UMA_HISTOGRAM_COUNTS("WebIntents.Dispatch", 1);
2529
2530 TabContents* tab_contents = TabContents::FromWebContents(web_contents);
2531 tab_contents->web_intent_picker_controller()->SetIntentsDispatcher(
2532 intents_dispatcher);
2533 tab_contents->web_intent_picker_controller()->ShowDialog(
2534 intents_dispatcher->GetIntent().action,
2535 intents_dispatcher->GetIntent().type);
2536 }
2537
2538 void Browser::UpdatePreferredSize(WebContents* source,
2539 const gfx::Size& pref_size) {
2540 window_->UpdatePreferredSize(source, pref_size);
2541 }
2542
2543 void Browser::ResizeDueToAutoResize(WebContents* source,
2544 const gfx::Size& new_size) {
2545 window_->ResizeDueToAutoResize(source, new_size);
2546 }
2547
2548 void Browser::FindReply(WebContents* web_contents,
2549 int request_id,
2550 int number_of_matches,
2551 const gfx::Rect& selection_rect,
2552 int active_match_ordinal,
2553 bool final_update) {
2554 FindReplyHelper(web_contents, request_id, number_of_matches, selection_rect,
2555 active_match_ordinal, final_update);
2556 }
2557
2558 void Browser::RequestToLockMouse(WebContents* web_contents,
2559 bool user_gesture,
2560 bool last_unlocked_by_target) {
2561 fullscreen_controller_->RequestToLockMouse(web_contents,
2562 user_gesture,
2563 last_unlocked_by_target);
2564 }
2565
2566 void Browser::LostMouseLock() {
2567 fullscreen_controller_->LostMouseLock();
2568 }
2569
2570 void Browser::RequestMediaAccessPermission(
2571 content::WebContents* web_contents,
2572 const content::MediaStreamRequest* request,
2573 const content::MediaResponseCallback& callback) {
2574 TabContents* tab = TabContents::FromWebContents(web_contents);
2575 DCHECK(tab);
2576
2577 scoped_ptr<MediaStreamDevicesController>
2578 controller(new MediaStreamDevicesController(tab->profile(),
2579 request,
2580 callback));
2581 if (!controller->DismissInfoBarAndTakeActionOnSettings()) {
2582 InfoBarTabHelper* infobar_helper = tab->infobar_tab_helper();
2583 InfoBarDelegate* old_infobar = NULL;
2584 for (size_t i = 0; i < infobar_helper->infobar_count(); ++i) {
2585 old_infobar = infobar_helper->GetInfoBarDelegateAt(i)->
2586 AsMediaStreamInfoBarDelegate();
2587 if (old_infobar)
2588 break;
2589 }
2590
2591 InfoBarDelegate* infobar =
2592 new MediaStreamInfoBarDelegate(infobar_helper, controller.release());
2593 if (old_infobar)
2594 infobar_helper->ReplaceInfoBar(old_infobar, infobar);
2595 else
2596 infobar_helper->AddInfoBar(infobar);
2597 }
2598 }
2599
2600 ///////////////////////////////////////////////////////////////////////////////
2601 // Browser, CoreTabHelperDelegate implementation:
2602
2603 void Browser::SwapTabContents(TabContents* old_tab_contents,
2604 TabContents* new_tab_contents) {
2605 int index = tab_strip_model_->GetIndexOfTabContents(old_tab_contents);
2606 DCHECK_NE(TabStripModel::kNoTab, index);
2607 tab_strip_model_->ReplaceTabContentsAt(index, new_tab_contents);
2608 }
2609
2610 bool Browser::CanReloadContents(TabContents* source) const {
2611 return !is_devtools();
2612 }
2613
2614 bool Browser::CanSaveContents(TabContents* source) const {
2615 return !is_devtools();
2616 }
2617
2618 ///////////////////////////////////////////////////////////////////////////////
2619 // Browser, SearchEngineTabHelperDelegate implementation:
2620
2621 void Browser::ConfirmAddSearchProvider(TemplateURL* template_url,
2622 Profile* profile) {
2623 window()->ConfirmAddSearchProvider(template_url, profile);
2624 }
2625
2626 ///////////////////////////////////////////////////////////////////////////////
2627 // Browser, ConstrainedWindowTabHelperDelegate implementation:
2628
2629 void Browser::SetTabContentBlocked(TabContents* tab_contents, bool blocked) {
2630 int index = tab_strip_model_->GetIndexOfTabContents(tab_contents);
2631 if (index == TabStripModel::kNoTab) {
2632 NOTREACHED();
2633 return;
2634 }
2635 tab_strip_model_->SetTabBlocked(index, blocked);
2636 UpdatePrintingState(tab_contents->web_contents()->GetContentRestrictions());
2637 if (!blocked && GetActiveTabContents() == tab_contents)
2638 tab_contents->web_contents()->Focus();
2639 }
2640
2641 ///////////////////////////////////////////////////////////////////////////////
2642 // Browser, BlockedContentTabHelperDelegate implementation:
2643
2644 TabContents* Browser::GetConstrainingTabContents(TabContents* source) {
2645 return source;
2646 }
2647
2648 ///////////////////////////////////////////////////////////////////////////////
2649 // Browser, BookmarkTabHelperDelegate implementation:
2650
2651 void Browser::URLStarredChanged(TabContents* source, bool starred) {
2652 if (source == GetActiveTabContents())
2653 window_->SetStarredState(starred);
2654 }
2655
2656 ///////////////////////////////////////////////////////////////////////////////
2657 // Browser, ZoomObserver implementation:
2658
2659 void Browser::OnZoomIconChanged(TabContents* source,
2660 ZoomController::ZoomIconState state) {
2661 if (source == GetActiveTabContents())
2662 window_->SetZoomIconState(state);
2663 }
2664
2665 void Browser::OnZoomChanged(TabContents* source,
2666 int zoom_percent,
2667 bool can_show_bubble) {
2668 if (source == GetActiveTabContents()) {
2669 window_->SetZoomIconTooltipPercent(zoom_percent);
2670
2671 // Only show the zoom bubble for zoom changes in the active window.
2672 if (can_show_bubble && window_->IsActive())
2673 window_->ShowZoomBubble(zoom_percent);
2674 }
2675 }
2676
2677 ///////////////////////////////////////////////////////////////////////////////
2678 // Browser, ExtensionTabHelperDelegate implementation:
2679
2680 void Browser::OnDidGetApplicationInfo(TabContents* source,
2681 int32 page_id) {
2682 if (GetActiveTabContents() != source)
2683 return;
2684
2685 NavigationEntry* entry =
2686 source->web_contents()->GetController().GetLastCommittedEntry();
2687 if (!entry || (entry->GetPageID() != page_id))
2688 return;
2689
2690 switch (pending_web_app_action_) {
2691 case CREATE_SHORTCUT: {
2692 window()->ShowCreateWebAppShortcutsDialog(source);
2693 break;
2694 }
2695 case UPDATE_SHORTCUT: {
2696 web_app::UpdateShortcutForTabContents(source);
2697 break;
2698 }
2699 default:
2700 NOTREACHED();
2701 break;
2702 }
2703
2704 pending_web_app_action_ = NONE;
2705 }
2706
2707 void Browser::OnInstallApplication(TabContents* source,
2708 const WebApplicationInfo& web_app) {
2709 ExtensionService* extension_service = profile()->GetExtensionService();
2710 if (!extension_service)
2711 return;
2712
2713 scoped_refptr<CrxInstaller> installer(CrxInstaller::Create(
2714 extension_service,
2715 extension_service->show_extensions_prompts() ?
2716 new ExtensionInstallPrompt(this) : NULL));
2717 installer->InstallWebApp(web_app);
2718 }
2719
2720 ///////////////////////////////////////////////////////////////////////////////
2721 // Browser, SelectFileDialog::Listener implementation:
2722
2723 void Browser::FileSelected(const FilePath& path, int index, void* params) {
2724 profile_->set_last_selected_directory(path.DirName());
2725 GURL file_url = net::FilePathToFileURL(path);
2726
2727 #if defined(OS_CHROMEOS)
2728 gdata::util::ModifyGDataFileResourceUrl(profile_, path, &file_url);
2729 #endif
2730
2731 if (file_url.is_empty())
2732 return;
2733
2734 OpenURL(OpenURLParams(
2735 file_url, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
2736 false));
2737 }
2738
2739 ///////////////////////////////////////////////////////////////////////////////
2740 // Browser, content::NotificationObserver implementation:
2741
2742 void Browser::Observe(int type,
2743 const content::NotificationSource& source,
2744 const content::NotificationDetails& details) {
2745 switch (type) { 577 switch (type) {
2746 case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED: 578 case NOTIFICATION_PREF_CHANGED: {
2747 if (is_attempting_to_close_browser_) {
2748 // Pass in false so that we delay processing. We need to delay the
2749 // processing as it may close the tab, which is currently on the call
2750 // stack above us.
2751 ClearUnloadState(content::Source<WebContents>(source).ptr(), false);
2752 }
2753 break;
2754
2755 case content::NOTIFICATION_SSL_VISIBLE_STATE_CHANGED:
2756 // When the current tab's SSL state changes, we need to update the URL
2757 // bar to reflect the new state. Note that it's possible for the selected
2758 // tab contents to be NULL. This is because we listen for all sources
2759 // (NavigationControllers) for convenience, so the notification could
2760 // actually be for a different window while we're doing asynchronous
2761 // closing of this one.
2762 if (GetActiveWebContents() &&
2763 &GetActiveWebContents()->GetController() ==
2764 content::Source<NavigationController>(source).ptr())
2765 UpdateToolbar(false);
2766 break;
2767
2768 case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
2769 if (window()->GetLocationBar())
2770 window()->GetLocationBar()->UpdatePageActions();
2771
2772 // Close any tabs from the unloaded extension, unless it's terminated,
2773 // in which case let the sad tabs remain.
2774 if (content::Details<extensions::UnloadedExtensionInfo>(
2775 details)->reason != extension_misc::UNLOAD_REASON_TERMINATE) {
2776 const Extension* extension =
2777 content::Details<extensions::UnloadedExtensionInfo>(
2778 details)->extension;
2779 for (int i = tab_strip_model_->count() - 1; i >= 0; --i) {
2780 WebContents* tc =
2781 tab_strip_model_->GetTabContentsAt(i)->web_contents();
2782 bool close_tab_contents =
2783 tc->GetURL().SchemeIs(chrome::kExtensionScheme) &&
2784 tc->GetURL().host() == extension->id();
2785 // We want to close all panels originated by the unloaded extension.
2786 close_tab_contents = close_tab_contents ||
2787 (type_ == TYPE_PANEL &&
2788 (web_app::GetExtensionIdFromApplicationName(app_name_) ==
2789 extension->id()));
2790 if (close_tab_contents) {
2791 CloseTabContents(tc);
2792 }
2793 }
2794 }
2795 break;
2796 }
2797
2798 case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: {
2799 Profile* profile = content::Source<Profile>(source).ptr();
2800 if (profile_->IsSameProfile(profile) && window()->GetLocationBar())
2801 window()->GetLocationBar()->InvalidatePageActions();
2802 break;
2803 }
2804
2805 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
2806 case chrome::NOTIFICATION_EXTENSION_LOADED:
2807 // During window creation on Windows we may end up calling into
2808 // SHAppBarMessage, which internally spawns a nested message loop. This
2809 // makes it possible for us to end up here before window creation has
2810 // completed,at which point window_ is NULL. See 94752 for details.
2811 if (window() && window()->GetLocationBar())
2812 window()->GetLocationBar()->UpdatePageActions();
2813 break;
2814
2815 #if defined(ENABLE_THEMES)
2816 case chrome::NOTIFICATION_BROWSER_THEME_CHANGED:
2817 window()->UserChangedTheme();
2818 break;
2819 #endif
2820
2821 case chrome::NOTIFICATION_PREF_CHANGED: {
2822 const std::string& pref_name = 579 const std::string& pref_name =
2823 *content::Details<std::string>(details).ptr(); 580 *content::Details<std::string>(details).ptr();
2824 if (pref_name == prefs::kPrintingEnabled) { 581 if (pref_name == prefs::kPrintingEnabled) {
2825 UpdatePrintingState(GetContentRestrictionsForSelectedTab()); 582 UpdatePrintingState();
2826 } else if (pref_name == prefs::kInstantEnabled) {
2827 if (browser_shutdown::ShuttingDownWithoutClosingBrowsers() ||
2828 !InstantController::IsEnabled(profile())) {
2829 if (instant()) {
2830 instant()->DestroyPreviewContents();
2831 instant_.reset();
2832 instant_unload_handler_.reset();
2833 }
2834 } else {
2835 CreateInstantIfNecessary();
2836 }
2837 } else if (pref_name == prefs::kIncognitoModeAvailability) { 583 } else if (pref_name == prefs::kIncognitoModeAvailability) {
2838 UpdateCommandsForIncognitoAvailability(); 584 UpdateCommandsForIncognitoAvailability();
2839 } else if (pref_name == prefs::kDevToolsDisabled) { 585 } else if (pref_name == prefs::kDevToolsDisabled) {
2840 UpdateCommandsForDevTools(); 586 UpdateCommandsForDevTools();
2841 if (profile_->GetPrefs()->GetBoolean(prefs::kDevToolsDisabled))
2842 content::DevToolsManager::GetInstance()->CloseAllClientHosts();
2843 } else if (pref_name == prefs::kEditBookmarksEnabled) { 587 } else if (pref_name == prefs::kEditBookmarksEnabled) {
2844 UpdateCommandsForBookmarkEditing(); 588 UpdateCommandsForBookmarkEditing();
2845 } else if (pref_name == prefs::kShowBookmarkBar) { 589 } else if (pref_name == prefs::kShowBookmarkBar) {
2846 UpdateCommandsForBookmarkBar(); 590 UpdateCommandsForBookmarkBar();
2847 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_PREF_CHANGE);
2848 } else if (pref_name == prefs::kHomePage) {
2849 PrefService* pref_service = content::Source<PrefService>(source).ptr();
2850 MarkHomePageAsChanged(pref_service);
2851 } else if (pref_name == prefs::kAllowFileSelectionDialogs) { 591 } else if (pref_name == prefs::kAllowFileSelectionDialogs) {
2852 UpdateSaveAsState(GetContentRestrictionsForSelectedTab()); 592 UpdateSaveAsState();
2853 UpdateOpenFileState(); 593 UpdateOpenFileState();
2854 } else if (pref_name == prefs::kInManagedMode) { 594 } else if (pref_name == prefs::kInManagedMode) {
2855 UpdateCommandsForMultipleProfiles(); 595 UpdateCommandsForMultipleProfiles();
2856 } else { 596 } else {
2857 NOTREACHED(); 597 NOTREACHED();
2858 } 598 }
2859 break; 599 break;
2860 } 600 }
2861
2862 case chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED: {
2863 WebContents* web_contents = content::Source<WebContents>(source).ptr();
2864 if (web_contents == GetActiveWebContents()) {
2865 LocationBar* location_bar = window()->GetLocationBar();
2866 if (location_bar)
2867 location_bar->UpdateContentSettingsIcons();
2868 }
2869 break;
2870 }
2871
2872 case content::NOTIFICATION_INTERSTITIAL_ATTACHED: 601 case content::NOTIFICATION_INTERSTITIAL_ATTACHED:
2873 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_STATE);
2874 UpdateCommandsForTabState(); 602 UpdateCommandsForTabState();
2875 break; 603 break;
2876 604
2877 case content::NOTIFICATION_INTERSTITIAL_DETACHED: 605 case content::NOTIFICATION_INTERSTITIAL_DETACHED:
2878 UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_TAB_STATE);
2879 UpdateCommandsForTabState(); 606 UpdateCommandsForTabState();
2880 break; 607 break;
2881 608
2882 default: 609 default:
2883 NOTREACHED() << "Got a notification we didn't register for."; 610 NOTREACHED() << "Got a notification we didn't register for.";
2884 } 611 }
2885 } 612 }
2886 613
2887 /////////////////////////////////////////////////////////////////////////////// 614 ////////////////////////////////////////////////////////////////////////////////
2888 // Browser, ProfileSyncServiceObserver implementation: 615 // BrowserCommandController, TabStripModelObserver implementation:
2889 616
2890 void Browser::OnStateChanged() { 617 void BrowserCommandController::TabInsertedAt(TabContents* contents,
2891 DCHECK(ProfileSyncServiceFactory::GetInstance()->HasProfileSyncService( 618 int index,
2892 profile_)); 619 bool foreground) {
2893 // For unit tests, we don't have a window. 620 AddInterstitialObservers(contents);
2894 if (!window_)
2895 return;
2896 const bool show_main_ui = IsShowingMainUI(window_->IsFullscreen());
2897 command_updater_.UpdateCommandEnabled(IDC_SHOW_SYNC_SETUP,
2898 show_main_ui && profile_->GetOriginalProfile()->IsSyncAccessible());
2899 } 621 }
2900 622
2901 /////////////////////////////////////////////////////////////////////////////// 623 void BrowserCommandController::TabDetachedAt(TabContents* contents, int index) {
2902 // Browser, InstantDelegate implementation: 624 RemoveInterstitialObservers(contents);
2903
2904 void Browser::ShowInstant(TabContents* preview_contents) {
2905 window_->ShowInstant(preview_contents);
2906
2907 // TODO(beng): investigate if we can avoid this and instead rely on the
2908 // visibility of the WebContentsView
2909 GetActiveWebContents()->WasHidden();
2910 preview_contents->web_contents()->WasRestored();
2911 } 625 }
2912 626
2913 void Browser::HideInstant() { 627 void BrowserCommandController::TabReplacedAt(TabStripModel* tab_strip_model,
2914 window_->HideInstant(); 628 TabContents* old_contents,
2915 if (GetActiveWebContents()) 629 TabContents* new_contents,
2916 GetActiveWebContents()->WasRestored(); 630 int index) {
2917 if (instant_->GetPreviewContents()) 631 RemoveInterstitialObservers(old_contents);
2918 instant_->GetPreviewContents()->web_contents()->WasHidden(); 632 AddInterstitialObservers(new_contents);
2919 } 633 }
2920 634
2921 void Browser::CommitInstant(TabContents* preview_contents) { 635 ////////////////////////////////////////////////////////////////////////////////
2922 TabContents* tab_contents = GetActiveTabContents(); 636 // BrowserCommandController, TabRestoreServiceObserver implementation:
2923 int index = tab_strip_model_->GetIndexOfTabContents(tab_contents);
2924 DCHECK_NE(TabStripModel::kNoTab, index);
2925 // TabStripModel takes ownership of preview_contents.
2926 tab_strip_model_->ReplaceTabContentsAt(index, preview_contents);
2927 // InstantUnloadHandler takes ownership of tab_contents.
2928 instant_unload_handler_->RunUnloadListenersOrDestroy(tab_contents, index);
2929 637
2930 GURL url = preview_contents->web_contents()->GetURL(); 638 void BrowserCommandController::TabRestoreServiceChanged(
2931 DCHECK(profile_->GetExtensionService()); 639 TabRestoreService* service) {
2932 if (profile_->GetExtensionService()->IsInstalledApp(url)) { 640 command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB,
2933 AppLauncherHandler::RecordAppLaunchType( 641 CanRestoreTab(browser_));
2934 extension_misc::APP_LAUNCH_OMNIBOX_INSTANT);
2935 }
2936 } 642 }
2937 643
2938 void Browser::SetSuggestedText(const string16& text, 644 void BrowserCommandController::TabRestoreServiceDestroyed(
2939 InstantCompleteBehavior behavior) { 645 TabRestoreService* service) {
2940 if (window()->GetLocationBar()) 646 service->RemoveObserver(this);
2941 window()->GetLocationBar()->SetSuggestedText(text, behavior);
2942 } 647 }
2943 648
2944 gfx::Rect Browser::GetInstantBounds() { 649 ////////////////////////////////////////////////////////////////////////////////
2945 return window()->GetInstantBounds(); 650 // BrowserCommandController, ProfileSyncServiceObserver implementation:
651
652 void BrowserCommandController::OnStateChanged() {
653 DCHECK(ProfileSyncServiceFactory::GetInstance()->HasProfileSyncService(
654 profile()));
655 // For unit tests, we don't have a window.
656 if (!window())
657 return;
658 const bool show_main_ui = IsShowingMainUI(window()->IsFullscreen());
659 command_updater_.UpdateCommandEnabled(IDC_SHOW_SYNC_SETUP,
660 show_main_ui && profile()->GetOriginalProfile()->IsSyncAccessible());
2946 } 661 }
2947 662
2948 void Browser::InstantPreviewFocused() { 663 ////////////////////////////////////////////////////////////////////////////////
2949 // NOTE: This is only invoked on aura. 664 // BrowserCommandController, private:
2950 window_->WebContentsFocused(instant_->GetPreviewContents()->web_contents());
2951 }
2952 665
2953 TabContents* Browser::GetInstantHostTabContents() const { 666 bool BrowserCommandController::IsShowingMainUI(bool is_fullscreen) {
2954 return GetActiveTabContents();
2955 }
2956
2957 ///////////////////////////////////////////////////////////////////////////////
2958 // Browser, Command and state updating (private):
2959
2960 bool Browser::IsShowingMainUI(bool is_fullscreen) {
2961 #if !defined(OS_MACOSX) 667 #if !defined(OS_MACOSX)
2962 return is_type_tabbed() && !is_fullscreen; 668 return browser_->is_type_tabbed() && !is_fullscreen;
2963 #else 669 #else
2964 return is_type_tabbed(); 670 return browser_->is_type_tabbed();
2965 #endif 671 #endif
2966 } 672 }
2967 673
2968 void Browser::InitCommandState() { 674 void BrowserCommandController::InitCommandState() {
2969 // All browser commands whose state isn't set automagically some other way 675 // All browser commands whose state isn't set automagically some other way
2970 // (like Back & Forward with initial page load) must have their state 676 // (like Back & Forward with initial page load) must have their state
2971 // initialized here, otherwise they will be forever disabled. 677 // initialized here, otherwise they will be forever disabled.
2972 678
2973 // Navigation commands 679 // Navigation commands
2974 command_updater_.UpdateCommandEnabled(IDC_RELOAD, true); 680 command_updater_.UpdateCommandEnabled(IDC_RELOAD, true);
2975 command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE, true); 681 command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE, true);
2976 682
2977 // Window management commands 683 // Window management commands
2978 command_updater_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true); 684 command_updater_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true);
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
3027 // Zoom 733 // Zoom
3028 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, true); 734 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, true);
3029 command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true); 735 command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true);
3030 command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, true); 736 command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, true);
3031 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true); 737 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true);
3032 738
3033 // Show various bits of UI 739 // Show various bits of UI
3034 UpdateOpenFileState(); 740 UpdateOpenFileState();
3035 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false); 741 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false);
3036 UpdateCommandsForDevTools(); 742 UpdateCommandsForDevTools();
3037 command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, 743 command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, CanOpenTaskManager());
3038 chrome::CanOpenTaskManager());
3039 command_updater_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true); 744 command_updater_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true);
3040 command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true); 745 command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
3041 command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE_VIA_KEYBOARD, true); 746 command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE_VIA_KEYBOARD, true);
3042 command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE_VIA_MENU, true); 747 command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE_VIA_MENU, true);
3043 command_updater_.UpdateCommandEnabled(IDC_BOOKMARKS_MENU, true); 748 command_updater_.UpdateCommandEnabled(IDC_BOOKMARKS_MENU, true);
3044 749
3045 command_updater_.UpdateCommandEnabled( 750 command_updater_.UpdateCommandEnabled(
3046 IDC_SHOW_SYNC_SETUP, profile_->GetOriginalProfile()->IsSyncAccessible()); 751 IDC_SHOW_SYNC_SETUP, profile()->GetOriginalProfile()->IsSyncAccessible());
3047 752
3048 // Initialize other commands based on the window type. 753 // Initialize other commands based on the window type.
3049 bool normal_window = is_type_tabbed(); 754 bool normal_window = browser_->is_type_tabbed();
3050 755
3051 // Navigation commands 756 // Navigation commands
3052 command_updater_.UpdateCommandEnabled(IDC_HOME, normal_window); 757 command_updater_.UpdateCommandEnabled(IDC_HOME, normal_window);
3053 758
3054 // Window management commands 759 // Window management commands
3055 // TODO(rohitrao): Disable fullscreen on non-Lion? 760 // TODO(rohitrao): Disable fullscreen on non-Lion?
3056 command_updater_.UpdateCommandEnabled(IDC_FULLSCREEN, 761 command_updater_.UpdateCommandEnabled(IDC_FULLSCREEN,
3057 !(is_type_panel() && is_app())); 762 !(browser_->is_type_panel() && browser_->is_app()));
3058 command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window); 763 command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window);
3059 command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB, 764 command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB,
3060 normal_window); 765 normal_window);
3061 command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_NEXT, normal_window); 766 command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_NEXT, normal_window);
3062 command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_PREVIOUS, normal_window); 767 command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_PREVIOUS, normal_window);
3063 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_0, normal_window); 768 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_0, normal_window);
3064 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_1, normal_window); 769 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_1, normal_window);
3065 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_2, normal_window); 770 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_2, normal_window);
3066 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_3, normal_window); 771 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_3, normal_window);
3067 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_4, normal_window); 772 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_4, normal_window);
3068 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_5, normal_window); 773 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_5, normal_window);
3069 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window); 774 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window);
3070 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window); 775 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window);
3071 command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window); 776 command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window);
3072 #if defined(OS_WIN) 777 #if defined(OS_WIN)
3073 const bool metro_mode = base::win::IsMetroProcess(); 778 const bool metro_mode = base::win::IsMetroProcess();
3074 command_updater_.UpdateCommandEnabled(IDC_METRO_SNAP_ENABLE, metro_mode); 779 command_updater_.UpdateCommandEnabled(IDC_METRO_SNAP_ENABLE, metro_mode);
3075 command_updater_.UpdateCommandEnabled(IDC_METRO_SNAP_DISABLE, metro_mode); 780 command_updater_.UpdateCommandEnabled(IDC_METRO_SNAP_DISABLE, metro_mode);
3076 #endif 781 #endif
3077 #if defined(OS_MACOSX) 782 #if defined(OS_MACOSX)
3078 command_updater_.UpdateCommandEnabled(IDC_TABPOSE, normal_window); 783 command_updater_.UpdateCommandEnabled(IDC_TABPOSE, normal_window);
3079 command_updater_.UpdateCommandEnabled(IDC_PRESENTATION_MODE, 784 command_updater_.UpdateCommandEnabled(IDC_PRESENTATION_MODE,
3080 !(is_type_panel() && is_app())); 785 !(browser_->is_type_panel() && browser_->is_app()));
3081 #endif 786 #endif
3082 787
3083 // Clipboard commands 788 // Clipboard commands
3084 command_updater_.UpdateCommandEnabled(IDC_COPY_URL, !is_devtools()); 789 command_updater_.UpdateCommandEnabled(IDC_COPY_URL, !browser_->is_devtools());
3085 790
3086 // Find-in-page 791 // Find-in-page
3087 command_updater_.UpdateCommandEnabled(IDC_FIND, !is_devtools()); 792 command_updater_.UpdateCommandEnabled(IDC_FIND, !browser_->is_devtools());
3088 command_updater_.UpdateCommandEnabled(IDC_FIND_NEXT, !is_devtools()); 793 command_updater_.UpdateCommandEnabled(IDC_FIND_NEXT,
3089 command_updater_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, !is_devtools()); 794 !browser_->is_devtools());
795 command_updater_.UpdateCommandEnabled(IDC_FIND_PREVIOUS,
796 !browser_->is_devtools());
3090 797
3091 // Show various bits of UI 798 // Show various bits of UI
3092 command_updater_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA, normal_window); 799 command_updater_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA, normal_window);
3093 800
3094 // The upgrade entry and the view incompatibility entry should always be 801 // The upgrade entry and the view incompatibility entry should always be
3095 // enabled. Whether they are visible is a separate matter determined on menu 802 // enabled. Whether they are visible is a separate matter determined on menu
3096 // show. 803 // show.
3097 command_updater_.UpdateCommandEnabled(IDC_UPGRADE_DIALOG, true); 804 command_updater_.UpdateCommandEnabled(IDC_UPGRADE_DIALOG, true);
3098 command_updater_.UpdateCommandEnabled(IDC_VIEW_INCOMPATIBILITIES, true); 805 command_updater_.UpdateCommandEnabled(IDC_VIEW_INCOMPATIBILITIES, true);
3099 806
3100 // View Background Pages entry is always enabled, but is hidden if there are 807 // View Background Pages entry is always enabled, but is hidden if there are
3101 // no background pages. 808 // no background pages.
3102 command_updater_.UpdateCommandEnabled(IDC_VIEW_BACKGROUND_PAGES, true); 809 command_updater_.UpdateCommandEnabled(IDC_VIEW_BACKGROUND_PAGES, true);
3103 810
3104 // Toggle speech input 811 // Toggle speech input
3105 command_updater_.UpdateCommandEnabled(IDC_TOGGLE_SPEECH_INPUT, true); 812 command_updater_.UpdateCommandEnabled(IDC_TOGGLE_SPEECH_INPUT, true);
3106 813
3107 // Initialize other commands whose state changes based on fullscreen mode. 814 // Initialize other commands whose state changes based on fullscreen mode.
3108 UpdateCommandsForFullscreenMode(FULLSCREEN_DISABLED); 815 UpdateCommandsForFullscreenMode(FULLSCREEN_DISABLED);
3109 816
3110 UpdateCommandsForContentRestrictionState(); 817 UpdateCommandsForContentRestrictionState();
3111 818
3112 UpdateCommandsForBookmarkEditing(); 819 UpdateCommandsForBookmarkEditing();
3113 820
3114 UpdateCommandsForIncognitoAvailability(); 821 UpdateCommandsForIncognitoAvailability();
3115 } 822 }
3116 823
3117 void Browser::UpdateCommandsForIncognitoAvailability() { 824 void BrowserCommandController::UpdateCommandsForIncognitoAvailability() {
3118 IncognitoModePrefs::Availability incognito_availability = 825 IncognitoModePrefs::Availability incognito_availability =
3119 IncognitoModePrefs::GetAvailability(profile_->GetPrefs()); 826 IncognitoModePrefs::GetAvailability(profile()->GetPrefs());
3120 command_updater_.UpdateCommandEnabled( 827 command_updater_.UpdateCommandEnabled(
3121 IDC_NEW_WINDOW, 828 IDC_NEW_WINDOW,
3122 incognito_availability != IncognitoModePrefs::FORCED); 829 incognito_availability != IncognitoModePrefs::FORCED);
3123 command_updater_.UpdateCommandEnabled( 830 command_updater_.UpdateCommandEnabled(
3124 IDC_NEW_INCOGNITO_WINDOW, 831 IDC_NEW_INCOGNITO_WINDOW,
3125 incognito_availability != IncognitoModePrefs::DISABLED); 832 incognito_availability != IncognitoModePrefs::DISABLED);
3126 833
3127 // Bookmark manager and settings page/subpages are forced to open in normal 834 // Bookmark manager and settings page/subpages are forced to open in normal
3128 // mode. For this reason we disable these commands when incognito is forced. 835 // mode. For this reason we disable these commands when incognito is forced.
3129 const bool command_enabled = 836 const bool command_enabled =
3130 incognito_availability != IncognitoModePrefs::FORCED; 837 incognito_availability != IncognitoModePrefs::FORCED;
3131 command_updater_.UpdateCommandEnabled( 838 command_updater_.UpdateCommandEnabled(
3132 IDC_SHOW_BOOKMARK_MANAGER, 839 IDC_SHOW_BOOKMARK_MANAGER,
3133 browser_defaults::bookmarks_enabled && command_enabled); 840 browser_defaults::bookmarks_enabled && command_enabled);
3134 ExtensionService* extension_service = profile()->GetExtensionService(); 841 ExtensionService* extension_service = profile()->GetExtensionService();
3135 bool enable_extensions = 842 bool enable_extensions =
3136 extension_service && extension_service->extensions_enabled(); 843 extension_service && extension_service->extensions_enabled();
3137 command_updater_.UpdateCommandEnabled(IDC_MANAGE_EXTENSIONS, 844 command_updater_.UpdateCommandEnabled(IDC_MANAGE_EXTENSIONS,
3138 enable_extensions && command_enabled); 845 enable_extensions && command_enabled);
3139 846
3140 const bool show_main_ui = IsShowingMainUI(window_ && window_->IsFullscreen()); 847 const bool show_main_ui =
848 IsShowingMainUI(window() && window()->IsFullscreen());
3141 command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, 849 command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS,
3142 show_main_ui && command_enabled); 850 show_main_ui && command_enabled);
3143 command_updater_.UpdateCommandEnabled(IDC_OPTIONS, 851 command_updater_.UpdateCommandEnabled(IDC_OPTIONS,
3144 show_main_ui && command_enabled); 852 show_main_ui && command_enabled);
3145 } 853 }
3146 854
3147 void Browser::UpdateCommandsForTabState() { 855 void BrowserCommandController::UpdateCommandsForTabState() {
3148 TabContents* current_tab_contents = GetActiveTabContents(); 856 TabContents* current_tab_contents = browser_->GetActiveTabContents();
3149 if (!current_tab_contents) // May be NULL during tab restore. 857 if (!current_tab_contents) // May be NULL during tab restore.
3150 return; 858 return;
3151 WebContents* current_web_contents = current_tab_contents->web_contents(); 859 WebContents* current_web_contents = current_tab_contents->web_contents();
3152 860
3153 // Navigation commands 861 // Navigation commands
3154 NavigationController& nc = current_web_contents->GetController(); 862 command_updater_.UpdateCommandEnabled(IDC_BACK, CanGoBack(browser_));
3155 command_updater_.UpdateCommandEnabled(IDC_BACK, nc.CanGoBack()); 863 command_updater_.UpdateCommandEnabled(IDC_FORWARD, CanGoForward(browser_));
3156 command_updater_.UpdateCommandEnabled(IDC_FORWARD, nc.CanGoForward()); 864 command_updater_.UpdateCommandEnabled(IDC_RELOAD, CanReload(browser_));
3157 command_updater_.UpdateCommandEnabled( 865 command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE,
3158 IDC_RELOAD, CanReloadContents(current_tab_contents)); 866 CanReload(browser_));
3159 command_updater_.UpdateCommandEnabled(
3160 IDC_RELOAD_IGNORING_CACHE, CanReloadContents(current_tab_contents));
3161 867
3162 // Window management commands 868 // Window management commands
3163 command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, 869 command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB,
3164 !is_app() && CanDuplicateContentsAt(active_index())); 870 !browser_->is_app() && CanDuplicateTab(browser_));
3165 871
3166 // Page-related commands 872 // Page-related commands
3167 window_->SetStarredState( 873 window()->SetStarredState(
3168 current_tab_contents->bookmark_tab_helper()->is_starred()); 874 current_tab_contents->bookmark_tab_helper()->is_starred());
3169 window_->SetZoomIconState( 875 window()->SetZoomIconState(
3170 current_tab_contents->zoom_controller()->zoom_icon_state()); 876 current_tab_contents->zoom_controller()->zoom_icon_state());
3171 window_->SetZoomIconTooltipPercent( 877 window()->SetZoomIconTooltipPercent(
3172 current_tab_contents->zoom_controller()->zoom_percent()); 878 current_tab_contents->zoom_controller()->zoom_percent());
3173 command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE, 879 command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE,
3174 current_web_contents->GetController().CanViewSource()); 880 CanViewSource(browser_));
3175 command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION, 881 command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION,
3176 toolbar_model_->ShouldDisplayURL() && 882 CanEmailPageLocation(browser_));
3177 current_web_contents->GetURL().is_valid()); 883 if (browser_->is_devtools())
3178 if (is_devtools()) 884 command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, false);
3179 command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, false);
3180 885
3181 // Changing the encoding is not possible on Chrome-internal webpages. 886 // Changing the encoding is not possible on Chrome-internal webpages.
887 NavigationController& nc = current_web_contents->GetController();
3182 bool is_chrome_internal = HasInternalURL(nc.GetActiveEntry()) || 888 bool is_chrome_internal = HasInternalURL(nc.GetActiveEntry()) ||
3183 current_web_contents->ShowingInterstitialPage(); 889 current_web_contents->ShowingInterstitialPage();
3184 command_updater_.UpdateCommandEnabled(IDC_ENCODING_MENU, 890 command_updater_.UpdateCommandEnabled(IDC_ENCODING_MENU,
3185 !is_chrome_internal && current_web_contents->IsSavable()); 891 !is_chrome_internal && current_web_contents->IsSavable());
3186 892
3187 // Show various bits of UI 893 // Show various bits of UI
3188 // TODO(pinkerton): Disable app-mode in the model until we implement it 894 // TODO(pinkerton): Disable app-mode in the model until we implement it
3189 // on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148 895 // on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148
3190 #if !defined(OS_MACOSX) 896 #if !defined(OS_MACOSX)
3191 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, 897 command_updater_.UpdateCommandEnabled(
3192 web_app::IsValidUrl(current_web_contents->GetURL())); 898 IDC_CREATE_SHORTCUTS,
899 CanCreateApplicationShortcuts(browser_));
3193 #endif 900 #endif
3194 901
3195 UpdateCommandsForContentRestrictionState(); 902 UpdateCommandsForContentRestrictionState();
3196 UpdateCommandsForBookmarkEditing(); 903 UpdateCommandsForBookmarkEditing();
3197 } 904 }
3198 905
3199 void Browser::UpdateCommandsForContentRestrictionState() { 906 void BrowserCommandController::UpdateCommandsForContentRestrictionState() {
3200 int restrictions = GetContentRestrictionsForSelectedTab(); 907 int restrictions = GetContentRestrictions(browser_);
3201 908
3202 command_updater_.UpdateCommandEnabled( 909 command_updater_.UpdateCommandEnabled(
3203 IDC_COPY, !(restrictions & content::CONTENT_RESTRICTION_COPY)); 910 IDC_COPY, !(restrictions & content::CONTENT_RESTRICTION_COPY));
3204 command_updater_.UpdateCommandEnabled( 911 command_updater_.UpdateCommandEnabled(
3205 IDC_CUT, !(restrictions & content::CONTENT_RESTRICTION_CUT)); 912 IDC_CUT, !(restrictions & content::CONTENT_RESTRICTION_CUT));
3206 command_updater_.UpdateCommandEnabled( 913 command_updater_.UpdateCommandEnabled(
3207 IDC_PASTE, !(restrictions & content::CONTENT_RESTRICTION_PASTE)); 914 IDC_PASTE, !(restrictions & content::CONTENT_RESTRICTION_PASTE));
3208 UpdateSaveAsState(restrictions); 915 UpdateSaveAsState();
3209 UpdatePrintingState(restrictions); 916 UpdatePrintingState();
3210 } 917 }
3211 918
3212 void Browser::UpdateCommandsForDevTools() { 919 void BrowserCommandController::UpdateCommandsForDevTools() {
3213 bool dev_tools_enabled = 920 bool dev_tools_enabled =
3214 !profile_->GetPrefs()->GetBoolean(prefs::kDevToolsDisabled); 921 !profile()->GetPrefs()->GetBoolean(prefs::kDevToolsDisabled);
3215 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS, 922 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS,
3216 dev_tools_enabled); 923 dev_tools_enabled);
3217 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_CONSOLE, 924 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_CONSOLE,
3218 dev_tools_enabled); 925 dev_tools_enabled);
3219 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_INSPECT, 926 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_INSPECT,
3220 dev_tools_enabled); 927 dev_tools_enabled);
3221 } 928 }
3222 929
3223 void Browser::UpdateCommandsForBookmarkEditing() { 930 void BrowserCommandController::UpdateCommandsForBookmarkEditing() {
3224 bool enabled =
3225 profile_->GetPrefs()->GetBoolean(prefs::kEditBookmarksEnabled) &&
3226 browser_defaults::bookmarks_enabled;
3227
3228 command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_PAGE, 931 command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_PAGE,
3229 enabled && is_type_tabbed()); 932 CanBookmarkCurrentPage(browser_));
3230 command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_ALL_TABS, 933 command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_ALL_TABS,
3231 enabled && CanBookmarkAllTabs()); 934 CanBookmarkAllTabs(browser_));
3232 command_updater_.UpdateCommandEnabled(IDC_PIN_TO_START_SCREEN, 935 command_updater_.UpdateCommandEnabled(IDC_PIN_TO_START_SCREEN,
3233 true); 936 true);
3234 } 937 }
3235 938
3236 void Browser::UpdateCommandsForBookmarkBar() { 939 void BrowserCommandController::UpdateCommandsForBookmarkBar() {
3237 const bool show_main_ui = IsShowingMainUI(window_ && window_->IsFullscreen()); 940 const bool show_main_ui =
941 IsShowingMainUI(window() && window()->IsFullscreen());
3238 command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR, 942 command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR,
3239 browser_defaults::bookmarks_enabled && 943 browser_defaults::bookmarks_enabled &&
3240 !profile_->GetPrefs()->IsManagedPreference(prefs::kShowBookmarkBar) && 944 !profile()->GetPrefs()->IsManagedPreference(prefs::kShowBookmarkBar) &&
3241 show_main_ui); 945 show_main_ui);
3242 } 946 }
3243 947
3244 void Browser::MarkHomePageAsChanged(PrefService* pref_service) { 948 void BrowserCommandController::UpdateCommandsForFullscreenMode(
3245 pref_service->SetBoolean(prefs::kHomePageChanged, true); 949 FullScreenMode fullscreen_mode) {
3246 }
3247
3248 void Browser::UpdateCommandsForFullscreenMode(FullScreenMode fullscreen_mode) {
3249 const bool show_main_ui = 950 const bool show_main_ui =
3250 IsShowingMainUI(fullscreen_mode != FULLSCREEN_DISABLED); 951 IsShowingMainUI(fullscreen_mode != FULLSCREEN_DISABLED);
3251 bool main_not_fullscreen = show_main_ui && 952 bool main_not_fullscreen = show_main_ui &&
3252 (fullscreen_mode == FULLSCREEN_DISABLED); 953 (fullscreen_mode == FULLSCREEN_DISABLED);
3253 954
3254 // Navigation commands 955 // Navigation commands
3255 command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, show_main_ui); 956 command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, show_main_ui);
3256 957
3257 // Window management commands 958 // Window management commands
3258 command_updater_.UpdateCommandEnabled(IDC_SHOW_AS_TAB, 959 command_updater_.UpdateCommandEnabled(
3259 type_ != TYPE_TABBED && (fullscreen_mode == FULLSCREEN_DISABLED)); 960 IDC_SHOW_AS_TAB,
961 !browser_->is_type_tabbed() && fullscreen_mode == FULLSCREEN_DISABLED);
3260 962
3261 // Focus various bits of UI 963 // Focus various bits of UI
3262 command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, show_main_ui); 964 command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, show_main_ui);
3263 command_updater_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, show_main_ui); 965 command_updater_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, show_main_ui);
3264 command_updater_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, show_main_ui); 966 command_updater_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, show_main_ui);
3265 command_updater_.UpdateCommandEnabled( 967 command_updater_.UpdateCommandEnabled(
3266 IDC_FOCUS_MENU_BAR, main_not_fullscreen); 968 IDC_FOCUS_MENU_BAR, main_not_fullscreen);
3267 command_updater_.UpdateCommandEnabled( 969 command_updater_.UpdateCommandEnabled(
3268 IDC_FOCUS_NEXT_PANE, main_not_fullscreen); 970 IDC_FOCUS_NEXT_PANE, main_not_fullscreen);
3269 command_updater_.UpdateCommandEnabled( 971 command_updater_.UpdateCommandEnabled(
3270 IDC_FOCUS_PREVIOUS_PANE, main_not_fullscreen); 972 IDC_FOCUS_PREVIOUS_PANE, main_not_fullscreen);
3271 command_updater_.UpdateCommandEnabled( 973 command_updater_.UpdateCommandEnabled(
3272 IDC_FOCUS_BOOKMARKS, main_not_fullscreen); 974 IDC_FOCUS_BOOKMARKS, main_not_fullscreen);
3273 975
3274 // Show various bits of UI 976 // Show various bits of UI
3275 command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, show_main_ui); 977 command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, show_main_ui);
3276 command_updater_.UpdateCommandEnabled(IDC_FEEDBACK, show_main_ui); 978 command_updater_.UpdateCommandEnabled(IDC_FEEDBACK, show_main_ui);
3277 command_updater_.UpdateCommandEnabled(IDC_SHOW_SYNC_SETUP, 979 command_updater_.UpdateCommandEnabled(IDC_SHOW_SYNC_SETUP,
3278 show_main_ui && profile_->GetOriginalProfile()->IsSyncAccessible()); 980 show_main_ui && profile()->GetOriginalProfile()->IsSyncAccessible());
3279 981
3280 // Settings page/subpages are forced to open in normal mode. We disable these 982 // Settings page/subpages are forced to open in normal mode. We disable these
3281 // commands when incognito is forced. 983 // commands when incognito is forced.
3282 const bool options_enabled = show_main_ui && 984 const bool options_enabled = show_main_ui &&
3283 IncognitoModePrefs::GetAvailability( 985 IncognitoModePrefs::GetAvailability(
3284 profile_->GetPrefs()) != IncognitoModePrefs::FORCED; 986 profile()->GetPrefs()) != IncognitoModePrefs::FORCED;
3285 command_updater_.UpdateCommandEnabled(IDC_OPTIONS, options_enabled); 987 command_updater_.UpdateCommandEnabled(IDC_OPTIONS, options_enabled);
3286 command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, options_enabled); 988 command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, options_enabled);
3287 989
3288 command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui); 990 command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui);
3289 command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui); 991 command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui);
3290 command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui); 992 command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui);
3291 command_updater_.UpdateCommandEnabled(IDC_SHOW_APP_MENU, show_main_ui); 993 command_updater_.UpdateCommandEnabled(IDC_SHOW_APP_MENU, show_main_ui);
3292 #if defined (ENABLE_PROFILING) && !defined(NO_TCMALLOC) 994 #if defined (ENABLE_PROFILING) && !defined(NO_TCMALLOC)
3293 command_updater_.UpdateCommandEnabled(IDC_PROFILING_ENABLED, show_main_ui); 995 command_updater_.UpdateCommandEnabled(IDC_PROFILING_ENABLED, show_main_ui);
3294 #endif 996 #endif
3295 997
3296 // Disable explicit fullscreen toggling when in metro snap mode. 998 // Disable explicit fullscreen toggling when in metro snap mode.
3297 command_updater_.UpdateCommandEnabled( 999 command_updater_.UpdateCommandEnabled(
3298 IDC_FULLSCREEN, 1000 IDC_FULLSCREEN,
3299 fullscreen_mode != FULLSCREEN_METRO_SNAP); 1001 fullscreen_mode != FULLSCREEN_METRO_SNAP);
3300 1002
3301 UpdateCommandsForBookmarkBar(); 1003 UpdateCommandsForBookmarkBar();
3302 UpdateCommandsForMultipleProfiles(); 1004 UpdateCommandsForMultipleProfiles();
3303 } 1005 }
3304 1006
3305 void Browser::UpdateCommandsForMultipleProfiles() { 1007 void BrowserCommandController::UpdateCommandsForMultipleProfiles() {
3306 bool show_main_ui = IsShowingMainUI(window_ && window_->IsFullscreen()); 1008 bool show_main_ui = IsShowingMainUI(window() && window()->IsFullscreen());
3307 command_updater_.UpdateCommandEnabled(IDC_SHOW_AVATAR_MENU, 1009 command_updater_.UpdateCommandEnabled(IDC_SHOW_AVATAR_MENU,
3308 show_main_ui && 1010 show_main_ui &&
3309 !profile()->IsOffTheRecord() && 1011 !profile()->IsOffTheRecord() &&
3310 ProfileManager::IsMultipleProfilesEnabled()); 1012 ProfileManager::IsMultipleProfilesEnabled());
3311 } 1013 }
3312 1014
3313 void Browser::UpdatePrintingState(int content_restrictions) { 1015 void BrowserCommandController::UpdatePrintingState() {
3314 bool print_enabled = true; 1016 command_updater_.UpdateCommandEnabled(IDC_PRINT, CanPrint(browser_));
3315 bool advanced_print_enabled = true;
3316 if (g_browser_process->local_state()) {
3317 print_enabled =
3318 g_browser_process->local_state()->GetBoolean(prefs::kPrintingEnabled);
3319 advanced_print_enabled = print_enabled;
3320 }
3321 if (print_enabled) {
3322 // Do not print when a constrained window is showing. It's confusing.
3323 TabContents* tab_contents = GetActiveTabContents();
3324 bool has_constrained_window =
3325 tab_contents &&
3326 tab_contents->constrained_window_tab_helper()->
3327 constrained_window_count();
3328 if (has_constrained_window ||
3329 content_restrictions & content::CONTENT_RESTRICTION_PRINT) {
3330 print_enabled = false;
3331 advanced_print_enabled = false;
3332 }
3333
3334 // The exception is print preview,
3335 // where advanced printing is always enabled.
3336 printing::PrintPreviewTabController* controller =
3337 printing::PrintPreviewTabController::GetInstance();
3338 if (controller && (controller->GetPrintPreviewForTab(tab_contents) ||
3339 controller->is_creating_print_preview_tab())) {
3340 advanced_print_enabled = true;
3341 }
3342 }
3343 command_updater_.UpdateCommandEnabled(IDC_PRINT, print_enabled);
3344 command_updater_.UpdateCommandEnabled(IDC_ADVANCED_PRINT, 1017 command_updater_.UpdateCommandEnabled(IDC_ADVANCED_PRINT,
3345 advanced_print_enabled); 1018 CanAdvancedPrint(browser_));
3346 } 1019 }
3347 1020
3348 void Browser::UpdateSaveAsState(int content_restrictions) { 1021 void BrowserCommandController::UpdateSaveAsState() {
3349 bool enabled = !(content_restrictions & content::CONTENT_RESTRICTION_SAVE); 1022 command_updater_.UpdateCommandEnabled(IDC_SAVE_PAGE, CanSavePage(browser_));
3350 enabled = enabled && CanSaveContents(GetActiveTabContents());
3351 PrefService* state = g_browser_process->local_state();
3352 if (state)
3353 enabled = enabled && state->GetBoolean(prefs::kAllowFileSelectionDialogs);
3354
3355 command_updater_.UpdateCommandEnabled(IDC_SAVE_PAGE, enabled);
3356 } 1023 }
3357 1024
3358 void Browser::UpdateOpenFileState() { 1025 void BrowserCommandController::UpdateOpenFileState() {
3359 bool enabled = true; 1026 bool enabled = true;
3360 PrefService* local_state = g_browser_process->local_state(); 1027 PrefService* local_state = g_browser_process->local_state();
3361 if (local_state) 1028 if (local_state)
3362 enabled = local_state->GetBoolean(prefs::kAllowFileSelectionDialogs); 1029 enabled = local_state->GetBoolean(prefs::kAllowFileSelectionDialogs);
3363 1030
3364 command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, enabled); 1031 command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, enabled);
3365 } 1032 }
3366 1033
3367 void Browser::UpdateReloadStopState(bool is_loading, bool force) { 1034 void BrowserCommandController::UpdateReloadStopState(bool is_loading,
3368 window_->UpdateReloadStopState(is_loading, force); 1035 bool force) {
1036 window()->UpdateReloadStopState(is_loading, force);
3369 command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading); 1037 command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading);
3370 } 1038 }
3371 1039
3372 /////////////////////////////////////////////////////////////////////////////// 1040 void BrowserCommandController::AddInterstitialObservers(TabContents* contents) {
3373 // Browser, UI update coalescing and handling (private): 1041 registrar_.Add(this, content::NOTIFICATION_INTERSTITIAL_ATTACHED,
3374 1042 content::Source<WebContents>(contents->web_contents()));
3375 void Browser::UpdateToolbar(bool should_restore_state) { 1043 registrar_.Add(this, content::NOTIFICATION_INTERSTITIAL_DETACHED,
3376 window_->UpdateToolbar(GetActiveTabContents(), should_restore_state); 1044 content::Source<WebContents>(contents->web_contents()));
3377 } 1045 }
3378 1046
3379 void Browser::UpdateSearchState(TabContents* contents) { 1047 void BrowserCommandController::RemoveInterstitialObservers(
3380 if (chrome::search::IsInstantExtendedAPIEnabled(profile_)) 1048 TabContents* contents) {
3381 search_delegate_->OnTabActivated(contents);
3382 }
3383
3384 void Browser::ScheduleUIUpdate(const WebContents* source,
3385 unsigned changed_flags) {
3386 if (!source)
3387 return;
3388
3389 // Do some synchronous updates.
3390 if (changed_flags & content::INVALIDATE_TYPE_URL &&
3391 source == GetActiveWebContents()) {
3392 // Only update the URL for the current tab. Note that we do not update
3393 // the navigation commands since those would have already been updated
3394 // synchronously by NavigationStateChanged.
3395 UpdateToolbar(false);
3396 changed_flags &= ~content::INVALIDATE_TYPE_URL;
3397 }
3398 if (changed_flags & content::INVALIDATE_TYPE_LOAD) {
3399 // Update the loading state synchronously. This is so the throbber will
3400 // immediately start/stop, which gives a more snappy feel. We want to do
3401 // this for any tab so they start & stop quickly.
3402 tab_strip_model_->UpdateTabContentsStateAt(
3403 GetIndexOfController(&source->GetController()),
3404 TabStripModelObserver::LOADING_ONLY);
3405 // The status bubble needs to be updated during INVALIDATE_TYPE_LOAD too,
3406 // but we do that asynchronously by not stripping INVALIDATE_TYPE_LOAD from
3407 // changed_flags.
3408 }
3409
3410 if (changed_flags & content::INVALIDATE_TYPE_TITLE && !source->IsLoading()) {
3411 // To correctly calculate whether the title changed while not loading
3412 // we need to process the update synchronously. This state only matters for
3413 // the TabStripModel, so we notify the TabStripModel now and notify others
3414 // asynchronously.
3415 tab_strip_model_->UpdateTabContentsStateAt(
3416 GetIndexOfController(&source->GetController()),
3417 TabStripModelObserver::TITLE_NOT_LOADING);
3418 }
3419
3420 // If the only updates were synchronously handled above, we're done.
3421 if (changed_flags == 0)
3422 return;
3423
3424 // Save the dirty bits.
3425 scheduled_updates_[source] |= changed_flags;
3426
3427 if (!chrome_updater_factory_.HasWeakPtrs()) {
3428 // No task currently scheduled, start another.
3429 MessageLoop::current()->PostDelayedTask(
3430 FROM_HERE,
3431 base::Bind(&Browser::ProcessPendingUIUpdates,
3432 chrome_updater_factory_.GetWeakPtr()),
3433 base::TimeDelta::FromMilliseconds(kUIUpdateCoalescingTimeMS));
3434 }
3435 }
3436
3437 void Browser::ProcessPendingUIUpdates() {
3438 #ifndef NDEBUG
3439 // Validate that all tabs we have pending updates for exist. This is scary
3440 // because the pending list must be kept in sync with any detached or
3441 // deleted tabs.
3442 for (UpdateMap::const_iterator i = scheduled_updates_.begin();
3443 i != scheduled_updates_.end(); ++i) {
3444 bool found = false;
3445 for (int tab = 0; tab < tab_count(); tab++) {
3446 if (GetWebContentsAt(tab) == i->first) {
3447 found = true;
3448 break;
3449 }
3450 }
3451 DCHECK(found);
3452 }
3453 #endif
3454
3455 chrome_updater_factory_.InvalidateWeakPtrs();
3456
3457 for (UpdateMap::const_iterator i = scheduled_updates_.begin();
3458 i != scheduled_updates_.end(); ++i) {
3459 // Do not dereference |contents|, it may be out-of-date!
3460 const WebContents* contents = i->first;
3461 unsigned flags = i->second;
3462
3463 if (contents == GetActiveWebContents()) {
3464 // Updates that only matter when the tab is selected go here.
3465
3466 if (flags & content::INVALIDATE_TYPE_PAGE_ACTIONS) {
3467 LocationBar* location_bar = window()->GetLocationBar();
3468 if (location_bar)
3469 location_bar->UpdatePageActions();
3470 }
3471 // Updating the URL happens synchronously in ScheduleUIUpdate.
3472 if (flags & content::INVALIDATE_TYPE_LOAD && GetStatusBubble()) {
3473 GetStatusBubble()->SetStatus(
3474 GetActiveTabContents()->
3475 core_tab_helper()->GetStatusText());
3476 }
3477
3478 if (flags & (content::INVALIDATE_TYPE_TAB |
3479 content::INVALIDATE_TYPE_TITLE)) {
3480 // TODO(pinkerton): Disable app-mode in the model until we implement it
3481 // on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148
3482 #if !defined(OS_MACOSX)
3483 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
3484 web_app::IsValidUrl(contents->GetURL()));
3485 #endif
3486 window_->UpdateTitleBar();
3487 }
3488 }
3489
3490 // Updates that don't depend upon the selected state go here.
3491 if (flags &
3492 (content::INVALIDATE_TYPE_TAB | content::INVALIDATE_TYPE_TITLE)) {
3493 tab_strip_model_->UpdateTabContentsStateAt(
3494 tab_strip_model_->GetIndexOfWebContents(contents),
3495 TabStripModelObserver::ALL);
3496 }
3497
3498 // We don't need to process INVALIDATE_STATE, since that's not visible.
3499 }
3500
3501 scheduled_updates_.clear();
3502 }
3503
3504 void Browser::RemoveScheduledUpdatesFor(WebContents* contents) {
3505 if (!contents)
3506 return;
3507
3508 UpdateMap::iterator i = scheduled_updates_.find(contents);
3509 if (i != scheduled_updates_.end())
3510 scheduled_updates_.erase(i);
3511 }
3512
3513
3514 ///////////////////////////////////////////////////////////////////////////////
3515 // Browser, Getters for UI (private):
3516
3517 StatusBubble* Browser::GetStatusBubble() {
3518 #if !defined(OS_MACOSX)
3519 // In kiosk mode, we want to always hide the status bubble.
3520 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode))
3521 return NULL;
3522 #endif
3523 return window_ ? window_->GetStatusBubble() : NULL;
3524 }
3525
3526 ///////////////////////////////////////////////////////////////////////////////
3527 // Browser, Session restore functions (private):
3528
3529 void Browser::SyncHistoryWithTabs(int index) {
3530 SessionService* session_service =
3531 SessionServiceFactory::GetForProfileIfExisting(profile());
3532 if (session_service) {
3533 for (int i = index; i < tab_count(); ++i) {
3534 TabContents* tab = GetTabContentsAt(i);
3535 if (tab) {
3536 session_service->SetTabIndexInWindow(
3537 session_id(), tab->restore_tab_helper()->session_id(), i);
3538 session_service->SetPinnedState(
3539 session_id(),
3540 tab->restore_tab_helper()->session_id(),
3541 IsTabPinned(i));
3542 }
3543 }
3544 }
3545 }
3546
3547 ///////////////////////////////////////////////////////////////////////////////
3548 // Browser, OnBeforeUnload handling (private):
3549
3550 void Browser::ProcessPendingTabs() {
3551 if (!is_attempting_to_close_browser_) {
3552 // Because we might invoke this after a delay it's possible for the value of
3553 // is_attempting_to_close_browser_ to have changed since we scheduled the
3554 // task.
3555 return;
3556 }
3557
3558 if (HasCompletedUnloadProcessing()) {
3559 // We've finished all the unload events and can proceed to close the
3560 // browser.
3561 OnWindowClosing();
3562 return;
3563 }
3564
3565 // Process beforeunload tabs first. When that queue is empty, process
3566 // unload tabs.
3567 if (!tabs_needing_before_unload_fired_.empty()) {
3568 WebContents* web_contents = *(tabs_needing_before_unload_fired_.begin());
3569 // Null check render_view_host here as this gets called on a PostTask and
3570 // the tab's render_view_host may have been nulled out.
3571 if (web_contents->GetRenderViewHost()) {
3572 web_contents->GetRenderViewHost()->FirePageBeforeUnload(false);
3573 } else {
3574 ClearUnloadState(web_contents, true);
3575 }
3576 } else if (!tabs_needing_unload_fired_.empty()) {
3577 // We've finished firing all beforeunload events and can proceed with unload
3578 // events.
3579 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
3580 // somewhere around here so that we have accurate measurements of shutdown
3581 // time.
3582 // TODO(ojan): We can probably fire all the unload events in parallel and
3583 // get a perf benefit from that in the cases where the tab hangs in it's
3584 // unload handler or takes a long time to page in.
3585 WebContents* web_contents = *(tabs_needing_unload_fired_.begin());
3586 // Null check render_view_host here as this gets called on a PostTask and
3587 // the tab's render_view_host may have been nulled out.
3588 if (web_contents->GetRenderViewHost()) {
3589 web_contents->GetRenderViewHost()->ClosePage();
3590 } else {
3591 ClearUnloadState(web_contents, true);
3592 }
3593 } else {
3594 NOTREACHED();
3595 }
3596 }
3597
3598 bool Browser::HasCompletedUnloadProcessing() const {
3599 return is_attempting_to_close_browser_ &&
3600 tabs_needing_before_unload_fired_.empty() &&
3601 tabs_needing_unload_fired_.empty();
3602 }
3603
3604 void Browser::CancelWindowClose() {
3605 // Closing of window can be canceled from a beforeunload handler.
3606 DCHECK(is_attempting_to_close_browser_);
3607 tabs_needing_before_unload_fired_.clear();
3608 tabs_needing_unload_fired_.clear();
3609 is_attempting_to_close_browser_ = false;
3610
3611 content::NotificationService::current()->Notify(
3612 chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED,
3613 content::Source<Browser>(this),
3614 content::NotificationService::NoDetails());
3615 }
3616
3617 bool Browser::RemoveFromSet(UnloadListenerSet* set, WebContents* web_contents) {
3618 DCHECK(is_attempting_to_close_browser_);
3619
3620 UnloadListenerSet::iterator iter =
3621 std::find(set->begin(), set->end(), web_contents);
3622 if (iter != set->end()) {
3623 set->erase(iter);
3624 return true;
3625 }
3626 return false;
3627 }
3628
3629 void Browser::ClearUnloadState(WebContents* web_contents, bool process_now) {
3630 if (is_attempting_to_close_browser_) {
3631 RemoveFromSet(&tabs_needing_before_unload_fired_, web_contents);
3632 RemoveFromSet(&tabs_needing_unload_fired_, web_contents);
3633 if (process_now) {
3634 ProcessPendingTabs();
3635 } else {
3636 MessageLoop::current()->PostTask(
3637 FROM_HERE,
3638 base::Bind(&Browser::ProcessPendingTabs, weak_factory_.GetWeakPtr()));
3639 }
3640 }
3641 }
3642
3643 ///////////////////////////////////////////////////////////////////////////////
3644 // Browser, In-progress download termination handling (private):
3645
3646 bool Browser::CanCloseWithInProgressDownloads() {
3647 // If we've prompted, we need to hear from the user before we
3648 // can close.
3649 if (cancel_download_confirmation_state_ != NOT_PROMPTED)
3650 return cancel_download_confirmation_state_ != WAITING_FOR_RESPONSE;
3651
3652 int num_downloads_blocking;
3653 if (DOWNLOAD_CLOSE_OK ==
3654 OkToCloseWithInProgressDownloads(&num_downloads_blocking))
3655 return true;
3656
3657 // Closing this window will kill some downloads; prompt to make sure
3658 // that's ok.
3659 cancel_download_confirmation_state_ = WAITING_FOR_RESPONSE;
3660 window_->ConfirmBrowserCloseWithPendingDownloads();
3661
3662 // Return false so the browser does not close. We'll close if the user
3663 // confirms in the dialog.
3664 return false;
3665 }
3666
3667 ///////////////////////////////////////////////////////////////////////////////
3668 // Browser, Assorted utility functions (private):
3669
3670 void Browser::SetAsDelegate(TabContents* tab, Browser* delegate) {
3671 // WebContents...
3672 tab->web_contents()->SetDelegate(delegate);
3673
3674 // ...and all the helpers.
3675 tab->blocked_content_tab_helper()->set_delegate(delegate);
3676 tab->bookmark_tab_helper()->set_delegate(delegate);
3677 tab->zoom_controller()->set_observer(delegate);
3678 tab->constrained_window_tab_helper()->set_delegate(delegate);
3679 tab->core_tab_helper()->set_delegate(delegate);
3680 tab->extension_tab_helper()->set_delegate(delegate);
3681 tab->search_engine_tab_helper()->set_delegate(delegate);
3682 }
3683
3684 void Browser::CloseFrame() {
3685 window_->Close();
3686 }
3687
3688 void Browser::TabDetachedAtImpl(TabContents* contents, int index,
3689 DetachType type) {
3690 if (type == DETACH_TYPE_DETACH) {
3691 // Save the current location bar state, but only if the tab being detached
3692 // is the selected tab. Because saving state can conditionally revert the
3693 // location bar, saving the current tab's location bar state to a
3694 // non-selected tab can corrupt both tabs.
3695 if (contents == GetActiveTabContents()) {
3696 LocationBar* location_bar = window()->GetLocationBar();
3697 if (location_bar)
3698 location_bar->SaveStateToContents(contents->web_contents());
3699 }
3700
3701 if (!tab_strip_model_->closing_all())
3702 SyncHistoryWithTabs(0);
3703 }
3704
3705 SetAsDelegate(contents, NULL);
3706 RemoveScheduledUpdatesFor(contents->web_contents());
3707
3708 if (find_bar_controller_.get() && index == active_index()) {
3709 find_bar_controller_->ChangeTabContents(NULL);
3710 }
3711
3712 if (is_attempting_to_close_browser_) {
3713 // If this is the last tab with unload handlers, then ProcessPendingTabs
3714 // would call back into the TabStripModel (which is invoking this method on
3715 // us). Avoid that by passing in false so that the call to
3716 // ProcessPendingTabs is delayed.
3717 ClearUnloadState(contents->web_contents(), false);
3718 }
3719
3720 // Stop observing search model changes for this tab.
3721 search_delegate_->OnTabDetached(contents);
3722
3723 registrar_.Remove(this, content::NOTIFICATION_INTERSTITIAL_ATTACHED, 1049 registrar_.Remove(this, content::NOTIFICATION_INTERSTITIAL_ATTACHED,
3724 content::Source<WebContents>(contents->web_contents())); 1050 content::Source<WebContents>(contents->web_contents()));
3725 registrar_.Remove(this, content::NOTIFICATION_INTERSTITIAL_DETACHED, 1051 registrar_.Remove(this, content::NOTIFICATION_INTERSTITIAL_DETACHED,
3726 content::Source<WebContents>(contents->web_contents())); 1052 content::Source<WebContents>(contents->web_contents()));
3727 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
3728 content::Source<WebContents>(contents->web_contents()));
3729 } 1053 }
3730 1054
3731 bool Browser::SupportsWindowFeatureImpl(WindowFeature feature, 1055 BrowserWindow* BrowserCommandController::window() {
3732 bool check_fullscreen) const { 1056 return browser_->window();
3733 // On Mac, fullscreen mode has most normal things (in a slide-down panel). On
3734 // other platforms, we hide some controls when in fullscreen mode.
3735 bool hide_ui_for_fullscreen = false;
3736 #if !defined(OS_MACOSX)
3737 hide_ui_for_fullscreen = check_fullscreen && window_ &&
3738 window_->IsFullscreen();
3739 #endif
3740
3741 unsigned int features = FEATURE_INFOBAR | FEATURE_DOWNLOADSHELF;
3742
3743 if (is_type_tabbed())
3744 features |= FEATURE_BOOKMARKBAR;
3745
3746 if (!hide_ui_for_fullscreen) {
3747 if (!is_type_tabbed())
3748 features |= FEATURE_TITLEBAR;
3749
3750 if (is_type_tabbed())
3751 features |= FEATURE_TABSTRIP;
3752
3753 if (is_type_tabbed())
3754 features |= FEATURE_TOOLBAR;
3755
3756 if (!is_app())
3757 features |= FEATURE_LOCATIONBAR;
3758 }
3759 return !!(features & feature);
3760 } 1057 }
3761 1058
3762 void Browser::CreateInstantIfNecessary() { 1059 Profile* BrowserCommandController::profile() {
3763 if (is_type_tabbed() && InstantController::IsEnabled(profile()) && 1060 return browser_->profile();
3764 !profile()->IsOffTheRecord()) {
3765 instant_.reset(new InstantController(this, InstantController::INSTANT));
3766 instant_unload_handler_.reset(new InstantUnloadHandler(this));
3767 }
3768 } 1061 }
3769 1062
3770 int Browser::GetContentRestrictionsForSelectedTab() { 1063 } // namespace chrome
3771 int content_restrictions = 0;
3772 WebContents* current_tab = GetActiveWebContents();
3773 if (current_tab) {
3774 content_restrictions = current_tab->GetContentRestrictions();
3775 NavigationEntry* active_entry =
3776 current_tab->GetController().GetActiveEntry();
3777 // See comment in UpdateCommandsForTabState about why we call url().
3778 if (!download_util::IsSavableURL(
3779 active_entry ? active_entry->GetURL() : GURL())
3780 || current_tab->ShowingInterstitialPage())
3781 content_restrictions |= content::CONTENT_RESTRICTION_SAVE;
3782 if (current_tab->ShowingInterstitialPage())
3783 content_restrictions |= content::CONTENT_RESTRICTION_PRINT;
3784 }
3785 return content_restrictions;
3786 }
3787
3788 void Browser::UpdateBookmarkBarState(BookmarkBarStateChangeReason reason) {
3789 BookmarkBar::State state;
3790 // The bookmark bar is hidden in fullscreen mode, unless on the new tab page.
3791 if (browser_defaults::bookmarks_enabled &&
3792 profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar) &&
3793 (!window_ || !window_->IsFullscreen())) {
3794 state = BookmarkBar::SHOW;
3795 } else {
3796 TabContents* tab = GetActiveTabContents();
3797 if (tab && tab->bookmark_tab_helper()->ShouldShowBookmarkBar())
3798 state = BookmarkBar::DETACHED;
3799 else
3800 state = BookmarkBar::HIDDEN;
3801 }
3802
3803 // Only allow the bookmark bar to be shown in default mode.
3804 if (!search_model_->mode().is_default())
3805 state = BookmarkBar::HIDDEN;
3806
3807 if (state == bookmark_bar_state_)
3808 return;
3809
3810 bookmark_bar_state_ = state;
3811
3812 if (!window_)
3813 return; // This is called from the constructor when window_ is NULL.
3814
3815 if (reason == BOOKMARK_BAR_STATE_CHANGE_TAB_SWITCH) {
3816 // Don't notify BrowserWindow on a tab switch as at the time this is invoked
3817 // BrowserWindow hasn't yet switched tabs. The BrowserWindow implementations
3818 // end up querying state once they process the tab switch.
3819 return;
3820 }
3821
3822 BookmarkBar::AnimateChangeType animate_type =
3823 (reason == BOOKMARK_BAR_STATE_CHANGE_PREF_CHANGE) ?
3824 BookmarkBar::ANIMATE_STATE_CHANGE :
3825 BookmarkBar::DONT_ANIMATE_STATE_CHANGE;
3826 window_->BookmarkBarStateChanged(animate_type);
3827 }
3828
3829 bool Browser::MaybeCreateBackgroundContents(int route_id,
3830 WebContents* opener_web_contents,
3831 const string16& frame_name,
3832 const GURL& target_url) {
3833 GURL opener_url = opener_web_contents->GetURL();
3834 ExtensionService* extensions_service = profile_->GetExtensionService();
3835
3836 if (!opener_url.is_valid() ||
3837 frame_name.empty() ||
3838 !extensions_service ||
3839 !extensions_service->is_ready())
3840 return false;
3841
3842 // Only hosted apps have web extents, so this ensures that only hosted apps
3843 // can create BackgroundContents. We don't have to check for background
3844 // permission as that is checked in RenderMessageFilter when the CreateWindow
3845 // message is processed.
3846 const Extension* extension =
3847 extensions_service->extensions()->GetHostedAppByURL(
3848 ExtensionURLInfo(opener_url));
3849 if (!extension)
3850 return false;
3851
3852 // No BackgroundContents allowed if BackgroundContentsService doesn't exist.
3853 BackgroundContentsService* service =
3854 BackgroundContentsServiceFactory::GetForProfile(profile_);
3855 if (!service)
3856 return false;
3857
3858 // Ensure that we're trying to open this from the extension's process.
3859 SiteInstance* opener_site_instance = opener_web_contents->GetSiteInstance();
3860 extensions::ProcessMap* process_map = extensions_service->process_map();
3861 if (!opener_site_instance->GetProcess() ||
3862 !process_map->Contains(
3863 extension->id(), opener_site_instance->GetProcess()->GetID())) {
3864 return false;
3865 }
3866
3867 // Only allow a single background contents per app.
3868 bool allow_js_access = extension->allow_background_js_access();
3869 BackgroundContents* existing =
3870 service->GetAppBackgroundContents(ASCIIToUTF16(extension->id()));
3871 if (existing) {
3872 // For non-scriptable background contents, ignore the request altogether,
3873 // (returning true, so that a regular WebContents isn't created either).
3874 if (!allow_js_access)
3875 return true;
3876 // For scriptable background pages, if one already exists, close it (even
3877 // if it was specified in the manifest).
3878 DLOG(INFO) << "Closing existing BackgroundContents for " << opener_url;
3879 delete existing;
3880 }
3881
3882 // If script access is not allowed, create the the background contents in a
3883 // new SiteInstance, so that a separate process is used.
3884 scoped_refptr<content::SiteInstance> site_instance =
3885 allow_js_access ?
3886 opener_site_instance :
3887 content::SiteInstance::Create(opener_web_contents->GetBrowserContext());
3888
3889 // Passed all the checks, so this should be created as a BackgroundContents.
3890 BackgroundContents* contents = service->CreateBackgroundContents(
3891 site_instance,
3892 route_id,
3893 profile_,
3894 frame_name,
3895 ASCIIToUTF16(extension->id()));
3896
3897 // When a separate process is used, the original renderer cannot access the
3898 // new window later, thus we need to navigate the window now.
3899 if (contents && !allow_js_access) {
3900 contents->web_contents()->GetController().LoadURL(
3901 target_url,
3902 content::Referrer(),
3903 content::PAGE_TRANSITION_LINK,
3904 std::string()); // No extra headers.
3905 }
3906
3907 return contents != NULL;
3908 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/browser_command_controller.h ('k') | chrome/browser/ui/browser_commands.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698