Home | History | Annotate | Download | only in tabs
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/tabs/tab_strip_model_order_controller.h"
      6 
      7 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
      8 
      9 ///////////////////////////////////////////////////////////////////////////////
     10 // TabStripModelOrderController, public:
     11 
     12 TabStripModelOrderController::TabStripModelOrderController(
     13     TabStripModel* tabstrip)
     14     : tabstrip_(tabstrip),
     15       insertion_policy_(TabStripModel::INSERT_AFTER) {
     16   tabstrip_->AddObserver(this);
     17 }
     18 
     19 TabStripModelOrderController::~TabStripModelOrderController() {
     20   tabstrip_->RemoveObserver(this);
     21 }
     22 
     23 int TabStripModelOrderController::DetermineInsertionIndex(
     24     TabContentsWrapper* new_contents,
     25     PageTransition::Type transition,
     26     bool foreground) {
     27   int tab_count = tabstrip_->count();
     28   if (!tab_count)
     29     return 0;
     30 
     31   // NOTE: TabStripModel enforces that all non-mini-tabs occur after mini-tabs,
     32   // so we don't have to check here too.
     33   if (transition == PageTransition::LINK && tabstrip_->active_index() != -1) {
     34     int delta = (insertion_policy_ == TabStripModel::INSERT_AFTER) ? 1 : 0;
     35     if (foreground) {
     36       // If the page was opened in the foreground by a link click in another
     37       // tab, insert it adjacent to the tab that opened that link.
     38       return tabstrip_->active_index() + delta;
     39     }
     40     NavigationController* opener =
     41         &tabstrip_->GetSelectedTabContents()->controller();
     42     // Get the index of the next item opened by this tab, and insert after
     43     // it...
     44     int index;
     45     if (insertion_policy_ == TabStripModel::INSERT_AFTER) {
     46       index = tabstrip_->GetIndexOfLastTabContentsOpenedBy(
     47           opener, tabstrip_->active_index());
     48     } else {
     49       index = tabstrip_->GetIndexOfFirstTabContentsOpenedBy(
     50           opener, tabstrip_->active_index());
     51     }
     52     if (index != TabStripModel::kNoTab)
     53       return index + delta;
     54     // Otherwise insert adjacent to opener...
     55     return tabstrip_->active_index() + delta;
     56   }
     57   // In other cases, such as Ctrl+T, open at the end of the strip.
     58   return DetermineInsertionIndexForAppending();
     59 }
     60 
     61 int TabStripModelOrderController::DetermineInsertionIndexForAppending() {
     62   return (insertion_policy_ == TabStripModel::INSERT_AFTER) ?
     63       tabstrip_->count() : 0;
     64 }
     65 
     66 int TabStripModelOrderController::DetermineNewSelectedIndex(
     67     int removing_index) const {
     68   int tab_count = tabstrip_->count();
     69   DCHECK(removing_index >= 0 && removing_index < tab_count);
     70   NavigationController* parent_opener =
     71       tabstrip_->GetOpenerOfTabContentsAt(removing_index);
     72   // First see if the index being removed has any "child" tabs. If it does, we
     73   // want to select the first in that child group, not the next tab in the same
     74   // group of the removed tab.
     75   NavigationController* removed_controller =
     76       &tabstrip_->GetTabContentsAt(removing_index)->controller();
     77   // The parent opener should never be the same as the controller being removed.
     78   DCHECK(parent_opener != removed_controller);
     79   int index = tabstrip_->GetIndexOfNextTabContentsOpenedBy(removed_controller,
     80                                                            removing_index,
     81                                                            false);
     82   if (index != TabStripModel::kNoTab)
     83     return GetValidIndex(index, removing_index);
     84 
     85   if (parent_opener) {
     86     // If the tab was in a group, shift selection to the next tab in the group.
     87     int index = tabstrip_->GetIndexOfNextTabContentsOpenedBy(parent_opener,
     88                                                              removing_index,
     89                                                              false);
     90     if (index != TabStripModel::kNoTab)
     91       return GetValidIndex(index, removing_index);
     92 
     93     // If we can't find a subsequent group member, just fall back to the
     94     // parent_opener itself. Note that we use "group" here since opener is
     95     // reset by select operations..
     96     index = tabstrip_->GetIndexOfController(parent_opener);
     97     if (index != TabStripModel::kNoTab)
     98       return GetValidIndex(index, removing_index);
     99   }
    100 
    101   // No opener set, fall through to the default handler...
    102   int selected_index = tabstrip_->active_index();
    103   if (selected_index >= (tab_count - 1))
    104     return selected_index - 1;
    105 
    106   return selected_index;
    107 }
    108 
    109 void TabStripModelOrderController::TabSelectedAt(
    110     TabContentsWrapper* old_contents,
    111     TabContentsWrapper* new_contents,
    112     int index,
    113     bool user_gesture) {
    114   if (old_contents == new_contents)
    115     return;
    116 
    117   NavigationController* old_opener = NULL;
    118   if (old_contents) {
    119     int index = tabstrip_->GetIndexOfTabContents(old_contents);
    120     if (index != TabStripModel::kNoTab) {
    121       old_opener = tabstrip_->GetOpenerOfTabContentsAt(index);
    122 
    123       // Forget any group/opener relationships that need to be reset whenever
    124       // selection changes (see comment in TabStripModel::AddTabContentsAt).
    125       if (tabstrip_->ShouldResetGroupOnSelect(old_contents))
    126         tabstrip_->ForgetGroup(old_contents);
    127     }
    128   }
    129   NavigationController* new_opener =
    130       tabstrip_->GetOpenerOfTabContentsAt(index);
    131   if (user_gesture && new_opener != old_opener &&
    132       new_opener != &old_contents->controller() &&
    133       old_opener != &new_contents->controller()) {
    134     tabstrip_->ForgetAllOpeners();
    135   }
    136 }
    137 
    138 ///////////////////////////////////////////////////////////////////////////////
    139 // TabStripModelOrderController, private:
    140 
    141 int TabStripModelOrderController::GetValidIndex(
    142     int index, int removing_index) const {
    143   if (removing_index < index)
    144     index = std::max(0, index - 1);
    145   return index;
    146 }
    147