| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 5 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <string> | 9 #include <string> |
| 10 | 10 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 | 62 |
| 63 /////////////////////////////////////////////////////////////////////////////// | 63 /////////////////////////////////////////////////////////////////////////////// |
| 64 // TabStripModel, public: | 64 // TabStripModel, public: |
| 65 | 65 |
| 66 TabStripModel::TabStripModel(TabStripModelDelegate* delegate, Profile* profile) | 66 TabStripModel::TabStripModel(TabStripModelDelegate* delegate, Profile* profile) |
| 67 : delegate_(delegate), | 67 : delegate_(delegate), |
| 68 profile_(profile), | 68 profile_(profile), |
| 69 closing_all_(false), | 69 closing_all_(false), |
| 70 order_controller_(NULL) { | 70 order_controller_(NULL) { |
| 71 DCHECK(delegate_); | 71 DCHECK(delegate_); |
| 72 registrar_.Add(this, | 72 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED, |
| 73 chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED, | |
| 74 content::NotificationService::AllBrowserContextsAndSources()); | 73 content::NotificationService::AllBrowserContextsAndSources()); |
| 75 registrar_.Add(this, | 74 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
| 76 chrome::NOTIFICATION_EXTENSION_UNLOADED, | |
| 77 content::Source<Profile>(profile_)); | 75 content::Source<Profile>(profile_)); |
| 78 order_controller_ = new TabStripModelOrderController(this); | 76 order_controller_ = new TabStripModelOrderController(this); |
| 79 } | 77 } |
| 80 | 78 |
| 81 TabStripModel::~TabStripModel() { | 79 TabStripModel::~TabStripModel() { |
| 82 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, | 80 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, |
| 83 TabStripModelDeleted()); | 81 TabStripModelDeleted()); |
| 84 STLDeleteElements(&contents_data_); | 82 STLDeleteElements(&contents_data_); |
| 85 delete order_controller_; | 83 delete order_controller_; |
| 86 } | 84 } |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 return GetTabContentsAt(active_index()); | 351 return GetTabContentsAt(active_index()); |
| 354 } | 352 } |
| 355 | 353 |
| 356 TabContents* TabStripModel::GetTabContentsAt(int index) const { | 354 TabContents* TabStripModel::GetTabContentsAt(int index) const { |
| 357 if (ContainsIndex(index)) | 355 if (ContainsIndex(index)) |
| 358 return GetContentsAt(index); | 356 return GetContentsAt(index); |
| 359 return NULL; | 357 return NULL; |
| 360 } | 358 } |
| 361 | 359 |
| 362 int TabStripModel::GetIndexOfTabContents(const TabContents* contents) const { | 360 int TabStripModel::GetIndexOfTabContents(const TabContents* contents) const { |
| 363 int index = 0; | 361 for (size_t i = 0; i < contents_data_.size(); ++i) { |
| 364 TabContentsDataVector::const_iterator iter = contents_data_.begin(); | 362 if (contents_data_[i]->contents == contents) |
| 365 for (; iter != contents_data_.end(); ++iter, ++index) { | 363 return i; |
| 366 if ((*iter)->contents == contents) | |
| 367 return index; | |
| 368 } | 364 } |
| 369 return kNoTab; | 365 return kNoTab; |
| 370 } | 366 } |
| 371 | 367 |
| 372 int TabStripModel::GetIndexOfWebContents(const WebContents* contents) const { | 368 int TabStripModel::GetIndexOfWebContents(const WebContents* contents) const { |
| 373 int index = 0; | 369 return contents ? |
| 374 TabContentsDataVector::const_iterator iter = contents_data_.begin(); | 370 GetIndexOfTabContents(TabContents::FromWebContents(contents)) : kNoTab; |
| 375 for (; iter != contents_data_.end(); ++iter, ++index) { | |
| 376 if ((*iter)->contents->web_contents() == contents) | |
| 377 return index; | |
| 378 } | |
| 379 return kNoTab; | |
| 380 } | 371 } |
| 381 | 372 |
| 382 void TabStripModel::UpdateTabContentsStateAt(int index, | 373 void TabStripModel::UpdateTabContentsStateAt(int index, |
| 383 TabStripModelObserver::TabChangeType change_type) { | 374 TabStripModelObserver::TabChangeType change_type) { |
| 384 DCHECK(ContainsIndex(index)); | 375 DCHECK(ContainsIndex(index)); |
| 385 | 376 |
| 386 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, | 377 FOR_EACH_OBSERVER(TabStripModelObserver, observers_, |
| 387 TabChangedAt(GetContentsAt(index), index, change_type)); | 378 TabChangedAt(GetContentsAt(index), index, change_type)); |
| 388 } | 379 } |
| 389 | 380 |
| 390 void TabStripModel::CloseAllTabs() { | 381 void TabStripModel::CloseAllTabs() { |
| 391 // Set state so that observers can adjust their behavior to suit this | 382 // Set state so that observers can adjust their behavior to suit this |
| 392 // specific condition when CloseTabContentsAt causes a flurry of | 383 // specific condition when CloseTabContentsAt causes a flurry of |
| 393 // Close/Detach/Select notifications to be sent. | 384 // Close/Detach/Select notifications to be sent. |
| 394 closing_all_ = true; | 385 closing_all_ = true; |
| 395 std::vector<int> closing_tabs; | 386 std::vector<int> closing_tabs; |
| 396 for (int i = count() - 1; i >= 0; --i) | 387 for (int i = count() - 1; i >= 0; --i) |
| 397 closing_tabs.push_back(i); | 388 closing_tabs.push_back(i); |
| 398 InternalCloseTabs(closing_tabs, CLOSE_CREATE_HISTORICAL_TAB); | 389 InternalCloseTabs(closing_tabs, CLOSE_CREATE_HISTORICAL_TAB); |
| 399 } | 390 } |
| 400 | 391 |
| 401 bool TabStripModel::CloseTabContentsAt(int index, uint32 close_types) { | 392 bool TabStripModel::CloseTabContentsAt(int index, uint32 close_types) { |
| 402 std::vector<int> closing_tabs; | 393 std::vector<int> closing_tabs; |
| 403 closing_tabs.push_back(index); | 394 closing_tabs.push_back(index); |
| 404 return InternalCloseTabs(closing_tabs, close_types); | 395 return InternalCloseTabs(closing_tabs, close_types); |
| 405 } | 396 } |
| 406 | 397 |
| 407 bool TabStripModel::TabsAreLoading() const { | 398 bool TabStripModel::TabsAreLoading() const { |
| 408 TabContentsDataVector::const_iterator iter = contents_data_.begin(); | 399 for (TabContentsDataVector::const_iterator iter = contents_data_.begin(); |
| 409 for (; iter != contents_data_.end(); ++iter) { | 400 iter != contents_data_.end(); ++iter) { |
| 410 if ((*iter)->contents->web_contents()->IsLoading()) | 401 if ((*iter)->contents->web_contents()->IsLoading()) |
| 411 return true; | 402 return true; |
| 412 } | 403 } |
| 413 return false; | 404 return false; |
| 414 } | 405 } |
| 415 | 406 |
| 416 NavigationController* TabStripModel::GetOpenerOfTabContentsAt(int index) { | 407 NavigationController* TabStripModel::GetOpenerOfTabContentsAt(int index) { |
| 417 DCHECK(ContainsIndex(index)); | 408 DCHECK(ContainsIndex(index)); |
| 418 return contents_data_[index]->opener; | 409 return contents_data_[index]->opener; |
| 419 } | 410 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 440 } | 431 } |
| 441 // Then check tabs before start_index, iterating backwards. | 432 // Then check tabs before start_index, iterating backwards. |
| 442 for (int i = start_index - 1; i >= 0; --i) { | 433 for (int i = start_index - 1; i >= 0; --i) { |
| 443 if (OpenerMatches(contents_data_[i], opener, use_group)) | 434 if (OpenerMatches(contents_data_[i], opener, use_group)) |
| 444 return i; | 435 return i; |
| 445 } | 436 } |
| 446 return kNoTab; | 437 return kNoTab; |
| 447 } | 438 } |
| 448 | 439 |
| 449 int TabStripModel::GetIndexOfFirstTabContentsOpenedBy( | 440 int TabStripModel::GetIndexOfFirstTabContentsOpenedBy( |
| 450 const NavigationController* opener, int start_index) const { | 441 const NavigationController* opener, |
| 442 int start_index) const { |
| 451 DCHECK(opener); | 443 DCHECK(opener); |
| 452 DCHECK(ContainsIndex(start_index)); | 444 DCHECK(ContainsIndex(start_index)); |
| 453 | 445 |
| 454 for (int i = 0; i < start_index; ++i) { | 446 for (int i = 0; i < start_index; ++i) { |
| 455 if (contents_data_[i]->opener == opener) | 447 if (contents_data_[i]->opener == opener) |
| 456 return i; | 448 return i; |
| 457 } | 449 } |
| 458 return kNoTab; | 450 return kNoTab; |
| 459 } | 451 } |
| 460 | 452 |
| 461 int TabStripModel::GetIndexOfLastTabContentsOpenedBy( | 453 int TabStripModel::GetIndexOfLastTabContentsOpenedBy( |
| 462 const NavigationController* opener, int start_index) const { | 454 const NavigationController* opener, |
| 455 int start_index) const { |
| 463 DCHECK(opener); | 456 DCHECK(opener); |
| 464 DCHECK(ContainsIndex(start_index)); | 457 DCHECK(ContainsIndex(start_index)); |
| 465 | 458 |
| 466 TabContentsDataVector::const_iterator end = | 459 for (int i = contents_data_.size() - 1; i > start_index; --i) { |
| 467 contents_data_.begin() + start_index; | 460 if (contents_data_[i]->opener == opener) |
| 468 TabContentsDataVector::const_iterator iter = contents_data_.end(); | 461 return i; |
| 469 TabContentsDataVector::const_iterator next; | |
| 470 for (; iter != end; --iter) { | |
| 471 next = iter - 1; | |
| 472 if (next == end) | |
| 473 break; | |
| 474 if ((*next)->opener == opener) | |
| 475 return static_cast<int>(next - contents_data_.begin()); | |
| 476 } | 462 } |
| 477 return kNoTab; | 463 return kNoTab; |
| 478 } | 464 } |
| 479 | 465 |
| 480 void TabStripModel::TabNavigating(TabContents* contents, | 466 void TabStripModel::TabNavigating(TabContents* contents, |
| 481 content::PageTransition transition) { | 467 content::PageTransition transition) { |
| 482 if (ShouldForgetOpenersForTransition(transition)) { | 468 if (ShouldForgetOpenersForTransition(transition)) { |
| 483 // Don't forget the openers if this tab is a New Tab page opened at the | 469 // Don't forget the openers if this tab is a New Tab page opened at the |
| 484 // end of the TabStrip (e.g. by pressing Ctrl+T). Give the user one | 470 // end of the TabStrip (e.g. by pressing Ctrl+T). Give the user one |
| 485 // navigation of one of these transition types before resetting the | 471 // navigation of one of these transition types before resetting the |
| 486 // opener relationships (this allows for the use case of opening a new | 472 // opener relationships (this allows for the use case of opening a new |
| 487 // tab to do a quick look-up of something while viewing a tab earlier in | 473 // tab to do a quick look-up of something while viewing a tab earlier in |
| 488 // the strip). We can make this heuristic more permissive if need be. | 474 // the strip). We can make this heuristic more permissive if need be. |
| 489 if (!IsNewTabAtEndOfTabStrip(contents)) { | 475 if (!IsNewTabAtEndOfTabStrip(contents)) { |
| 490 // If the user navigates the current tab to another page in any way | 476 // If the user navigates the current tab to another page in any way |
| 491 // other than by clicking a link, we want to pro-actively forget all | 477 // other than by clicking a link, we want to pro-actively forget all |
| 492 // TabStrip opener relationships since we assume they're beginning a | 478 // TabStrip opener relationships since we assume they're beginning a |
| 493 // different task by reusing the current tab. | 479 // different task by reusing the current tab. |
| 494 ForgetAllOpeners(); | 480 ForgetAllOpeners(); |
| 495 // In this specific case we also want to reset the group relationship, | 481 // In this specific case we also want to reset the group relationship, |
| 496 // since it is now technically invalid. | 482 // since it is now technically invalid. |
| 497 ForgetGroup(contents); | 483 ForgetGroup(contents); |
| 498 } | 484 } |
| 499 } | 485 } |
| 500 } | 486 } |
| 501 | 487 |
| 502 void TabStripModel::ForgetAllOpeners() { | 488 void TabStripModel::ForgetAllOpeners() { |
| 503 // Forget all opener memories so we don't do anything weird with tab | 489 // Forget all opener memories so we don't do anything weird with tab |
| 504 // re-selection ordering. | 490 // re-selection ordering. |
| 505 TabContentsDataVector::const_iterator iter = contents_data_.begin(); | 491 for (TabContentsDataVector::const_iterator iter = contents_data_.begin(); |
| 506 for (; iter != contents_data_.end(); ++iter) | 492 iter != contents_data_.end(); ++iter) |
| 507 (*iter)->ForgetOpener(); | 493 (*iter)->ForgetOpener(); |
| 508 } | 494 } |
| 509 | 495 |
| 510 void TabStripModel::ForgetGroup(TabContents* contents) { | 496 void TabStripModel::ForgetGroup(TabContents* contents) { |
| 511 int index = GetIndexOfTabContents(contents); | 497 int index = GetIndexOfTabContents(contents); |
| 512 DCHECK(ContainsIndex(index)); | 498 DCHECK(ContainsIndex(index)); |
| 513 contents_data_[index]->SetGroup(NULL); | 499 contents_data_[index]->SetGroup(NULL); |
| 514 contents_data_[index]->ForgetOpener(); | 500 contents_data_[index]->ForgetOpener(); |
| 515 } | 501 } |
| 516 | 502 |
| (...skipping 623 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1140 processes.find(process); | 1126 processes.find(process); |
| 1141 if (iter == processes.end()) { | 1127 if (iter == processes.end()) { |
| 1142 processes[process] = 1; | 1128 processes[process] = 1; |
| 1143 } else { | 1129 } else { |
| 1144 iter->second++; | 1130 iter->second++; |
| 1145 } | 1131 } |
| 1146 } | 1132 } |
| 1147 | 1133 |
| 1148 // Try to fast shutdown the tabs that can close. | 1134 // Try to fast shutdown the tabs that can close. |
| 1149 for (std::map<content::RenderProcessHost*, size_t>::iterator iter = | 1135 for (std::map<content::RenderProcessHost*, size_t>::iterator iter = |
| 1150 processes.begin(); | 1136 processes.begin(); iter != processes.end(); ++iter) { |
| 1151 iter != processes.end(); ++iter) { | |
| 1152 iter->first->FastShutdownForPageCount(iter->second); | 1137 iter->first->FastShutdownForPageCount(iter->second); |
| 1153 } | 1138 } |
| 1154 } | 1139 } |
| 1155 | 1140 |
| 1156 // We now return to our regularly scheduled shutdown procedure. | 1141 // We now return to our regularly scheduled shutdown procedure. |
| 1157 bool retval = true; | 1142 bool retval = true; |
| 1158 for (size_t i = 0; i < tabs.size(); ++i) { | 1143 for (size_t i = 0; i < tabs.size(); ++i) { |
| 1159 TabContents* detached_contents = tabs[i]; | 1144 TabContents* detached_contents = tabs[i]; |
| 1160 int index = GetIndexOfTabContents(detached_contents); | 1145 int index = GetIndexOfTabContents(detached_contents); |
| 1161 // Make sure we still contain the tab. | 1146 // Make sure we still contain the tab. |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1326 void TabStripModel::ForgetOpenersAndGroupsReferencing( | 1311 void TabStripModel::ForgetOpenersAndGroupsReferencing( |
| 1327 const NavigationController* tab) { | 1312 const NavigationController* tab) { |
| 1328 for (TabContentsDataVector::const_iterator i = contents_data_.begin(); | 1313 for (TabContentsDataVector::const_iterator i = contents_data_.begin(); |
| 1329 i != contents_data_.end(); ++i) { | 1314 i != contents_data_.end(); ++i) { |
| 1330 if ((*i)->group == tab) | 1315 if ((*i)->group == tab) |
| 1331 (*i)->group = NULL; | 1316 (*i)->group = NULL; |
| 1332 if ((*i)->opener == tab) | 1317 if ((*i)->opener == tab) |
| 1333 (*i)->opener = NULL; | 1318 (*i)->opener = NULL; |
| 1334 } | 1319 } |
| 1335 } | 1320 } |
| OLD | NEW |