| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/sessions/tab_restore_service.h" | 5 #include "chrome/browser/sessions/tab_restore_service.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <iterator> | 8 #include <iterator> |
| 9 #include <map> | 9 #include <map> |
| 10 | 10 |
| 11 #include "base/callback.h" | 11 #include "base/callback.h" |
| 12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 13 #include "base/scoped_vector.h" | 13 #include "base/scoped_vector.h" |
| 14 #include "base/stl_util-inl.h" | 14 #include "base/stl_util-inl.h" |
| 15 #include "chrome/browser/browser_list.h" | |
| 16 #include "chrome/browser/browser_window.h" | 15 #include "chrome/browser/browser_window.h" |
| 17 #include "chrome/browser/extensions/extension_service.h" | 16 #include "chrome/browser/extensions/extension_service.h" |
| 18 #include "chrome/browser/profiles/profile.h" | 17 #include "chrome/browser/profiles/profile.h" |
| 19 #include "chrome/browser/sessions/session_service.h" | 18 #include "chrome/browser/sessions/session_service.h" |
| 20 #include "chrome/browser/sessions/session_command.h" | 19 #include "chrome/browser/sessions/session_command.h" |
| 21 #include "chrome/browser/sessions/session_types.h" | 20 #include "chrome/browser/sessions/session_types.h" |
| 22 #include "chrome/browser/sessions/tab_restore_service_observer.h" | 21 #include "chrome/browser/sessions/tab_restore_service_observer.h" |
| 23 #include "chrome/browser/tabs/tab_strip_model.h" | |
| 24 #include "chrome/common/extensions/extension.h" | 22 #include "chrome/common/extensions/extension.h" |
| 25 #include "chrome/common/extensions/extension_constants.h" | 23 #include "chrome/common/extensions/extension_constants.h" |
| 26 #include "content/browser/tab_contents/navigation_controller.h" | 24 #include "content/browser/tab_contents/navigation_controller.h" |
| 27 #include "content/browser/tab_contents/navigation_entry.h" | 25 #include "content/browser/tab_contents/navigation_entry.h" |
| 28 #include "content/browser/tab_contents/tab_contents.h" | 26 #include "content/browser/tab_contents/tab_contents.h" |
| 29 | 27 |
| 30 using base::Time; | 28 using base::Time; |
| 31 | 29 |
| 32 // TimeFactory----------------------------------------------------------------- | 30 // TimeFactory----------------------------------------------------------------- |
| 33 | 31 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 // If the ID matches one of this window's tabs, remove it from the list. | 143 // If the ID matches one of this window's tabs, remove it from the list. |
| 146 if ((*j).id == id) { | 144 if ((*j).id == id) { |
| 147 window->tabs.erase(j); | 145 window->tabs.erase(j); |
| 148 return; | 146 return; |
| 149 } | 147 } |
| 150 } | 148 } |
| 151 } | 149 } |
| 152 } | 150 } |
| 153 } | 151 } |
| 154 | 152 |
| 155 void RecordAppLaunch(Browser* browser, const TabRestoreService::Tab& tab) { | 153 void RecordAppLaunch(TabRestoreServiceDelegate* browser, |
| 154 const TabRestoreService::Tab& tab) { |
| 156 GURL url = tab.navigations.at(tab.current_navigation_index).virtual_url(); | 155 GURL url = tab.navigations.at(tab.current_navigation_index).virtual_url(); |
| 157 Profile* profile = browser->profile(); | 156 Profile* profile = browser->profile(); |
| 158 DCHECK(profile->GetExtensionService()); | 157 DCHECK(profile->GetExtensionService()); |
| 159 if (!profile->GetExtensionService()->IsInstalledApp(url)) | 158 if (!profile->GetExtensionService()->IsInstalledApp(url)) |
| 160 return; | 159 return; |
| 161 | 160 |
| 162 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, | 161 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, |
| 163 extension_misc::APP_LAUNCH_NTP_RECENTLY_CLOSED, | 162 extension_misc::APP_LAUNCH_NTP_RECENTLY_CLOSED, |
| 164 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); | 163 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); |
| 165 } | 164 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 } | 210 } |
| 212 | 211 |
| 213 void TabRestoreService::RemoveObserver(TabRestoreServiceObserver* observer) { | 212 void TabRestoreService::RemoveObserver(TabRestoreServiceObserver* observer) { |
| 214 observer_list_.RemoveObserver(observer); | 213 observer_list_.RemoveObserver(observer); |
| 215 } | 214 } |
| 216 | 215 |
| 217 void TabRestoreService::CreateHistoricalTab(NavigationController* tab) { | 216 void TabRestoreService::CreateHistoricalTab(NavigationController* tab) { |
| 218 if (restoring_) | 217 if (restoring_) |
| 219 return; | 218 return; |
| 220 | 219 |
| 221 Browser* browser = Browser::GetBrowserForController(tab, NULL); | 220 TabRestoreServiceDelegate* browser = |
| 221 TabRestoreServiceDelegate::GetBrowserForController(tab, NULL); |
| 222 if (closing_browsers_.find(browser) != closing_browsers_.end()) | 222 if (closing_browsers_.find(browser) != closing_browsers_.end()) |
| 223 return; | 223 return; |
| 224 | 224 |
| 225 scoped_ptr<Tab> local_tab(new Tab()); | 225 scoped_ptr<Tab> local_tab(new Tab()); |
| 226 PopulateTab(local_tab.get(), browser, tab); | 226 PopulateTab(local_tab.get(), browser, tab); |
| 227 if (local_tab->navigations.empty()) | 227 if (local_tab->navigations.empty()) |
| 228 return; | 228 return; |
| 229 | 229 |
| 230 AddEntry(local_tab.release(), true, true); | 230 AddEntry(local_tab.release(), true, true); |
| 231 } | 231 } |
| 232 | 232 |
| 233 void TabRestoreService::BrowserClosing(Browser* browser) { | 233 void TabRestoreService::BrowserClosing(TabRestoreServiceDelegate* browser) { |
| 234 if (browser->type() != Browser::TYPE_NORMAL || | 234 if (!browser->IsNormalBrowser() || browser->tab_count() == 0) |
| 235 browser->tab_count() == 0) | |
| 236 return; | 235 return; |
| 237 | 236 |
| 238 closing_browsers_.insert(browser); | 237 closing_browsers_.insert(browser); |
| 239 | 238 |
| 240 scoped_ptr<Window> window(new Window()); | 239 scoped_ptr<Window> window(new Window()); |
| 241 window->selected_tab_index = browser->selected_index(); | 240 window->selected_tab_index = browser->selected_index(); |
| 242 window->timestamp = TimeNow(); | 241 window->timestamp = TimeNow(); |
| 243 // Don't use std::vector::resize() because it will push copies of an empty tab | 242 // Don't use std::vector::resize() because it will push copies of an empty tab |
| 244 // into the vector, which will give all tabs in a window the same ID. | 243 // into the vector, which will give all tabs in a window the same ID. |
| 245 for (int i = 0; i < browser->tab_count(); ++i) { | 244 for (int i = 0; i < browser->tab_count(); ++i) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 263 // the stack. | 262 // the stack. |
| 264 AddEntry(new Tab(window->tabs[0]), true, true); | 263 AddEntry(new Tab(window->tabs[0]), true, true); |
| 265 } else if (!window->tabs.empty()) { | 264 } else if (!window->tabs.empty()) { |
| 266 window->selected_tab_index = | 265 window->selected_tab_index = |
| 267 std::min(static_cast<int>(window->tabs.size() - 1), | 266 std::min(static_cast<int>(window->tabs.size() - 1), |
| 268 window->selected_tab_index); | 267 window->selected_tab_index); |
| 269 AddEntry(window.release(), true, true); | 268 AddEntry(window.release(), true, true); |
| 270 } | 269 } |
| 271 } | 270 } |
| 272 | 271 |
| 273 void TabRestoreService::BrowserClosed(Browser* browser) { | 272 void TabRestoreService::BrowserClosed(TabRestoreServiceDelegate* browser) { |
| 274 closing_browsers_.erase(browser); | 273 closing_browsers_.erase(browser); |
| 275 } | 274 } |
| 276 | 275 |
| 277 void TabRestoreService::ClearEntries() { | 276 void TabRestoreService::ClearEntries() { |
| 278 // Mark all the tabs as closed so that we don't attempt to restore them. | 277 // Mark all the tabs as closed so that we don't attempt to restore them. |
| 279 for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) | 278 for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) |
| 280 ScheduleCommand(CreateRestoredEntryCommand((*i)->id)); | 279 ScheduleCommand(CreateRestoredEntryCommand((*i)->id)); |
| 281 | 280 |
| 282 entries_to_write_ = 0; | 281 entries_to_write_ = 0; |
| 283 | 282 |
| 284 // Schedule a pending reset so that we nuke the file on next write. | 283 // Schedule a pending reset so that we nuke the file on next write. |
| 285 set_pending_reset(true); | 284 set_pending_reset(true); |
| 286 | 285 |
| 287 // Schedule a command, otherwise if there are no pending commands Save does | 286 // Schedule a command, otherwise if there are no pending commands Save does |
| 288 // nothing. | 287 // nothing. |
| 289 ScheduleCommand(CreateRestoredEntryCommand(1)); | 288 ScheduleCommand(CreateRestoredEntryCommand(1)); |
| 290 | 289 |
| 291 STLDeleteElements(&entries_); | 290 STLDeleteElements(&entries_); |
| 292 NotifyTabsChanged(); | 291 NotifyTabsChanged(); |
| 293 } | 292 } |
| 294 | 293 |
| 295 const TabRestoreService::Entries& TabRestoreService::entries() const { | 294 const TabRestoreService::Entries& TabRestoreService::entries() const { |
| 296 return entries_; | 295 return entries_; |
| 297 } | 296 } |
| 298 | 297 |
| 299 void TabRestoreService::RestoreMostRecentEntry(Browser* browser) { | 298 void TabRestoreService::RestoreMostRecentEntry( |
| 299 TabRestoreServiceDelegate* browser) { |
| 300 if (entries_.empty()) | 300 if (entries_.empty()) |
| 301 return; | 301 return; |
| 302 | 302 |
| 303 RestoreEntryById(browser, entries_.front()->id, false); | 303 RestoreEntryById(browser, entries_.front()->id, false); |
| 304 } | 304 } |
| 305 | 305 |
| 306 void TabRestoreService::RestoreEntryById(Browser* browser, | 306 void TabRestoreService::RestoreEntryById(TabRestoreServiceDelegate* browser, |
| 307 SessionID::id_type id, | 307 SessionID::id_type id, |
| 308 bool replace_existing_tab) { | 308 bool replace_existing_tab) { |
| 309 Entries::iterator i = GetEntryIteratorById(id); | 309 Entries::iterator i = GetEntryIteratorById(id); |
| 310 if (i == entries_.end()) { | 310 if (i == entries_.end()) { |
| 311 // Don't hoark here, we allow an invalid id. | 311 // Don't hoark here, we allow an invalid id. |
| 312 return; | 312 return; |
| 313 } | 313 } |
| 314 | 314 |
| 315 size_t index = 0; | 315 size_t index = 0; |
| 316 for (Entries::iterator j = entries_.begin(); j != i && j != entries_.end(); | 316 for (Entries::iterator j = entries_.begin(); j != i && j != entries_.end(); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 333 } | 333 } |
| 334 | 334 |
| 335 // |browser| will be NULL in cases where one isn't already available (eg, | 335 // |browser| will be NULL in cases where one isn't already available (eg, |
| 336 // when invoked on Mac OS X with no windows open). In this case, create a | 336 // when invoked on Mac OS X with no windows open). In this case, create a |
| 337 // new browser into which we restore the tabs. | 337 // new browser into which we restore the tabs. |
| 338 if (entry->type == TAB) { | 338 if (entry->type == TAB) { |
| 339 Tab* tab = static_cast<Tab*>(entry); | 339 Tab* tab = static_cast<Tab*>(entry); |
| 340 browser = RestoreTab(*tab, browser, replace_existing_tab); | 340 browser = RestoreTab(*tab, browser, replace_existing_tab); |
| 341 browser->window()->Show(); | 341 browser->window()->Show(); |
| 342 } else if (entry->type == WINDOW) { | 342 } else if (entry->type == WINDOW) { |
| 343 Browser* current_browser = browser; | 343 TabRestoreServiceDelegate* current_browser = browser; |
| 344 Window* window = static_cast<Window*>(entry); | 344 Window* window = static_cast<Window*>(entry); |
| 345 | 345 |
| 346 // When restoring a window, either the entire window can be restored, or a | 346 // When restoring a window, either the entire window can be restored, or a |
| 347 // single tab within it. If the entry's ID matches the one to restore, then | 347 // single tab within it. If the entry's ID matches the one to restore, then |
| 348 // the entire window will be restored. | 348 // the entire window will be restored. |
| 349 if (!restoring_tab_in_window) { | 349 if (!restoring_tab_in_window) { |
| 350 browser = Browser::Create(profile()); | 350 browser = TabRestoreServiceDelegate::Create(profile()); |
| 351 for (size_t tab_i = 0; tab_i < window->tabs.size(); ++tab_i) { | 351 for (size_t tab_i = 0; tab_i < window->tabs.size(); ++tab_i) { |
| 352 const Tab& tab = window->tabs[tab_i]; | 352 const Tab& tab = window->tabs[tab_i]; |
| 353 TabContents* restored_tab = | 353 TabContents* restored_tab = |
| 354 browser->AddRestoredTab(tab.navigations, browser->tab_count(), | 354 browser->AddRestoredTab(tab.navigations, browser->tab_count(), |
| 355 tab.current_navigation_index, | 355 tab.current_navigation_index, |
| 356 tab.extension_app_id, | 356 tab.extension_app_id, |
| 357 (static_cast<int>(tab_i) == | 357 (static_cast<int>(tab_i) == |
| 358 window->selected_tab_index), | 358 window->selected_tab_index), |
| 359 tab.pinned, tab.from_last_session, | 359 tab.pinned, tab.from_last_session, |
| 360 tab.session_storage_namespace); | 360 tab.session_storage_namespace); |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 469 } | 469 } |
| 470 entries_written_++; | 470 entries_written_++; |
| 471 } | 471 } |
| 472 } | 472 } |
| 473 if (pending_reset()) | 473 if (pending_reset()) |
| 474 entries_written_ = 0; | 474 entries_written_ = 0; |
| 475 BaseSessionService::Save(); | 475 BaseSessionService::Save(); |
| 476 } | 476 } |
| 477 | 477 |
| 478 void TabRestoreService::PopulateTab(Tab* tab, | 478 void TabRestoreService::PopulateTab(Tab* tab, |
| 479 Browser* browser, | 479 TabRestoreServiceDelegate* browser, |
| 480 NavigationController* controller) { | 480 NavigationController* controller) { |
| 481 const int pending_index = controller->pending_entry_index(); | 481 const int pending_index = controller->pending_entry_index(); |
| 482 int entry_count = controller->entry_count(); | 482 int entry_count = controller->entry_count(); |
| 483 if (entry_count == 0 && pending_index == 0) | 483 if (entry_count == 0 && pending_index == 0) |
| 484 entry_count++; | 484 entry_count++; |
| 485 tab->navigations.resize(static_cast<int>(entry_count)); | 485 tab->navigations.resize(static_cast<int>(entry_count)); |
| 486 for (int i = 0; i < entry_count; ++i) { | 486 for (int i = 0; i < entry_count; ++i) { |
| 487 NavigationEntry* entry = (i == pending_index) ? | 487 NavigationEntry* entry = (i == pending_index) ? |
| 488 controller->pending_entry() : controller->GetEntryAtIndex(i); | 488 controller->pending_entry() : controller->GetEntryAtIndex(i); |
| 489 tab->navigations[i].SetFromNavigationEntry(*entry); | 489 tab->navigations[i].SetFromNavigationEntry(*entry); |
| 490 } | 490 } |
| 491 tab->timestamp = TimeNow(); | 491 tab->timestamp = TimeNow(); |
| 492 tab->current_navigation_index = controller->GetCurrentEntryIndex(); | 492 tab->current_navigation_index = controller->GetCurrentEntryIndex(); |
| 493 if (tab->current_navigation_index == -1 && entry_count > 0) | 493 if (tab->current_navigation_index == -1 && entry_count > 0) |
| 494 tab->current_navigation_index = 0; | 494 tab->current_navigation_index = 0; |
| 495 | 495 |
| 496 const Extension* extension = controller->tab_contents()->extension_app(); | 496 const Extension* extension = controller->tab_contents()->extension_app(); |
| 497 if (extension) | 497 if (extension) |
| 498 tab->extension_app_id = extension->id(); | 498 tab->extension_app_id = extension->id(); |
| 499 | 499 |
| 500 tab->session_storage_namespace = controller->session_storage_namespace(); | 500 tab->session_storage_namespace = controller->session_storage_namespace(); |
| 501 | 501 |
| 502 // Browser may be NULL during unit tests. | 502 // Browser may be NULL during unit tests. |
| 503 if (browser) { | 503 if (browser) { |
| 504 tab->browser_id = browser->session_id().id(); | 504 tab->browser_id = browser->session_id().id(); |
| 505 tab->tabstrip_index = | 505 tab->tabstrip_index = browser->GetIndexOfController(controller); |
| 506 browser->tabstrip_model()->GetIndexOfController(controller); | 506 tab->pinned = browser->IsTabPinned(tab->tabstrip_index); |
| 507 tab->pinned = browser->tabstrip_model()->IsTabPinned(tab->tabstrip_index); | |
| 508 } | 507 } |
| 509 } | 508 } |
| 510 | 509 |
| 511 void TabRestoreService::NotifyTabsChanged() { | 510 void TabRestoreService::NotifyTabsChanged() { |
| 512 FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_, | 511 FOR_EACH_OBSERVER(TabRestoreServiceObserver, observer_list_, |
| 513 TabRestoreServiceChanged(this)); | 512 TabRestoreServiceChanged(this)); |
| 514 } | 513 } |
| 515 | 514 |
| 516 void TabRestoreService::AddEntry(Entry* entry, bool notify, bool to_front) { | 515 void TabRestoreService::AddEntry(Entry* entry, bool notify, bool to_front) { |
| 517 if (to_front) | 516 if (to_front) |
| (...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 872 } | 871 } |
| 873 } | 872 } |
| 874 | 873 |
| 875 // If there was corruption some of the entries won't be valid. Prune any | 874 // If there was corruption some of the entries won't be valid. Prune any |
| 876 // entries with no navigations. | 875 // entries with no navigations. |
| 877 ValidateAndDeleteEmptyEntries(&(entries.get())); | 876 ValidateAndDeleteEmptyEntries(&(entries.get())); |
| 878 | 877 |
| 879 loaded_entries->swap(entries.get()); | 878 loaded_entries->swap(entries.get()); |
| 880 } | 879 } |
| 881 | 880 |
| 882 Browser* TabRestoreService::RestoreTab(const Tab& tab, | 881 TabRestoreServiceDelegate* TabRestoreService::RestoreTab(const Tab& tab, |
| 883 Browser* browser, | 882 TabRestoreServiceDelegate* browser, |
| 884 bool replace_existing_tab) { | 883 bool replace_existing_tab) { |
| 885 // |browser| will be NULL in cases where one isn't already available (eg, | 884 // |browser| will be NULL in cases where one isn't already available (eg, |
| 886 // when invoked on Mac OS X with no windows open). In this case, create a | 885 // when invoked on Mac OS X with no windows open). In this case, create a |
| 887 // new browser into which we restore the tabs. | 886 // new browser into which we restore the tabs. |
| 888 if (replace_existing_tab && browser) { | 887 if (replace_existing_tab && browser) { |
| 889 browser->ReplaceRestoredTab(tab.navigations, | 888 browser->ReplaceRestoredTab(tab.navigations, |
| 890 tab.current_navigation_index, | 889 tab.current_navigation_index, |
| 891 tab.from_last_session, | 890 tab.from_last_session, |
| 892 tab.extension_app_id, | 891 tab.extension_app_id, |
| 893 tab.session_storage_namespace); | 892 tab.session_storage_namespace); |
| 894 } else { | 893 } else { |
| 895 if (tab.has_browser()) | 894 if (tab.has_browser()) |
| 896 browser = BrowserList::FindBrowserWithID(tab.browser_id); | 895 browser = TabRestoreServiceDelegate::FindBrowserWithID(tab.browser_id); |
| 897 | 896 |
| 898 int tab_index = -1; | 897 int tab_index = -1; |
| 899 if (browser) { | 898 if (browser) { |
| 900 tab_index = tab.tabstrip_index; | 899 tab_index = tab.tabstrip_index; |
| 901 } else { | 900 } else { |
| 902 browser = Browser::Create(profile()); | 901 browser = TabRestoreServiceDelegate::Create(profile()); |
| 903 if (tab.has_browser()) { | 902 if (tab.has_browser()) { |
| 904 UpdateTabBrowserIDs(tab.browser_id, browser->session_id().id()); | 903 UpdateTabBrowserIDs(tab.browser_id, browser->session_id().id()); |
| 905 } | 904 } |
| 906 } | 905 } |
| 907 | 906 |
| 908 if (tab_index < 0 || tab_index > browser->tab_count()) { | 907 if (tab_index < 0 || tab_index > browser->tab_count()) { |
| 909 tab_index = browser->tab_count(); | 908 tab_index = browser->tab_count(); |
| 910 } | 909 } |
| 911 | 910 |
| 912 browser->AddRestoredTab(tab.navigations, | 911 browser->AddRestoredTab(tab.navigations, |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1076 // correctly write out the entries when Save is invoked (Save starts from | 1075 // correctly write out the entries when Save is invoked (Save starts from |
| 1077 // the front, not the end and we just added the entries to the end). | 1076 // the front, not the end and we just added the entries to the end). |
| 1078 entries_to_write_ = staging_entries_.size(); | 1077 entries_to_write_ = staging_entries_.size(); |
| 1079 | 1078 |
| 1080 PruneAndNotify(); | 1079 PruneAndNotify(); |
| 1081 } | 1080 } |
| 1082 | 1081 |
| 1083 Time TabRestoreService::TimeNow() const { | 1082 Time TabRestoreService::TimeNow() const { |
| 1084 return time_factory_ ? time_factory_->TimeNow() : Time::Now(); | 1083 return time_factory_ ? time_factory_->TimeNow() : Time::Now(); |
| 1085 } | 1084 } |
| OLD | NEW |