15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TabStripModelOrderController, public:
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabStripModelOrderController::TabStripModelOrderController(
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabStripModel* tabstrip)
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : tabstrip_(tabstrip) {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tabstrip_->AddObserver(this);
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabStripModelOrderController::~TabStripModelOrderController() {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tabstrip_->RemoveObserver(this);
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TabStripModelOrderController::DetermineInsertionIndex(
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::PageTransition transition,
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool foreground) {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int tab_count = tabstrip_->count();
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!tab_count)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: TabStripModel enforces that all non-mini-tabs occur after mini-tabs,
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // so we don't have to check here too.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (transition == content::PAGE_TRANSITION_LINK &&
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tabstrip_->active_index() != -1) {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (foreground) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the page was opened in the foreground by a link click in another
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // tab, insert it adjacent to the tab that opened that link.
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return tabstrip_->active_index() + 1;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::WebContents* opener = tabstrip_->GetActiveWebContents();
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get the index of the next item opened by this tab, and insert after
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // it...
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int index = tabstrip_->GetIndexOfLastWebContentsOpenedBy(
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        opener, tabstrip_->active_index());
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (index != TabStripModel::kNoTab)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return index + 1;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Otherwise insert adjacent to opener...
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return tabstrip_->active_index() + 1;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In other cases, such as Ctrl+T, open at the end of the strip.
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return tabstrip_->count();
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TabStripModelOrderController::DetermineNewSelectedIndex(
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int removing_index) const {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int tab_count = tabstrip_->count();
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(removing_index >= 0 && removing_index < tab_count);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::WebContents* parent_opener =
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tabstrip_->GetOpenerOfWebContentsAt(removing_index);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First see if the index being removed has any "child" tabs. If it does, we
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want to select the first in that child group, not the next tab in the same
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // group of the removed tab.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::WebContents* removed_contents =
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tabstrip_->GetWebContentsAt(removing_index);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The parent opener should never be the same as the controller being removed.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(parent_opener != removed_contents);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index = tabstrip_->GetIndexOfNextWebContentsOpenedBy(removed_contents,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                           removing_index,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                           false);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index != TabStripModel::kNoTab)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GetValidIndex(index, removing_index);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parent_opener) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the tab was in a group, shift selection to the next tab in the group.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index = tabstrip_->GetIndexOfNextWebContentsOpenedBy(parent_opener,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                             removing_index,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                             false);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (index != TabStripModel::kNoTab)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GetValidIndex(index, removing_index);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we can't find a subsequent group member, just fall back to the
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // parent_opener itself. Note that we use "group" here since opener is
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // reset by select operations..
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = tabstrip_->GetIndexOfWebContents(parent_opener);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (index != TabStripModel::kNoTab)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GetValidIndex(index, removing_index);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No opener set, fall through to the default handler...
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int selected_index = tabstrip_->active_index();
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (selected_index >= (tab_count - 1))
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return selected_index - 1;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return selected_index;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModelOrderController::ActiveTabChanged(
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    content::WebContents* old_contents,
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    content::WebContents* new_contents,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index,
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int reason) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::WebContents* old_opener = NULL;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (old_contents) {
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int index = tabstrip_->GetIndexOfWebContents(old_contents);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (index != TabStripModel::kNoTab) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      old_opener = tabstrip_->GetOpenerOfWebContentsAt(index);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Forget any group/opener relationships that need to be reset whenever
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // selection changes (see comment in TabStripModel::AddWebContentsAt).
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (tabstrip_->ShouldResetGroupOnSelect(old_contents))
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tabstrip_->ForgetGroup(old_contents);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::WebContents* new_opener = tabstrip_->GetOpenerOfWebContentsAt(index);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if ((reason & CHANGE_REASON_USER_GESTURE) && new_opener != old_opener &&
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ((old_contents == NULL && new_opener == NULL) ||
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          new_opener != old_contents) &&
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ((new_contents == NULL && old_opener == NULL) ||
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          old_opener != new_contents)) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tabstrip_->ForgetAllOpeners();
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TabStripModelOrderController, private:
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TabStripModelOrderController::GetValidIndex(
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index, int removing_index) const {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (removing_index < index)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = std::max(0, index - 1);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return index;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
132