| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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/tab_restore_service.h" | 5 #include "chrome/browser/tab_restore_service.h" |
| 6 | 6 |
| 7 #include "chrome/browser/profile.h" | 7 #include "chrome/browser/browser_list.h" |
| 8 #include "chrome/browser/navigation_controller.h" | 8 #include "chrome/browser/navigation_controller.h" |
| 9 #include "chrome/browser/navigation_entry.h" | 9 #include "chrome/browser/navigation_entry.h" |
| 10 #include "chrome/browser/profile.h" |
| 11 #include "chrome/common/stl_util-inl.h" |
| 10 | 12 |
| 11 using base::Time; | 13 using base::Time; |
| 12 | 14 |
| 13 // HistoricalTab -------------------------------------------------------------- | 15 // Entry ---------------------------------------------------------------------- |
| 14 | 16 |
| 15 // ID of the next HistoricalTab. | 17 // ID of the next Entry. |
| 16 static int next_historical_tab_id = 1; | 18 static int next_entry_id = 1; |
| 17 | 19 |
| 18 TabRestoreService::HistoricalTab::HistoricalTab() | 20 TabRestoreService::Entry::Entry() : id(next_entry_id++), type(TAB) {} |
| 19 : close_time(Time::Now()), | 21 |
| 20 from_last_session(false), | 22 TabRestoreService::Entry::Entry(Type type) : id(next_entry_id++), type(type) {} |
| 21 current_navigation_index(-1), | |
| 22 id(next_historical_tab_id++) { | |
| 23 } | |
| 24 | 23 |
| 25 // TabRestoreService ---------------------------------------------------------- | 24 // TabRestoreService ---------------------------------------------------------- |
| 26 | 25 |
| 27 // Max number of tabs we'll keep around. | 26 // Max number of entries we'll keep around. |
| 28 static const size_t kMaxTabs = 10; | 27 static const size_t kMaxEntries = 10; |
| 29 | |
| 30 // Amount of time from when the session starts and when we'll allow loading of | |
| 31 // the last sessions tabs. | |
| 32 static const int kLoadFromLastSessionMS = 600000; | |
| 33 | 28 |
| 34 TabRestoreService::TabRestoreService(Profile* profile) | 29 TabRestoreService::TabRestoreService(Profile* profile) |
| 35 : profile_(profile), | 30 : profile_(profile), |
| 36 loaded_last_session_(false) { | 31 loaded_last_session_(false), |
| 32 restoring_(false) { |
| 37 } | 33 } |
| 38 | 34 |
| 39 TabRestoreService::~TabRestoreService() { | 35 TabRestoreService::~TabRestoreService() { |
| 40 FOR_EACH_OBSERVER(Observer, observer_list_, TabRestoreServiceDestroyed(this)); | 36 FOR_EACH_OBSERVER(Observer, observer_list_, TabRestoreServiceDestroyed(this)); |
| 37 STLDeleteElements(&entries_); |
| 41 } | 38 } |
| 42 | 39 |
| 43 void TabRestoreService::AddObserver(Observer* observer) { | 40 void TabRestoreService::AddObserver(Observer* observer) { |
| 44 observer_list_.AddObserver(observer); | 41 observer_list_.AddObserver(observer); |
| 45 } | 42 } |
| 46 | 43 |
| 47 void TabRestoreService::RemoveObserver(Observer* observer) { | 44 void TabRestoreService::RemoveObserver(Observer* observer) { |
| 48 observer_list_.RemoveObserver(observer); | 45 observer_list_.RemoveObserver(observer); |
| 49 } | 46 } |
| 50 | 47 |
| 51 void TabRestoreService::LoadPreviousSessionTabs() { | 48 void TabRestoreService::CreateHistoricalTab(NavigationController* tab) { |
| 52 if (!WillLoadPreviousSessionTabs() || IsLoadingPreviousSessionTabs()) | 49 if (restoring_) |
| 53 return; | 50 return; |
| 54 | 51 |
| 55 profile_->GetSessionService()->GetLastSession( | 52 Browser* browser = Browser::GetBrowserForController(tab, NULL); |
| 56 &cancelable_consumer_, | 53 if (closing_browsers_.find(browser) != closing_browsers_.end()) |
| 57 NewCallback(this, &TabRestoreService::OnGotLastSession)); | 54 return; |
| 55 |
| 56 Tab* local_tab = new Tab(); |
| 57 PopulateTabFromController(tab, local_tab); |
| 58 entries_.push_front(local_tab); |
| 59 |
| 60 PruneAndNotify(); |
| 58 } | 61 } |
| 59 | 62 |
| 60 bool TabRestoreService::IsLoadingPreviousSessionTabs() { | 63 void TabRestoreService::BrowserClosing(Browser* browser) { |
| 61 return cancelable_consumer_.HasPendingRequests(); | 64 if (browser->type() != Browser::TYPE_NORMAL || |
| 65 browser->tab_count() == 0) |
| 66 return; |
| 67 |
| 68 closing_browsers_.insert(browser); |
| 69 |
| 70 Window* window = new Window(); |
| 71 window->selected_tab_index = browser->selected_index(); |
| 72 window->tabs.resize(browser->tab_count()); |
| 73 size_t entry_index = 0; |
| 74 for (int tab_index = 0; tab_index < browser->tab_count(); ++tab_index) { |
| 75 PopulateTabFromController( |
| 76 browser->GetTabContentsAt(tab_index)->controller(), |
| 77 &(window->tabs[entry_index])); |
| 78 if (window->tabs[entry_index].navigations.empty()) |
| 79 window->tabs.erase(window->tabs.begin() + entry_index); |
| 80 else |
| 81 entry_index++; |
| 82 } |
| 83 if (window->tabs.empty()) { |
| 84 delete window; |
| 85 window = NULL; |
| 86 } else { |
| 87 entries_.push_front(window); |
| 88 PruneAndNotify(); |
| 89 } |
| 62 } | 90 } |
| 63 | 91 |
| 64 bool TabRestoreService::WillLoadPreviousSessionTabs() { | 92 void TabRestoreService::BrowserClosed(Browser* browser) { |
| 65 return (!loaded_last_session_ && tabs_.size() < kMaxTabs && | 93 closing_browsers_.erase(browser); |
| 66 (Time::Now() - profile_->GetStartTime()).InMilliseconds() < | |
| 67 kLoadFromLastSessionMS); | |
| 68 } | 94 } |
| 69 | 95 |
| 70 void TabRestoreService::CreateHistoricalTab(NavigationController* tab) { | 96 void TabRestoreService::ClearEntries() { |
| 71 tabs_.push_front(HistoricalTab()); | 97 STLDeleteElements(&entries_); |
| 72 | |
| 73 PopulateTabFromController(tab, &(tabs_.front())); | |
| 74 | |
| 75 while (tabs_.size() > kMaxTabs) | |
| 76 tabs_.pop_back(); | |
| 77 | |
| 78 NotifyTabsChanged(); | 98 NotifyTabsChanged(); |
| 79 } | 99 } |
| 80 | 100 |
| 81 void TabRestoreService::RemoveHistoricalTabById(int id) { | 101 void TabRestoreService::RestoreMostRecentEntry(Browser* browser) { |
| 82 for (Tabs::iterator i = tabs_.begin(); i != tabs_.end(); ++i) { | 102 if (entries_.empty()) |
| 83 if (i->id == id) { | 103 return; |
| 84 tabs_.erase(i); | 104 |
| 85 NotifyTabsChanged(); | 105 RestoreEntryById(browser, entries_.front()->id, false); |
| 86 return; | |
| 87 } | |
| 88 } | |
| 89 // Don't hoark here, we allow an invalid id. | |
| 90 } | 106 } |
| 91 | 107 |
| 92 void TabRestoreService::ClearHistoricalTabs() { | 108 void TabRestoreService::RestoreEntryById(Browser* browser, |
| 93 tabs_.clear(); | 109 int id, |
| 94 NotifyTabsChanged(); | 110 bool replace_existing_tab) { |
| 95 } | 111 Entries::iterator i = GetEntryIteratorById(id); |
| 96 | 112 if (i == entries_.end()) { |
| 97 void TabRestoreService::OnGotLastSession(SessionService::Handle handle, | 113 // Don't hoark here, we allow an invalid id. |
| 98 std::vector<SessionWindow*>* windows) { | |
| 99 DCHECK(!loaded_last_session_); | |
| 100 loaded_last_session_ = true; | |
| 101 | |
| 102 if (tabs_.size() == kMaxTabs) | |
| 103 return; | 114 return; |
| 104 | |
| 105 AddHistoricalTabs(windows); | |
| 106 | |
| 107 NotifyTabsChanged(); | |
| 108 } | |
| 109 | |
| 110 void TabRestoreService::AddHistoricalTabs( | |
| 111 std::vector<SessionWindow*>* windows) { | |
| 112 // First pass, extract the selected tabs in each window. | |
| 113 for (size_t i = 0; i < windows->size(); ++i) { | |
| 114 SessionWindow* window = (*windows)[i]; | |
| 115 if (window->type == Browser::TYPE_NORMAL) { | |
| 116 DCHECK(window->selected_tab_index >= 0 && | |
| 117 window->selected_tab_index < | |
| 118 static_cast<int>(window->tabs.size())); | |
| 119 AppendHistoricalTabFromSessionTab( | |
| 120 window->tabs[window->selected_tab_index]); | |
| 121 if (tabs_.size() == kMaxTabs) | |
| 122 return; | |
| 123 } | |
| 124 } | 115 } |
| 125 | 116 |
| 126 // Second pass, extract the non-selected tabs. | 117 restoring_ = true; |
| 127 for (size_t window_index = 0; window_index < windows->size(); | 118 Entry* entry = *i; |
| 128 ++window_index) { | 119 entries_.erase(i); |
| 129 SessionWindow* window = (*windows)[window_index]; | 120 i = entries_.end(); |
| 130 if (window->type != Browser::TYPE_NORMAL) | 121 if (entry->type == TAB) { |
| 131 continue; // Ignore popups. | 122 Tab* tab = static_cast<Tab*>(entry); |
| 132 | 123 if (replace_existing_tab) { |
| 133 for (size_t tab_index = 0; tab_index < window->tabs.size(); ++tab_index) { | 124 browser->ReplaceRestoredTab(tab->navigations, |
| 134 if (tab_index == window->selected_tab_index) | 125 tab->current_navigation_index); |
| 135 continue; // Pass one took care of this tab. | 126 } else { |
| 136 AppendHistoricalTabFromSessionTab(window->tabs[tab_index]); | 127 browser->AddRestoredTab(tab->navigations, browser->tab_count(), |
| 137 if (tabs_.size() == kMaxTabs) | 128 tab->current_navigation_index, true); |
| 138 return; | |
| 139 } | 129 } |
| 130 } else if (entry->type == WINDOW) { |
| 131 const Window* window = static_cast<Window*>(entry); |
| 132 Browser* browser = Browser::Create(profile_); |
| 133 for (size_t tab_i = 0; tab_i < window->tabs.size(); ++tab_i) { |
| 134 const Tab& tab = window->tabs[tab_i]; |
| 135 NavigationController* restored_controller = |
| 136 browser->AddRestoredTab(tab.navigations, browser->tab_count(), |
| 137 tab.current_navigation_index, |
| 138 (tab_i == window->selected_tab_index)); |
| 139 if (restored_controller) |
| 140 restored_controller->LoadIfNecessary(); |
| 141 } |
| 142 browser->window()->Show(); |
| 143 } else { |
| 144 NOTREACHED(); |
| 140 } | 145 } |
| 141 } | 146 delete entry; |
| 142 | 147 restoring_ = false; |
| 143 void TabRestoreService::AppendHistoricalTabFromSessionTab( | 148 NotifyTabsChanged(); |
| 144 SessionTab* tab) { | |
| 145 tabs_.push_back(HistoricalTab()); | |
| 146 PopulateTabFromSessionTab(tab, &(tabs_.back())); | |
| 147 } | 149 } |
| 148 | 150 |
| 149 void TabRestoreService::PopulateTabFromController( | 151 void TabRestoreService::PopulateTabFromController( |
| 150 NavigationController* controller, | 152 NavigationController* controller, |
| 151 HistoricalTab* tab) { | 153 Tab* tab) { |
| 152 const int pending_index = controller->GetPendingEntryIndex(); | 154 const int pending_index = controller->GetPendingEntryIndex(); |
| 153 int entry_count = controller->GetEntryCount(); | 155 int entry_count = controller->GetEntryCount(); |
| 154 if (entry_count == 0 && pending_index == 0) | 156 if (entry_count == 0 && pending_index == 0) |
| 155 entry_count++; | 157 entry_count++; |
| 156 tab->navigations.resize(static_cast<int>(entry_count)); | 158 tab->navigations.resize(static_cast<int>(entry_count)); |
| 157 for (int i = 0; i < entry_count; ++i) { | 159 for (int i = 0; i < entry_count; ++i) { |
| 158 NavigationEntry* entry = (i == pending_index) ? | 160 NavigationEntry* entry = (i == pending_index) ? |
| 159 controller->GetPendingEntry() : controller->GetEntryAtIndex(i); | 161 controller->GetPendingEntry() : controller->GetEntryAtIndex(i); |
| 160 TabNavigation& tab_nav = tab->navigations[i]; | 162 TabNavigation& tab_nav = tab->navigations[i]; |
| 161 tab_nav.url = entry->display_url(); | 163 tab_nav.url = entry->display_url(); |
| 162 tab_nav.referrer = entry->referrer(); | 164 tab_nav.referrer = entry->referrer(); |
| 163 tab_nav.title = entry->title(); | 165 tab_nav.title = entry->title(); |
| 164 tab_nav.state = entry->content_state(); | 166 tab_nav.state = entry->content_state(); |
| 165 tab_nav.transition = entry->transition_type(); | 167 tab_nav.transition = entry->transition_type(); |
| 166 tab_nav.type_mask = entry->has_post_data() ? | 168 tab_nav.type_mask = entry->has_post_data() ? |
| 167 TabNavigation::HAS_POST_DATA : 0; | 169 TabNavigation::HAS_POST_DATA : 0; |
| 168 } | 170 } |
| 169 tab->current_navigation_index = controller->GetCurrentEntryIndex(); | 171 tab->current_navigation_index = controller->GetCurrentEntryIndex(); |
| 170 if (tab->current_navigation_index == -1 && entry_count > 0) | 172 if (tab->current_navigation_index == -1 && entry_count > 0) |
| 171 tab->current_navigation_index = 0; | 173 tab->current_navigation_index = 0; |
| 172 } | 174 } |
| 173 | 175 |
| 174 void TabRestoreService::PopulateTabFromSessionTab( | |
| 175 SessionTab* session_tab, | |
| 176 HistoricalTab* tab) { | |
| 177 tab->navigations.swap(session_tab->navigations); | |
| 178 tab->from_last_session = true; | |
| 179 tab->current_navigation_index = session_tab->current_navigation_index; | |
| 180 } | |
| 181 | |
| 182 void TabRestoreService::NotifyTabsChanged() { | 176 void TabRestoreService::NotifyTabsChanged() { |
| 183 FOR_EACH_OBSERVER(Observer, observer_list_, TabRestoreServiceChanged(this)); | 177 FOR_EACH_OBSERVER(Observer, observer_list_, TabRestoreServiceChanged(this)); |
| 184 } | 178 } |
| 179 |
| 180 void TabRestoreService::PruneAndNotify() { |
| 181 while (entries_.size() > kMaxEntries) { |
| 182 delete entries_.back(); |
| 183 entries_.pop_back(); |
| 184 } |
| 185 |
| 186 NotifyTabsChanged(); |
| 187 } |
| 188 |
| 189 TabRestoreService::Entries::iterator TabRestoreService::GetEntryIteratorById( |
| 190 int id) { |
| 191 for (Entries::iterator i = entries_.begin(); i != entries_.end(); ++i) { |
| 192 if ((*i)->id == id) |
| 193 return i; |
| 194 } |
| 195 return entries_.end(); |
| 196 } |
| OLD | NEW |