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 |