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/tabs/tab_strip_model.h" | 5 #include "chrome/browser/tabs/tab_strip_model.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/stl_util-inl.h" | 10 #include "base/stl_util-inl.h" |
11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
12 #include "build/build_config.h" | 12 #include "build/build_config.h" |
13 #include "chrome/browser/bookmarks/bookmark_model.h" | 13 #include "chrome/browser/bookmarks/bookmark_model.h" |
14 #include "chrome/browser/browser_shutdown.h" | 14 #include "chrome/browser/browser_shutdown.h" |
15 #include "chrome/browser/defaults.h" | 15 #include "chrome/browser/defaults.h" |
16 #include "chrome/browser/extensions/extensions_service.h" | 16 #include "chrome/browser/extensions/extensions_service.h" |
17 #include "chrome/browser/metrics/user_metrics.h" | 17 #include "chrome/browser/metrics/user_metrics.h" |
18 #include "chrome/browser/profile.h" | 18 #include "chrome/browser/profile.h" |
19 #include "chrome/browser/renderer_host/render_process_host.h" | 19 #include "chrome/browser/renderer_host/render_process_host.h" |
20 #include "chrome/browser/sessions/tab_restore_service.h" | 20 #include "chrome/browser/sessions/tab_restore_service.h" |
21 #include "chrome/browser/tabs/tab_strip_model_delegate.h" | 21 #include "chrome/browser/tabs/tab_strip_model_delegate.h" |
22 #include "chrome/browser/tabs/tab_strip_model_order_controller.h" | 22 #include "chrome/browser/tabs/tab_strip_model_order_controller.h" |
| 23 #include "chrome/browser/tab_contents_wrapper.h" |
23 #include "chrome/browser/tab_contents/navigation_controller.h" | 24 #include "chrome/browser/tab_contents/navigation_controller.h" |
24 #include "chrome/browser/tab_contents/tab_contents.h" | 25 #include "chrome/browser/tab_contents/tab_contents.h" |
25 #include "chrome/browser/tab_contents/tab_contents_delegate.h" | 26 #include "chrome/browser/tab_contents/tab_contents_delegate.h" |
26 #include "chrome/browser/tab_contents/tab_contents_view.h" | 27 #include "chrome/browser/tab_contents/tab_contents_view.h" |
27 #include "chrome/common/chrome_switches.h" | 28 #include "chrome/common/chrome_switches.h" |
28 #include "chrome/common/extensions/extension.h" | 29 #include "chrome/common/extensions/extension.h" |
29 #include "chrome/common/notification_service.h" | 30 #include "chrome/common/notification_service.h" |
30 #include "chrome/common/url_constants.h" | 31 #include "chrome/common/url_constants.h" |
31 | 32 |
32 namespace { | 33 namespace { |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 } | 97 } |
97 | 98 |
98 bool TabStripModel::HasObserver(TabStripModelObserver* observer) { | 99 bool TabStripModel::HasObserver(TabStripModelObserver* observer) { |
99 return observers_.HasObserver(observer); | 100 return observers_.HasObserver(observer); |
100 } | 101 } |
101 | 102 |
102 bool TabStripModel::ContainsIndex(int index) const { | 103 bool TabStripModel::ContainsIndex(int index) const { |
103 return index >= 0 && index < count(); | 104 return index >= 0 && index < count(); |
104 } | 105 } |
105 | 106 |
106 void TabStripModel::AppendTabContents(TabContents* contents, bool foreground) { | 107 void TabStripModel::AppendTabContents(TabContentsWrapper* contents, |
| 108 bool foreground) { |
107 int index = order_controller_->DetermineInsertionIndexForAppending(); | 109 int index = order_controller_->DetermineInsertionIndexForAppending(); |
108 InsertTabContentsAt(index, contents, | 110 InsertTabContentsAt(index, contents, |
109 foreground ? (ADD_INHERIT_GROUP | ADD_SELECTED) : | 111 foreground ? (ADD_INHERIT_GROUP | ADD_SELECTED) : |
110 ADD_NONE); | 112 ADD_NONE); |
111 } | 113 } |
112 | 114 |
113 void TabStripModel::InsertTabContentsAt(int index, | 115 void TabStripModel::InsertTabContentsAt(int index, |
114 TabContents* contents, | 116 TabContentsWrapper* contents, |
115 int add_types) { | 117 int add_types) { |
116 bool foreground = add_types & ADD_SELECTED; | 118 bool foreground = add_types & ADD_SELECTED; |
117 // Force app tabs to be pinned. | 119 // Force app tabs to be pinned. |
118 bool pin = contents->is_app() || add_types & ADD_PINNED; | 120 bool pin = contents->is_app() || add_types & ADD_PINNED; |
119 index = ConstrainInsertionIndex(index, pin); | 121 index = ConstrainInsertionIndex(index, pin); |
120 | 122 |
121 // In tab dragging situations, if the last tab in the window was detached | 123 // In tab dragging situations, if the last tab in the window was detached |
122 // then the user aborted the drag, we will have the |closing_all_| member | 124 // then the user aborted the drag, we will have the |closing_all_| member |
123 // set (see DetachTabContentsAt) which will mess with our mojo here. We need | 125 // set (see DetachTabContentsAt) which will mess with our mojo here. We need |
124 // to clear this bit. | 126 // to clear this bit. |
125 closing_all_ = false; | 127 closing_all_ = false; |
126 | 128 |
127 // Have to get the selected contents before we monkey with |contents_| | 129 // Have to get the selected contents before we monkey with |contents_| |
128 // otherwise we run into problems when we try to change the selected contents | 130 // otherwise we run into problems when we try to change the selected contents |
129 // since the old contents and the new contents will be the same... | 131 // since the old contents and the new contents will be the same... |
130 TabContents* selected_contents = GetSelectedTabContents(); | 132 TabContentsWrapper* selected_contents = GetSelectedTabContents(); |
131 TabContentsData* data = new TabContentsData(contents); | 133 TabContentsData* data = new TabContentsData(contents); |
132 data->pinned = pin; | 134 data->pinned = pin; |
133 if ((add_types & ADD_INHERIT_GROUP) && selected_contents) { | 135 if ((add_types & ADD_INHERIT_GROUP) && selected_contents) { |
134 if (foreground) { | 136 if (foreground) { |
135 // Forget any existing relationships, we don't want to make things too | 137 // Forget any existing relationships, we don't want to make things too |
136 // confusing by having multiple groups active at the same time. | 138 // confusing by having multiple groups active at the same time. |
137 ForgetAllOpeners(); | 139 ForgetAllOpeners(); |
138 } | 140 } |
139 // Anything opened by a link we deem to have an opener. | 141 // Anything opened by a link we deem to have an opener. |
140 data->SetGroup(&selected_contents->controller()); | 142 data->SetGroup(&selected_contents->controller()); |
(...skipping 14 matching lines...) Expand all Loading... |
155 ++selected_index_; | 157 ++selected_index_; |
156 } | 158 } |
157 | 159 |
158 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, | 160 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, |
159 TabInsertedAt(contents, index, foreground)); | 161 TabInsertedAt(contents, index, foreground)); |
160 | 162 |
161 if (foreground) | 163 if (foreground) |
162 ChangeSelectedContentsFrom(selected_contents, index, false); | 164 ChangeSelectedContentsFrom(selected_contents, index, false); |
163 } | 165 } |
164 | 166 |
165 void TabStripModel::ReplaceTabContentsAt(int index, TabContents* new_contents) { | 167 void TabStripModel::ReplaceTabContentsAt(int index, |
| 168 TabContentsWrapper* new_contents) { |
166 // TODO: this should reset group/opener of any tabs that point at | 169 // TODO: this should reset group/opener of any tabs that point at |
167 // old_contents. | 170 // old_contents. |
168 DCHECK(ContainsIndex(index)); | 171 DCHECK(ContainsIndex(index)); |
169 scoped_ptr<TabContents> old_contents(GetContentsAt(index)); | 172 scoped_ptr<TabContentsWrapper> old_contents(GetContentsAt(index)); |
170 | 173 |
171 contents_data_[index]->contents = new_contents; | 174 contents_data_[index]->contents = new_contents; |
172 | 175 |
173 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, | 176 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, |
174 TabReplacedAt(old_contents.get(), new_contents, index)); | 177 TabReplacedAt(old_contents.get(), new_contents, index)); |
175 | 178 |
176 // When the selected tab contents is replaced send out selected notification | 179 // When the selected tab contents is replaced send out selected notification |
177 // too. We do this as nearly all observers need to treat a replace of the | 180 // too. We do this as nearly all observers need to treat a replace of the |
178 // selected contents as selection changing. | 181 // selected contents as selection changing. |
179 if (selected_index_ == index) { | 182 if (selected_index_ == index) { |
180 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, | 183 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, |
181 TabSelectedAt(old_contents.get(), new_contents, | 184 TabSelectedAt(old_contents.get(), new_contents, |
182 selected_index_, false)); | 185 selected_index_, false)); |
183 } | 186 } |
184 } | 187 } |
185 | 188 |
186 void TabStripModel::ReplaceNavigationControllerAt( | 189 void TabStripModel::ReplaceNavigationControllerAt( |
187 int index, NavigationController* controller) { | 190 int index, TabContentsWrapper* contents) { |
188 // This appears to be OK with no flicker since no redraw event | 191 // This appears to be OK with no flicker since no redraw event |
189 // occurs between the call to add an aditional tab and one to close | 192 // occurs between the call to add an aditional tab and one to close |
190 // the previous tab. | 193 // the previous tab. |
191 InsertTabContentsAt( | 194 InsertTabContentsAt( |
192 index + 1, controller->tab_contents(), | 195 index + 1, contents, |
193 ADD_SELECTED | ADD_INHERIT_GROUP); | 196 ADD_SELECTED | ADD_INHERIT_GROUP); |
194 std::vector<int> closing_tabs; | 197 std::vector<int> closing_tabs; |
195 closing_tabs.push_back(index); | 198 closing_tabs.push_back(index); |
196 InternalCloseTabs(closing_tabs, CLOSE_NONE); | 199 InternalCloseTabs(closing_tabs, CLOSE_NONE); |
197 } | 200 } |
198 | 201 |
199 TabContents* TabStripModel::DetachTabContentsAt(int index) { | 202 TabContentsWrapper* TabStripModel::DetachTabContentsAt(int index) { |
200 if (contents_data_.empty()) | 203 if (contents_data_.empty()) |
201 return NULL; | 204 return NULL; |
202 | 205 |
203 DCHECK(ContainsIndex(index)); | 206 DCHECK(ContainsIndex(index)); |
204 | 207 |
205 TabContents* removed_contents = GetContentsAt(index); | 208 TabContentsWrapper* removed_contents = GetContentsAt(index); |
206 int next_selected_index = order_controller_->DetermineNewSelectedIndex(index); | 209 int next_selected_index = order_controller_->DetermineNewSelectedIndex(index); |
207 delete contents_data_.at(index); | 210 delete contents_data_.at(index); |
208 contents_data_.erase(contents_data_.begin() + index); | 211 contents_data_.erase(contents_data_.begin() + index); |
209 if (empty()) | 212 if (empty()) |
210 closing_all_ = true; | 213 closing_all_ = true; |
211 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, | 214 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, |
212 TabDetachedAt(removed_contents, index)); | 215 TabDetachedAt(removed_contents, index)); |
213 if (empty()) { | 216 if (empty()) { |
214 // TabDetachedAt() might unregister observers, so send |TabStripEmtpy()| in | 217 // TabDetachedAt() might unregister observers, so send |TabStripEmtpy()| in |
215 // a second pass. | 218 // a second pass. |
(...skipping 25 matching lines...) Expand all Loading... |
241 if ((index < first_non_mini_tab && to_position >= first_non_mini_tab) || | 244 if ((index < first_non_mini_tab && to_position >= first_non_mini_tab) || |
242 (to_position < first_non_mini_tab && index >= first_non_mini_tab)) { | 245 (to_position < first_non_mini_tab && index >= first_non_mini_tab)) { |
243 // This would result in mini tabs mixed with non-mini tabs. We don't allow | 246 // This would result in mini tabs mixed with non-mini tabs. We don't allow |
244 // that. | 247 // that. |
245 return; | 248 return; |
246 } | 249 } |
247 | 250 |
248 MoveTabContentsAtImpl(index, to_position, select_after_move); | 251 MoveTabContentsAtImpl(index, to_position, select_after_move); |
249 } | 252 } |
250 | 253 |
251 TabContents* TabStripModel::GetSelectedTabContents() const { | 254 TabContentsWrapper* TabStripModel::GetSelectedTabContents() const { |
252 return GetTabContentsAt(selected_index_); | 255 return GetTabContentsAt(selected_index_); |
253 } | 256 } |
254 | 257 |
255 TabContents* TabStripModel::GetTabContentsAt(int index) const { | 258 TabContentsWrapper* TabStripModel::GetTabContentsAt(int index) const { |
256 if (ContainsIndex(index)) | 259 if (ContainsIndex(index)) |
257 return GetContentsAt(index); | 260 return GetContentsAt(index); |
258 return NULL; | 261 return NULL; |
259 } | 262 } |
260 | 263 |
261 int TabStripModel::GetIndexOfTabContents(const TabContents* contents) const { | 264 int TabStripModel::GetIndexOfTabContents( |
| 265 const TabContentsWrapper* contents) const { |
262 int index = 0; | 266 int index = 0; |
263 TabContentsDataVector::const_iterator iter = contents_data_.begin(); | 267 TabContentsDataVector::const_iterator iter = contents_data_.begin(); |
264 for (; iter != contents_data_.end(); ++iter, ++index) { | 268 for (; iter != contents_data_.end(); ++iter, ++index) { |
265 if ((*iter)->contents == contents) | 269 if ((*iter)->contents == contents) |
266 return index; | 270 return index; |
267 } | 271 } |
268 return kNoTab; | 272 return kNoTab; |
269 } | 273 } |
270 | 274 |
| 275 int TabStripModel::GetWrapperIndex(const TabContents* contents) const { |
| 276 int index = 0; |
| 277 TabContentsDataVector::const_iterator iter = contents_data_.begin(); |
| 278 for (; iter != contents_data_.end(); ++iter, ++index) { |
| 279 if ((*iter)->contents->tab_contents() == contents) |
| 280 return index; |
| 281 } |
| 282 return kNoTab; |
| 283 } |
| 284 |
271 int TabStripModel::GetIndexOfController( | 285 int TabStripModel::GetIndexOfController( |
272 const NavigationController* controller) const { | 286 const NavigationController* controller) const { |
273 int index = 0; | 287 int index = 0; |
274 TabContentsDataVector::const_iterator iter = contents_data_.begin(); | 288 TabContentsDataVector::const_iterator iter = contents_data_.begin(); |
275 for (; iter != contents_data_.end(); ++iter, ++index) { | 289 for (; iter != contents_data_.end(); ++iter, ++index) { |
276 if (&(*iter)->contents->controller() == controller) | 290 if (&(*iter)->contents->controller() == controller) |
277 return index; | 291 return index; |
278 } | 292 } |
279 return kNoTab; | 293 return kNoTab; |
280 } | 294 } |
(...skipping 19 matching lines...) Expand all Loading... |
300 | 314 |
301 bool TabStripModel::CloseTabContentsAt(int index, uint32 close_types) { | 315 bool TabStripModel::CloseTabContentsAt(int index, uint32 close_types) { |
302 std::vector<int> closing_tabs; | 316 std::vector<int> closing_tabs; |
303 closing_tabs.push_back(index); | 317 closing_tabs.push_back(index); |
304 return InternalCloseTabs(closing_tabs, close_types); | 318 return InternalCloseTabs(closing_tabs, close_types); |
305 } | 319 } |
306 | 320 |
307 bool TabStripModel::TabsAreLoading() const { | 321 bool TabStripModel::TabsAreLoading() const { |
308 TabContentsDataVector::const_iterator iter = contents_data_.begin(); | 322 TabContentsDataVector::const_iterator iter = contents_data_.begin(); |
309 for (; iter != contents_data_.end(); ++iter) { | 323 for (; iter != contents_data_.end(); ++iter) { |
310 if ((*iter)->contents->is_loading()) | 324 if ((*iter)->contents->tab_contents()->is_loading()) |
311 return true; | 325 return true; |
312 } | 326 } |
313 return false; | 327 return false; |
314 } | 328 } |
315 | 329 |
316 NavigationController* TabStripModel::GetOpenerOfTabContentsAt(int index) { | 330 NavigationController* TabStripModel::GetOpenerOfTabContentsAt(int index) { |
317 DCHECK(ContainsIndex(index)); | 331 DCHECK(ContainsIndex(index)); |
318 return contents_data_.at(index)->opener; | 332 return contents_data_.at(index)->opener; |
319 } | 333 } |
320 | 334 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 for (; iter != end; --iter) { | 375 for (; iter != end; --iter) { |
362 next = iter - 1; | 376 next = iter - 1; |
363 if (next == end) | 377 if (next == end) |
364 break; | 378 break; |
365 if ((*next)->opener == opener) | 379 if ((*next)->opener == opener) |
366 return static_cast<int>(next - contents_data_.begin()); | 380 return static_cast<int>(next - contents_data_.begin()); |
367 } | 381 } |
368 return kNoTab; | 382 return kNoTab; |
369 } | 383 } |
370 | 384 |
371 void TabStripModel::TabNavigating(TabContents* contents, | 385 void TabStripModel::TabNavigating(TabContentsWrapper* contents, |
372 PageTransition::Type transition) { | 386 PageTransition::Type transition) { |
373 if (ShouldForgetOpenersForTransition(transition)) { | 387 if (ShouldForgetOpenersForTransition(transition)) { |
374 // Don't forget the openers if this tab is a New Tab page opened at the | 388 // Don't forget the openers if this tab is a New Tab page opened at the |
375 // end of the TabStrip (e.g. by pressing Ctrl+T). Give the user one | 389 // end of the TabStrip (e.g. by pressing Ctrl+T). Give the user one |
376 // navigation of one of these transition types before resetting the | 390 // navigation of one of these transition types before resetting the |
377 // opener relationships (this allows for the use case of opening a new | 391 // opener relationships (this allows for the use case of opening a new |
378 // tab to do a quick look-up of something while viewing a tab earlier in | 392 // tab to do a quick look-up of something while viewing a tab earlier in |
379 // the strip). We can make this heuristic more permissive if need be. | 393 // the strip). We can make this heuristic more permissive if need be. |
380 if (!IsNewTabAtEndOfTabStrip(contents)) { | 394 if (!IsNewTabAtEndOfTabStrip(contents)) { |
381 // If the user navigates the current tab to another page in any way | 395 // If the user navigates the current tab to another page in any way |
382 // other than by clicking a link, we want to pro-actively forget all | 396 // other than by clicking a link, we want to pro-actively forget all |
383 // TabStrip opener relationships since we assume they're beginning a | 397 // TabStrip opener relationships since we assume they're beginning a |
384 // different task by reusing the current tab. | 398 // different task by reusing the current tab. |
385 ForgetAllOpeners(); | 399 ForgetAllOpeners(); |
386 // In this specific case we also want to reset the group relationship, | 400 // In this specific case we also want to reset the group relationship, |
387 // since it is now technically invalid. | 401 // since it is now technically invalid. |
388 ForgetGroup(contents); | 402 ForgetGroup(contents); |
389 } | 403 } |
390 } | 404 } |
391 } | 405 } |
392 | 406 |
393 void TabStripModel::ForgetAllOpeners() { | 407 void TabStripModel::ForgetAllOpeners() { |
394 // Forget all opener memories so we don't do anything weird with tab | 408 // Forget all opener memories so we don't do anything weird with tab |
395 // re-selection ordering. | 409 // re-selection ordering. |
396 TabContentsDataVector::const_iterator iter = contents_data_.begin(); | 410 TabContentsDataVector::const_iterator iter = contents_data_.begin(); |
397 for (; iter != contents_data_.end(); ++iter) | 411 for (; iter != contents_data_.end(); ++iter) |
398 (*iter)->ForgetOpener(); | 412 (*iter)->ForgetOpener(); |
399 } | 413 } |
400 | 414 |
401 void TabStripModel::ForgetGroup(TabContents* contents) { | 415 void TabStripModel::ForgetGroup(TabContentsWrapper* contents) { |
402 int index = GetIndexOfTabContents(contents); | 416 int index = GetIndexOfTabContents(contents); |
403 DCHECK(ContainsIndex(index)); | 417 DCHECK(ContainsIndex(index)); |
404 contents_data_.at(index)->SetGroup(NULL); | 418 contents_data_.at(index)->SetGroup(NULL); |
405 contents_data_.at(index)->ForgetOpener(); | 419 contents_data_.at(index)->ForgetOpener(); |
406 } | 420 } |
407 | 421 |
408 bool TabStripModel::ShouldResetGroupOnSelect(TabContents* contents) const { | 422 bool TabStripModel::ShouldResetGroupOnSelect( |
| 423 TabContentsWrapper* contents) const { |
409 int index = GetIndexOfTabContents(contents); | 424 int index = GetIndexOfTabContents(contents); |
410 DCHECK(ContainsIndex(index)); | 425 DCHECK(ContainsIndex(index)); |
411 return contents_data_.at(index)->reset_group_on_select; | 426 return contents_data_.at(index)->reset_group_on_select; |
412 } | 427 } |
413 | 428 |
414 void TabStripModel::SetTabBlocked(int index, bool blocked) { | 429 void TabStripModel::SetTabBlocked(int index, bool blocked) { |
415 DCHECK(ContainsIndex(index)); | 430 DCHECK(ContainsIndex(index)); |
416 if (contents_data_[index]->blocked == blocked) | 431 if (contents_data_[index]->blocked == blocked) |
417 return; | 432 return; |
418 contents_data_[index]->blocked = blocked; | 433 contents_data_[index]->blocked = blocked; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 | 477 |
463 bool TabStripModel::IsTabPinned(int index) const { | 478 bool TabStripModel::IsTabPinned(int index) const { |
464 return contents_data_[index]->pinned; | 479 return contents_data_[index]->pinned; |
465 } | 480 } |
466 | 481 |
467 bool TabStripModel::IsMiniTab(int index) const { | 482 bool TabStripModel::IsMiniTab(int index) const { |
468 return IsTabPinned(index) || IsAppTab(index); | 483 return IsTabPinned(index) || IsAppTab(index); |
469 } | 484 } |
470 | 485 |
471 bool TabStripModel::IsAppTab(int index) const { | 486 bool TabStripModel::IsAppTab(int index) const { |
472 TabContents* contents = GetTabContentsAt(index); | 487 TabContentsWrapper* contents = GetTabContentsAt(index); |
473 return contents && contents->is_app(); | 488 return contents && contents->is_app(); |
474 } | 489 } |
475 | 490 |
476 bool TabStripModel::IsTabBlocked(int index) const { | 491 bool TabStripModel::IsTabBlocked(int index) const { |
477 return contents_data_[index]->blocked; | 492 return contents_data_[index]->blocked; |
478 } | 493 } |
479 | 494 |
480 int TabStripModel::IndexOfFirstNonMiniTab() const { | 495 int TabStripModel::IndexOfFirstNonMiniTab() const { |
481 for (size_t i = 0; i < contents_data_.size(); ++i) { | 496 for (size_t i = 0; i < contents_data_.size(); ++i) { |
482 if (!IsMiniTab(static_cast<int>(i))) | 497 if (!IsMiniTab(static_cast<int>(i))) |
483 return static_cast<int>(i); | 498 return static_cast<int>(i); |
484 } | 499 } |
485 // No mini-tabs. | 500 // No mini-tabs. |
486 return count(); | 501 return count(); |
487 } | 502 } |
488 | 503 |
489 int TabStripModel::ConstrainInsertionIndex(int index, bool mini_tab) { | 504 int TabStripModel::ConstrainInsertionIndex(int index, bool mini_tab) { |
490 return mini_tab ? std::min(std::max(0, index), IndexOfFirstNonMiniTab()) : | 505 return mini_tab ? std::min(std::max(0, index), IndexOfFirstNonMiniTab()) : |
491 std::min(count(), std::max(index, IndexOfFirstNonMiniTab())); | 506 std::min(count(), std::max(index, IndexOfFirstNonMiniTab())); |
492 } | 507 } |
493 | 508 |
494 void TabStripModel::AddTabContents(TabContents* contents, | 509 void TabStripModel::AddTabContents(TabContentsWrapper* contents, |
495 int index, | 510 int index, |
496 PageTransition::Type transition, | 511 PageTransition::Type transition, |
497 int add_types) { | 512 int add_types) { |
498 // If the newly-opened tab is part of the same task as the parent tab, we want | 513 // If the newly-opened tab is part of the same task as the parent tab, we want |
499 // to inherit the parent's "group" attribute, so that if this tab is then | 514 // to inherit the parent's "group" attribute, so that if this tab is then |
500 // closed we'll jump back to the parent tab. | 515 // closed we'll jump back to the parent tab. |
501 bool inherit_group = (add_types & ADD_INHERIT_GROUP) == ADD_INHERIT_GROUP; | 516 bool inherit_group = (add_types & ADD_INHERIT_GROUP) == ADD_INHERIT_GROUP; |
502 | 517 |
503 if (transition == PageTransition::LINK && | 518 if (transition == PageTransition::LINK && |
504 (add_types & ADD_FORCE_INDEX) == 0) { | 519 (add_types & ADD_FORCE_INDEX) == 0) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
538 // TODO(sky): figure out why this is here and not in InsertTabContentsAt. When | 553 // TODO(sky): figure out why this is here and not in InsertTabContentsAt. When |
539 // here we seem to get failures in startup perf tests. | 554 // here we seem to get failures in startup perf tests. |
540 // Ensure that the new TabContentsView begins at the same size as the | 555 // Ensure that the new TabContentsView begins at the same size as the |
541 // previous TabContentsView if it existed. Otherwise, the initial WebKit | 556 // previous TabContentsView if it existed. Otherwise, the initial WebKit |
542 // layout will be performed based on a width of 0 pixels, causing a | 557 // layout will be performed based on a width of 0 pixels, causing a |
543 // very long, narrow, inaccurate layout. Because some scripts on pages (as | 558 // very long, narrow, inaccurate layout. Because some scripts on pages (as |
544 // well as WebKit's anchor link location calculation) are run on the | 559 // well as WebKit's anchor link location calculation) are run on the |
545 // initial layout and not recalculated later, we need to ensure the first | 560 // initial layout and not recalculated later, we need to ensure the first |
546 // layout is performed with sane view dimensions even when we're opening a | 561 // layout is performed with sane view dimensions even when we're opening a |
547 // new background tab. | 562 // new background tab. |
548 if (TabContents* old_contents = GetSelectedTabContents()) { | 563 if (TabContentsWrapper* old_contents = GetSelectedTabContents()) { |
549 if ((add_types & ADD_SELECTED) == 0) { | 564 if ((add_types & ADD_SELECTED) == 0) { |
550 contents->view()->SizeContents(old_contents->view()->GetContainerSize()); | 565 contents->tab_contents()->view()-> |
| 566 SizeContents(old_contents->tab_contents()-> |
| 567 view()->GetContainerSize()); |
551 // We need to hide the contents or else we get and execute paints for | 568 // We need to hide the contents or else we get and execute paints for |
552 // background tabs. With enough background tabs they will steal the | 569 // background tabs. With enough background tabs they will steal the |
553 // backing store of the visible tab causing flashing. See bug 20831. | 570 // backing store of the visible tab causing flashing. See bug 20831. |
554 contents->HideContents(); | 571 contents->tab_contents()->HideContents(); |
555 } | 572 } |
556 } | 573 } |
557 } | 574 } |
558 | 575 |
559 void TabStripModel::CloseSelectedTab() { | 576 void TabStripModel::CloseSelectedTab() { |
560 CloseTabContentsAt(selected_index_, CLOSE_CREATE_HISTORICAL_TAB); | 577 CloseTabContentsAt(selected_index_, CLOSE_CREATE_HISTORICAL_TAB); |
561 } | 578 } |
562 | 579 |
563 void TabStripModel::SelectNextTab() { | 580 void TabStripModel::SelectNextTab() { |
564 SelectRelativeTab(true); | 581 SelectRelativeTab(true); |
(...skipping 19 matching lines...) Expand all Loading... |
584 | 601 |
585 // Context menu functions. | 602 // Context menu functions. |
586 bool TabStripModel::IsContextMenuCommandEnabled( | 603 bool TabStripModel::IsContextMenuCommandEnabled( |
587 int context_index, ContextMenuCommand command_id) const { | 604 int context_index, ContextMenuCommand command_id) const { |
588 DCHECK(command_id > CommandFirst && command_id < CommandLast); | 605 DCHECK(command_id > CommandFirst && command_id < CommandLast); |
589 switch (command_id) { | 606 switch (command_id) { |
590 case CommandNewTab: | 607 case CommandNewTab: |
591 case CommandCloseTab: | 608 case CommandCloseTab: |
592 return delegate_->CanCloseTab(); | 609 return delegate_->CanCloseTab(); |
593 case CommandReload: | 610 case CommandReload: |
594 if (TabContents* contents = GetTabContentsAt(context_index)) { | 611 if (TabContentsWrapper* contents = GetTabContentsAt(context_index)) { |
595 return contents->delegate()->CanReloadContents(contents); | 612 return contents->tab_contents()-> |
| 613 delegate()->CanReloadContents(contents->tab_contents()); |
596 } else { | 614 } else { |
597 return false; | 615 return false; |
598 } | 616 } |
599 case CommandCloseOtherTabs: { | 617 case CommandCloseOtherTabs: { |
600 int mini_tab_count = IndexOfFirstNonMiniTab(); | 618 int mini_tab_count = IndexOfFirstNonMiniTab(); |
601 int non_mini_tab_count = count() - mini_tab_count; | 619 int non_mini_tab_count = count() - mini_tab_count; |
602 // Close other doesn't effect mini-tabs. | 620 // Close other doesn't effect mini-tabs. |
603 return non_mini_tab_count > 1 || | 621 return non_mini_tab_count > 1 || |
604 (non_mini_tab_count == 1 && context_index != mini_tab_count); | 622 (non_mini_tab_count == 1 && context_index != mini_tab_count); |
605 } | 623 } |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
739 // TabStripModel, NotificationObserver implementation: | 757 // TabStripModel, NotificationObserver implementation: |
740 | 758 |
741 void TabStripModel::Observe(NotificationType type, | 759 void TabStripModel::Observe(NotificationType type, |
742 const NotificationSource& source, | 760 const NotificationSource& source, |
743 const NotificationDetails& details) { | 761 const NotificationDetails& details) { |
744 switch (type.value) { | 762 switch (type.value) { |
745 case NotificationType::TAB_CONTENTS_DESTROYED: { | 763 case NotificationType::TAB_CONTENTS_DESTROYED: { |
746 // Sometimes, on qemu, it seems like a TabContents object can be destroyed | 764 // Sometimes, on qemu, it seems like a TabContents object can be destroyed |
747 // while we still have a reference to it. We need to break this reference | 765 // while we still have a reference to it. We need to break this reference |
748 // here so we don't crash later. | 766 // here so we don't crash later. |
749 int index = GetIndexOfTabContents(Source<TabContents>(source).ptr()); | 767 int index = GetWrapperIndex(Source<TabContents>(source).ptr()); |
750 if (index != TabStripModel::kNoTab) { | 768 if (index != TabStripModel::kNoTab) { |
751 // Note that we only detach the contents here, not close it - it's | 769 // Note that we only detach the contents here, not close it - it's |
752 // already been closed. We just want to undo our bookkeeping. | 770 // already been closed. We just want to undo our bookkeeping. |
753 DetachTabContentsAt(index); | 771 DetachTabContentsAt(index); |
754 } | 772 } |
755 break; | 773 break; |
756 } | 774 } |
757 | 775 |
758 case NotificationType::EXTENSION_UNLOADED: { | 776 case NotificationType::EXTENSION_UNLOADED: { |
759 const Extension* extension = Details<const Extension>(details).ptr(); | 777 const Extension* extension = Details<const Extension>(details).ptr(); |
760 // Iterate backwards as we may remove items while iterating. | 778 // Iterate backwards as we may remove items while iterating. |
761 for (int i = count() - 1; i >= 0; i--) { | 779 for (int i = count() - 1; i >= 0; i--) { |
762 TabContents* contents = GetTabContentsAt(i); | 780 TabContentsWrapper* contents = GetTabContentsAt(i); |
763 if (contents->extension_app() == extension) { | 781 if (contents->extension_app() == extension) { |
764 // The extension an app tab was created from has been nuked. Delete | 782 // The extension an app tab was created from has been nuked. Delete |
765 // the TabContents. Deleting a TabContents results in a notification | 783 // the TabContents. Deleting a TabContents results in a notification |
766 // of type TAB_CONTENTS_DESTROYED; we do the necessary cleanup in | 784 // of type TAB_CONTENTS_DESTROYED; we do the necessary cleanup in |
767 // handling that notification. | 785 // handling that notification. |
768 | 786 |
769 InternalCloseTab(contents, i, false); | 787 InternalCloseTab(contents, i, false); |
770 } | 788 } |
771 } | 789 } |
772 break; | 790 break; |
773 } | 791 } |
774 | 792 |
775 default: | 793 default: |
776 NOTREACHED(); | 794 NOTREACHED(); |
777 } | 795 } |
778 } | 796 } |
779 | 797 |
780 /////////////////////////////////////////////////////////////////////////////// | 798 /////////////////////////////////////////////////////////////////////////////// |
781 // TabStripModel, private: | 799 // TabStripModel, private: |
782 | 800 |
783 bool TabStripModel::IsNewTabAtEndOfTabStrip(TabContents* contents) const { | 801 bool TabStripModel::IsNewTabAtEndOfTabStrip( |
784 return LowerCaseEqualsASCII(contents->GetURL().spec(), | 802 TabContentsWrapper* contents) const { |
| 803 return LowerCaseEqualsASCII(contents->tab_contents()->GetURL().spec(), |
785 chrome::kChromeUINewTabURL) && | 804 chrome::kChromeUINewTabURL) && |
786 contents == GetContentsAt(count() - 1) && | 805 contents == GetContentsAt(count() - 1) && |
787 contents->controller().entry_count() == 1; | 806 contents->controller().entry_count() == 1; |
788 } | 807 } |
789 | 808 |
790 bool TabStripModel::InternalCloseTabs(const std::vector<int>& indices, | 809 bool TabStripModel::InternalCloseTabs(const std::vector<int>& indices, |
791 uint32 close_types) { | 810 uint32 close_types) { |
792 if (indices.empty()) | 811 if (indices.empty()) |
793 return true; | 812 return true; |
794 | 813 |
795 bool retval = true; | 814 bool retval = true; |
796 | 815 |
797 // Map the indices to TabContents, that way if deleting a tab deletes other | 816 // Map the indices to TabContents, that way if deleting a tab deletes other |
798 // tabs we're ok. Crashes seem to indicate during tab deletion other tabs are | 817 // tabs we're ok. Crashes seem to indicate during tab deletion other tabs are |
799 // getting removed. | 818 // getting removed. |
800 std::vector<TabContents*> tabs; | 819 std::vector<TabContentsWrapper*> tabs; |
801 for (size_t i = 0; i < indices.size(); ++i) | 820 for (size_t i = 0; i < indices.size(); ++i) |
802 tabs.push_back(GetContentsAt(indices[i])); | 821 tabs.push_back(GetContentsAt(indices[i])); |
803 | 822 |
804 // We only try the fast shutdown path if the whole browser process is *not* | 823 // We only try the fast shutdown path if the whole browser process is *not* |
805 // shutting down. Fast shutdown during browser termination is handled in | 824 // shutting down. Fast shutdown during browser termination is handled in |
806 // BrowserShutdown. | 825 // BrowserShutdown. |
807 if (browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID) { | 826 if (browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID) { |
808 // Construct a map of processes to the number of associated tabs that are | 827 // Construct a map of processes to the number of associated tabs that are |
809 // closing. | 828 // closing. |
810 std::map<RenderProcessHost*, size_t> processes; | 829 std::map<RenderProcessHost*, size_t> processes; |
811 for (size_t i = 0; i < indices.size(); ++i) { | 830 for (size_t i = 0; i < indices.size(); ++i) { |
812 if (!delegate_->CanCloseContentsAt(indices[i])) { | 831 if (!delegate_->CanCloseContentsAt(indices[i])) { |
813 retval = false; | 832 retval = false; |
814 continue; | 833 continue; |
815 } | 834 } |
816 | 835 |
817 TabContents* detached_contents = GetContentsAt(indices[i]); | 836 TabContentsWrapper* detached_contents = GetContentsAt(indices[i]); |
818 RenderProcessHost* process = detached_contents->GetRenderProcessHost(); | 837 RenderProcessHost* process = |
| 838 detached_contents->tab_contents()->GetRenderProcessHost(); |
819 std::map<RenderProcessHost*, size_t>::iterator iter = | 839 std::map<RenderProcessHost*, size_t>::iterator iter = |
820 processes.find(process); | 840 processes.find(process); |
821 if (iter == processes.end()) { | 841 if (iter == processes.end()) { |
822 processes[process] = 1; | 842 processes[process] = 1; |
823 } else { | 843 } else { |
824 iter->second++; | 844 iter->second++; |
825 } | 845 } |
826 } | 846 } |
827 | 847 |
828 // Try to fast shutdown the tabs that can close. | 848 // Try to fast shutdown the tabs that can close. |
829 for (std::map<RenderProcessHost*, size_t>::iterator iter = | 849 for (std::map<RenderProcessHost*, size_t>::iterator iter = |
830 processes.begin(); | 850 processes.begin(); |
831 iter != processes.end(); ++iter) { | 851 iter != processes.end(); ++iter) { |
832 iter->first->FastShutdownForPageCount(iter->second); | 852 iter->first->FastShutdownForPageCount(iter->second); |
833 } | 853 } |
834 } | 854 } |
835 | 855 |
836 // We now return to our regularly scheduled shutdown procedure. | 856 // We now return to our regularly scheduled shutdown procedure. |
837 for (size_t i = 0; i < tabs.size(); ++i) { | 857 for (size_t i = 0; i < tabs.size(); ++i) { |
838 TabContents* detached_contents = tabs[i]; | 858 TabContentsWrapper* detached_contents = tabs[i]; |
839 int index = GetIndexOfTabContents(detached_contents); | 859 int index = GetIndexOfTabContents(detached_contents); |
840 // Make sure we still contain the tab. | 860 // Make sure we still contain the tab. |
841 if (index == kNoTab) | 861 if (index == kNoTab) |
842 continue; | 862 continue; |
843 | 863 |
844 detached_contents->OnCloseStarted(); | 864 detached_contents->tab_contents()->OnCloseStarted(); |
845 | 865 |
846 if (!delegate_->CanCloseContentsAt(index)) { | 866 if (!delegate_->CanCloseContentsAt(index)) { |
847 retval = false; | 867 retval = false; |
848 continue; | 868 continue; |
849 } | 869 } |
850 | 870 |
851 // Update the explicitly closed state. If the unload handlers cancel the | 871 // Update the explicitly closed state. If the unload handlers cancel the |
852 // close the state is reset in Browser. We don't update the explicitly | 872 // close the state is reset in Browser. We don't update the explicitly |
853 // closed state if already marked as explicitly closed as unload handlers | 873 // closed state if already marked as explicitly closed as unload handlers |
854 // call back to this if the close is allowed. | 874 // call back to this if the close is allowed. |
855 if (!detached_contents->closed_by_user_gesture()) { | 875 if (!detached_contents->tab_contents()->closed_by_user_gesture()) { |
856 detached_contents->set_closed_by_user_gesture( | 876 detached_contents->tab_contents()->set_closed_by_user_gesture( |
857 close_types & CLOSE_USER_GESTURE); | 877 close_types & CLOSE_USER_GESTURE); |
858 } | 878 } |
859 | 879 |
860 if (delegate_->RunUnloadListenerBeforeClosing(detached_contents)) { | 880 if (delegate_->RunUnloadListenerBeforeClosing(detached_contents)) { |
861 retval = false; | 881 retval = false; |
862 continue; | 882 continue; |
863 } | 883 } |
864 | 884 |
865 InternalCloseTab(detached_contents, index, | 885 InternalCloseTab(detached_contents, index, |
866 (close_types & CLOSE_CREATE_HISTORICAL_TAB) != 0); | 886 (close_types & CLOSE_CREATE_HISTORICAL_TAB) != 0); |
867 } | 887 } |
868 | 888 |
869 return retval; | 889 return retval; |
870 } | 890 } |
871 | 891 |
872 void TabStripModel::InternalCloseTab(TabContents* contents, | 892 void TabStripModel::InternalCloseTab(TabContentsWrapper* contents, |
873 int index, | 893 int index, |
874 bool create_historical_tabs) { | 894 bool create_historical_tabs) { |
875 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, | 895 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, |
876 TabClosingAt(this, contents, index)); | 896 TabClosingAt(this, contents, index)); |
877 | 897 |
878 // Ask the delegate to save an entry for this tab in the historical tab | 898 // Ask the delegate to save an entry for this tab in the historical tab |
879 // database if applicable. | 899 // database if applicable. |
880 if (create_historical_tabs) | 900 if (create_historical_tabs) |
881 delegate_->CreateHistoricalTab(contents); | 901 delegate_->CreateHistoricalTab(contents); |
882 | 902 |
883 // Deleting the TabContents will call back to us via NotificationObserver | 903 // Deleting the TabContents will call back to us via NotificationObserver |
884 // and detach it. | 904 // and detach it. |
885 delete contents; | 905 delete contents; |
886 } | 906 } |
887 | 907 |
888 TabContents* TabStripModel::GetContentsAt(int index) const { | 908 TabContentsWrapper* TabStripModel::GetContentsAt(int index) const { |
889 CHECK(ContainsIndex(index)) << | 909 CHECK(ContainsIndex(index)) << |
890 "Failed to find: " << index << " in: " << count() << " entries."; | 910 "Failed to find: " << index << " in: " << count() << " entries."; |
891 return contents_data_.at(index)->contents; | 911 return contents_data_.at(index)->contents; |
892 } | 912 } |
893 | 913 |
894 void TabStripModel::ChangeSelectedContentsFrom( | 914 void TabStripModel::ChangeSelectedContentsFrom( |
895 TabContents* old_contents, int to_index, bool user_gesture) { | 915 TabContentsWrapper* old_contents, int to_index, bool user_gesture) { |
896 TabContents* new_contents = GetContentsAt(to_index); | 916 TabContentsWrapper* new_contents = GetContentsAt(to_index); |
897 if (old_contents == new_contents) | 917 if (old_contents == new_contents) |
898 return; | 918 return; |
899 | 919 |
900 TabContents* last_selected_contents = old_contents; | 920 TabContentsWrapper* last_selected_contents = old_contents; |
901 if (last_selected_contents) { | 921 if (last_selected_contents) { |
902 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, | 922 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, |
903 TabDeselectedAt(last_selected_contents, selected_index_)); | 923 TabDeselectedAt(last_selected_contents, selected_index_)); |
904 } | 924 } |
905 | 925 |
906 selected_index_ = to_index; | 926 selected_index_ = to_index; |
| 927 ObserverListBase<TabStripModelObserver>::Iterator it(observers_); |
| 928 TabStripModelObserver* obs; |
| 929 while ((obs = it.GetNext()) != NULL) |
| 930 obs->TabSelectedAt(last_selected_contents, new_contents, selected_index_, us
er_gesture); |
| 931 /* |
907 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, | 932 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, |
908 TabSelectedAt(last_selected_contents, new_contents, selected_index_, | 933 TabSelectedAt(last_selected_contents, new_contents, selected_index_, |
909 user_gesture)); | 934 user_gesture)); |
| 935 */ |
910 } | 936 } |
911 | 937 |
912 void TabStripModel::SelectRelativeTab(bool next) { | 938 void TabStripModel::SelectRelativeTab(bool next) { |
913 // This may happen during automated testing or if a user somehow buffers | 939 // This may happen during automated testing or if a user somehow buffers |
914 // many key accelerators. | 940 // many key accelerators. |
915 if (contents_data_.empty()) | 941 if (contents_data_.empty()) |
916 return; | 942 return; |
917 | 943 |
918 int index = selected_index_; | 944 int index = selected_index_; |
919 int delta = next ? 1 : -1; | 945 int delta = next ? 1 : -1; |
(...skipping 19 matching lines...) Expand all Loading... |
939 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, | 965 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, |
940 TabMoved(moved_data->contents, index, to_position)); | 966 TabMoved(moved_data->contents, index, to_position)); |
941 } | 967 } |
942 | 968 |
943 // static | 969 // static |
944 bool TabStripModel::OpenerMatches(const TabContentsData* data, | 970 bool TabStripModel::OpenerMatches(const TabContentsData* data, |
945 const NavigationController* opener, | 971 const NavigationController* opener, |
946 bool use_group) { | 972 bool use_group) { |
947 return data->opener == opener || (use_group && data->group == opener); | 973 return data->opener == opener || (use_group && data->group == opener); |
948 } | 974 } |
OLD | NEW |