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.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/app/chrome_command_ids.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_shutdown.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/defaults.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/tab_helper.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_types.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_process_host.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/user_metrics.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents_view.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::UserMetricsAction;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if the specified transition is one of the types that cause the
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// opener relationships for the tab in which the transition occurred to be
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// forgotten. This is generally any navigation that isn't a link click (i.e.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// any navigation that can be considered to be the start of a new task distinct
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from what had previously occurred in that tab).
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShouldForgetOpenersForTransition(content::PageTransition transition) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return transition == content::PAGE_TRANSITION_TYPED ||
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      transition == content::PAGE_TRANSITION_AUTO_BOOKMARK ||
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      transition == content::PAGE_TRANSITION_GENERATED ||
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      transition == content::PAGE_TRANSITION_KEYWORD ||
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      transition == content::PAGE_TRANSITION_AUTO_TOPLEVEL;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// CloseTracker is used when closing a set of WebContents. It listens for
49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// deletions of the WebContents and removes from the internal set any time one
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// is deleted.
51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)class CloseTracker : public content::NotificationObserver {
52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) public:
53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  typedef std::vector<WebContents*> Contents;
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  explicit CloseTracker(const Contents& contents);
56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual ~CloseTracker();
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Returns true if there is another WebContents in the Tracker.
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool HasNext() const;
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Returns the next WebContents, or NULL if there are no more.
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  WebContents* Next();
63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private:
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // NotificationObserver:
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual void Observe(int type,
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                       const content::NotificationSource& source,
68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                       const content::NotificationDetails& details) OVERRIDE;
69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Contents contents_;
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  content::NotificationRegistrar registrar_;
73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(CloseTracker);
75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)CloseTracker::CloseTracker(const Contents& contents)
78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    : contents_(contents) {
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                 content::NotificationService::AllBrowserContextsAndSources());
81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)CloseTracker::~CloseTracker() {
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool CloseTracker::HasNext() const {
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return !contents_.empty();
88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)WebContents* CloseTracker::Next() {
91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (contents_.empty())
92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return NULL;
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  WebContents* web_contents = contents_[0];
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  contents_.erase(contents_.begin());
96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return web_contents;
97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void CloseTracker::Observe(int type,
100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                           const content::NotificationSource& source,
101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                           const content::NotificationDetails& details) {
102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  WebContents* web_contents = content::Source<WebContents>(source).ptr();
103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Contents::iterator i =
104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      std::find(contents_.begin(), contents_.end(), web_contents);
105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (i != contents_.end())
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    contents_.erase(i);
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TabStripModel, public:
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabStripModel::TabStripModel(TabStripModelDelegate* delegate, Profile* profile)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : delegate_(delegate),
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_(profile),
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      closing_all_(false) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(delegate_);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::NotificationService::AllBrowserContextsAndSources());
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  order_controller_.reset(new TabStripModelOrderController(this));
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TabStripModel::~TabStripModel() {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    TabStripModelDeleted());
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&contents_data_);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  order_controller_.reset();
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::AddObserver(TabStripModelObserver* observer) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.AddObserver(observer);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::RemoveObserver(TabStripModelObserver* observer) {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.RemoveObserver(observer);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStripModel::ContainsIndex(int index) const {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return index >= 0 && index < count();
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStripModel::AppendWebContents(WebContents* contents,
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      bool foreground) {
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  InsertWebContentsAt(count(), contents,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      foreground ? (ADD_INHERIT_GROUP | ADD_ACTIVE) :
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   ADD_NONE);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStripModel::InsertWebContentsAt(int index,
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        WebContents* contents,
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        int add_types) {
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delegate_->WillAddWebContents(contents);
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool active = add_types & ADD_ACTIVE;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force app tabs to be pinned.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extensions::TabHelper* extensions_tab_helper =
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extensions::TabHelper::FromWebContents(contents);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool pin = extensions_tab_helper->is_app() || add_types & ADD_PINNED;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  index = ConstrainInsertionIndex(index, pin);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In tab dragging situations, if the last tab in the window was detached
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // then the user aborted the drag, we will have the |closing_all_| member
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // set (see DetachWebContentsAt) which will mess with our mojo here. We need
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to clear this bit.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  closing_all_ = false;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Have to get the active contents before we monkey with |contents_|
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // otherwise we run into problems when we try to change the active contents
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // since the old contents and the new contents will be the same...
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebContents* active_contents = GetActiveWebContents();
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WebContentsData* data = new WebContentsData(contents);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data->pinned = pin;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((add_types & ADD_INHERIT_GROUP) && active_contents) {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (active) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Forget any existing relationships, we don't want to make things too
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // confusing by having multiple groups active at the same time.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ForgetAllOpeners();
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Anything opened by a link we deem to have an opener.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data->SetGroup(active_contents);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if ((add_types & ADD_INHERIT_OPENER) && active_contents) {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (active) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Forget any existing relationships, we don't want to make things too
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // confusing by having multiple groups active at the same time.
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ForgetAllOpeners();
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data->opener = active_contents;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contents_data_.insert(contents_data_.begin() + index, data);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  selection_model_.IncrementFrom(index);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    TabInsertedAt(contents, index, active));
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (active) {
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::ListSelectionModel new_model;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_model.Copy(selection_model_);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_model.SetSelectedIndex(index);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetSelection(new_model, NOTIFY_DEFAULT);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)WebContents* TabStripModel::ReplaceWebContentsAt(int index,
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                 WebContents* new_contents) {
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delegate_->WillAddWebContents(new_contents);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WebContents* old_contents = GetWebContentsAtImpl(index);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ForgetOpenersAndGroupsReferencing(old_contents);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  contents_data_[index]->contents = new_contents;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    TabReplacedAt(this, old_contents, new_contents, index));
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // When the active WebContents is replaced send out a selection notification
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // too. We do this as nearly all observers need to treat a replacement of the
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // selected contents as the selection changing.
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (active_index() == index) {
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    FOR_EACH_OBSERVER(
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        TabStripModelObserver,
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        observers_,
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ActiveTabChanged(old_contents,
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         new_contents,
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         active_index(),
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         TabStripModelObserver::CHANGE_REASON_REPLACED));
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return old_contents;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)WebContents* TabStripModel::DiscardWebContentsAt(int index) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Do not discard active tab.
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (active_index() == index)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WebContents* null_contents =
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      WebContents::Create(WebContents::CreateParams(profile()));
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WebContents* old_contents = GetWebContentsAtImpl(index);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Copy over the state from the navigation controller so we preserve the
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // back/forward history and continue to display the correct title/favicon.
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  null_contents->GetController().CopyStateFrom(old_contents->GetController());
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Replace the tab we're discarding with the null version.
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ReplaceWebContentsAt(index, null_contents);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mark the tab so it will reload when we click.
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contents_data_[index]->discarded = true;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Discard the old tab's renderer.
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(jamescook): This breaks script connections with other tabs.
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need to find a different approach that doesn't do that, perhaps based
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // on navigation to swappedout://.
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete old_contents;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return null_contents;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)WebContents* TabStripModel::DetachWebContentsAt(int index) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (contents_data_.empty())
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WebContents* removed_contents = GetWebContentsAtImpl(index);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool was_selected = IsTabSelected(index);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int next_selected_index = order_controller_->DetermineNewSelectedIndex(index);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete contents_data_[index];
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contents_data_.erase(contents_data_.begin() + index);
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ForgetOpenersAndGroupsReferencing(removed_contents);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (empty())
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    closing_all_ = true;
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    TabDetachedAt(removed_contents, index));
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (empty()) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    selection_model_.Clear();
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TabDetachedAt() might unregister observers, so send |TabStripEmpty()| in
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // a second pass.
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(TabStripModelObserver, observers_, TabStripEmpty());
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int old_active = active_index();
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    selection_model_.DecrementFrom(index);
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::ListSelectionModel old_model;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    old_model.Copy(selection_model_);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (index == old_active) {
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyIfTabDeactivated(removed_contents);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!selection_model_.empty()) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // The active tab was removed, but there is still something selected.
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Move the active and anchor to the first selected index.
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        selection_model_.set_active(selection_model_.selected_indices()[0]);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        selection_model_.set_anchor(selection_model_.active());
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // The active tab was removed and nothing is selected. Reset the
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // selection and send out notification.
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        selection_model_.SetSelectedIndex(next_selected_index);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotifyIfActiveTabChanged(removed_contents, NOTIFY_DEFAULT);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sending notification in case the detached tab was selected. Using
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NotifyIfActiveOrSelectionChanged() here would not guarantee that a
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // notification is sent even though the tab selection has changed because
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |old_model| is stored after calling DecrementFrom().
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (was_selected) {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        TabSelectionChanged(this, old_model));
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return removed_contents;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::ActivateTabAt(int index, bool user_gesture) {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::ListSelectionModel new_model;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_model.Copy(selection_model_);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_model.SetSelectedIndex(index);
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetSelection(new_model, user_gesture ? NOTIFY_USER_GESTURE : NOTIFY_DEFAULT);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::AddTabAtToSelection(int index) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::ListSelectionModel new_model;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_model.Copy(selection_model_);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_model.AddIndexToSelection(index);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetSelection(new_model, NOTIFY_DEFAULT);
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStripModel::MoveWebContentsAt(int index,
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      int to_position,
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      bool select_after_move) {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index == to_position)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int first_non_mini_tab = IndexOfFirstNonMiniTab();
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((index < first_non_mini_tab && to_position >= first_non_mini_tab) ||
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (to_position < first_non_mini_tab && index >= first_non_mini_tab)) {
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This would result in mini tabs mixed with non-mini tabs. We don't allow
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // that.
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MoveWebContentsAtImpl(index, to_position, select_after_move);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::MoveSelectedTabsTo(int index) {
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int total_mini_count = IndexOfFirstNonMiniTab();
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int selected_mini_count = 0;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int selected_count =
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<int>(selection_model_.selected_indices().size());
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < selected_count &&
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           IsMiniTab(selection_model_.selected_indices()[i]); ++i) {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    selected_mini_count++;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // To maintain that all mini-tabs occur before non-mini-tabs we move them
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // first.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (selected_mini_count > 0) {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MoveSelectedTabsToImpl(
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::min(total_mini_count - selected_mini_count, index), 0u,
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        selected_mini_count);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (index > total_mini_count - selected_mini_count) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We're being told to drag mini-tabs to an invalid location. Adjust the
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // index such that non-mini-tabs end up at a location as though we could
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // move the mini-tabs to index. See description in header for more
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // details.
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      index += selected_mini_count;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (selected_mini_count == selected_count)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Then move the non-pinned tabs.
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MoveSelectedTabsToImpl(std::max(index, total_mini_count),
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         selected_mini_count,
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         selected_count - selected_mini_count);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebContents* TabStripModel::GetActiveWebContents() const {
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetWebContentsAt(active_index());
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebContents* TabStripModel::GetWebContentsAt(int index) const {
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ContainsIndex(index))
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GetWebContentsAtImpl(index);
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TabStripModel::GetIndexOfWebContents(const WebContents* contents) const {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < contents_data_.size(); ++i) {
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (contents_data_[i]->contents == contents)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return i;
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kNoTab;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStripModel::UpdateWebContentsStateAt(int index,
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabStripModelObserver::TabChangeType change_type) {
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      TabChangedAt(GetWebContentsAtImpl(index), index, change_type));
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::CloseAllTabs() {
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set state so that observers can adjust their behavior to suit this
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // specific condition when CloseWebContentsAt causes a flurry of
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Close/Detach/Select notifications to be sent.
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  closing_all_ = true;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<int> closing_tabs;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = count() - 1; i >= 0; --i)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    closing_tabs.push_back(i);
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InternalCloseTabs(closing_tabs, CLOSE_CREATE_HISTORICAL_TAB);
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TabStripModel::CloseWebContentsAt(int index, uint32 close_types) {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<int> closing_tabs;
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  closing_tabs.push_back(index);
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return InternalCloseTabs(closing_tabs, close_types);
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStripModel::TabsAreLoading() const {
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (WebContentsDataVector::const_iterator iter = contents_data_.begin();
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != contents_data_.end(); ++iter) {
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((*iter)->contents->IsLoading())
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebContents* TabStripModel::GetOpenerOfWebContentsAt(int index) {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return contents_data_[index]->opener;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::SetOpenerOfWebContentsAt(int index,
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             WebContents* opener) {
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(opener);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contents_data_[index]->opener = opener;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TabStripModel::GetIndexOfNextWebContentsOpenedBy(const WebContents* opener,
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     int start_index,
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     bool use_group) const {
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(opener);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(start_index));
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check tabs after start_index first.
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = start_index + 1; i < count(); ++i) {
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (OpenerMatches(contents_data_[i], opener, use_group))
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return i;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Then check tabs before start_index, iterating backwards.
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = start_index - 1; i >= 0; --i) {
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (OpenerMatches(contents_data_[i], opener, use_group))
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return i;
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kNoTab;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TabStripModel::GetIndexOfLastWebContentsOpenedBy(const WebContents* opener,
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     int start_index) const {
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(opener);
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(start_index));
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = contents_data_.size() - 1; i > start_index; --i) {
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (contents_data_[i]->opener == opener)
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return i;
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kNoTab;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStripModel::TabNavigating(WebContents* contents,
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  content::PageTransition transition) {
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ShouldForgetOpenersForTransition(transition)) {
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Don't forget the openers if this tab is a New Tab page opened at the
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // end of the TabStrip (e.g. by pressing Ctrl+T). Give the user one
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // navigation of one of these transition types before resetting the
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // opener relationships (this allows for the use case of opening a new
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // tab to do a quick look-up of something while viewing a tab earlier in
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the strip). We can make this heuristic more permissive if need be.
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!IsNewTabAtEndOfTabStrip(contents)) {
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the user navigates the current tab to another page in any way
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // other than by clicking a link, we want to pro-actively forget all
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TabStrip opener relationships since we assume they're beginning a
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // different task by reusing the current tab.
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ForgetAllOpeners();
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // In this specific case we also want to reset the group relationship,
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // since it is now technically invalid.
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ForgetGroup(contents);
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::ForgetAllOpeners() {
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Forget all opener memories so we don't do anything weird with tab
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // re-selection ordering.
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (WebContentsDataVector::const_iterator iter = contents_data_.begin();
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != contents_data_.end(); ++iter)
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*iter)->ForgetOpener();
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStripModel::ForgetGroup(WebContents* contents) {
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int index = GetIndexOfWebContents(contents);
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contents_data_[index]->SetGroup(NULL);
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contents_data_[index]->ForgetOpener();
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TabStripModel::ShouldResetGroupOnSelect(WebContents* contents) const {
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int index = GetIndexOfWebContents(contents);
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return contents_data_[index]->reset_group_on_select;
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::SetTabBlocked(int index, bool blocked) {
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (contents_data_[index]->blocked == blocked)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contents_data_[index]->blocked = blocked;
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    TabBlockedStateChanged(contents_data_[index]->contents,
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           index));
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::SetTabPinned(int index, bool pinned) {
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (contents_data_[index]->pinned == pinned)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsAppTab(index)) {
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!pinned) {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // App tabs should always be pinned.
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Changing the pinned state of an app tab doesn't affect its mini-tab
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // status.
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contents_data_[index]->pinned = pinned;
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The tab is not an app tab, its position may have to change as the
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // mini-tab state is changing.
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int non_mini_tab_index = IndexOfFirstNonMiniTab();
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contents_data_[index]->pinned = pinned;
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (pinned && index != non_mini_tab_index) {
5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      MoveWebContentsAtImpl(index, non_mini_tab_index, false);
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      index = non_mini_tab_index;
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (!pinned && index + 1 != non_mini_tab_index) {
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      MoveWebContentsAtImpl(index, non_mini_tab_index - 1, false);
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      index = non_mini_tab_index - 1;
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TabMiniStateChanged(contents_data_[index]->contents,
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          index));
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // else: the tab was at the boundary and its position doesn't need to change.
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    TabPinnedStateChanged(contents_data_[index]->contents,
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          index));
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStripModel::IsTabPinned(int index) const {
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return contents_data_[index]->pinned;
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStripModel::IsMiniTab(int index) const {
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return IsTabPinned(index) || IsAppTab(index);
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStripModel::IsAppTab(int index) const {
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebContents* contents = GetWebContentsAt(index);
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return contents && extensions::TabHelper::FromWebContents(contents)->is_app();
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStripModel::IsTabBlocked(int index) const {
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return contents_data_[index]->blocked;
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStripModel::IsTabDiscarded(int index) const {
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return contents_data_[index]->discarded;
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TabStripModel::IndexOfFirstNonMiniTab() const {
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < contents_data_.size(); ++i) {
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!IsMiniTab(static_cast<int>(i)))
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return static_cast<int>(i);
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No mini-tabs.
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return count();
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TabStripModel::ConstrainInsertionIndex(int index, bool mini_tab) {
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mini_tab ? std::min(std::max(0, index), IndexOfFirstNonMiniTab()) :
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::min(count(), std::max(index, IndexOfFirstNonMiniTab()));
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::ExtendSelectionTo(int index) {
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::ListSelectionModel new_model;
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_model.Copy(selection_model_);
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_model.SetSelectionFromAnchorTo(index);
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetSelection(new_model, NOTIFY_DEFAULT);
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::ToggleSelectionAt(int index) {
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::ListSelectionModel new_model;
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_model.Copy(selection_model());
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (selection_model_.IsSelected(index)) {
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (selection_model_.size() == 1) {
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // One tab must be selected and this tab is currently selected so we can't
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // unselect it.
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_model.RemoveIndexFromSelection(index);
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_model.set_anchor(index);
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (new_model.active() == index ||
6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        new_model.active() == ui::ListSelectionModel::kUnselectedIndex)
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_model.set_active(new_model.selected_indices()[0]);
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_model.AddIndexToSelection(index);
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_model.set_anchor(index);
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_model.set_active(index);
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetSelection(new_model, NOTIFY_DEFAULT);
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::AddSelectionFromAnchorTo(int index) {
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::ListSelectionModel new_model;
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_model.Copy(selection_model_);
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_model.AddSelectionFromAnchorTo(index);
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetSelection(new_model, NOTIFY_DEFAULT);
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStripModel::IsTabSelected(int index) const {
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return selection_model_.IsSelected(index);
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::SetSelectionFromModel(
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ui::ListSelectionModel& source) {
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_NE(ui::ListSelectionModel::kUnselectedIndex, source.active());
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetSelection(source, NOTIFY_DEFAULT);
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStripModel::AddWebContents(WebContents* contents,
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   int index,
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   content::PageTransition transition,
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   int add_types) {
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the newly-opened tab is part of the same task as the parent tab, we want
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to inherit the parent's "group" attribute, so that if this tab is then
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // closed we'll jump back to the parent tab.
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool inherit_group = (add_types & ADD_INHERIT_GROUP) == ADD_INHERIT_GROUP;
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (transition == content::PAGE_TRANSITION_LINK &&
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (add_types & ADD_FORCE_INDEX) == 0) {
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We assume tabs opened via link clicks are part of the same task as their
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // parent.  Note that when |force_index| is true (e.g. when the user
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // drag-and-drops a link to the tab strip), callers aren't really handling
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // link clicks, they just want to score the navigation like a link click in
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the history backend, so we don't inherit the group in this case.
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    index = order_controller_->DetermineInsertionIndex(transition,
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                       add_types & ADD_ACTIVE);
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    inherit_group = true;
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // For all other types, respect what was passed to us, normalizing -1s and
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // values that are too large.
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (index < 0 || index > count())
6732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      index = count();
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (transition == content::PAGE_TRANSITION_TYPED && index == count()) {
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Also, any tab opened at the end of the TabStrip with a "TYPED"
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // transition inherit group as well. This covers the cases where the user
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // creates a New Tab (e.g. Ctrl+T, or clicks the New Tab button), or types
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // in the address bar and presses Alt+Enter. This allows for opening a new
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Tab to quickly look up something. When this Tab is closed, the old one
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // is re-selected, not the next-adjacent.
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    inherit_group = true;
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  InsertWebContentsAt(index, contents,
6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      add_types | (inherit_group ? ADD_INHERIT_GROUP : 0));
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reset the index, just in case insert ended up moving it on us.
6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  index = GetIndexOfWebContents(contents);
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (inherit_group && transition == content::PAGE_TRANSITION_TYPED)
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contents_data_[index]->reset_group_on_select = true;
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(sky): figure out why this is here and not in InsertWebContentsAt. When
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // here we seem to get failures in startup perf tests.
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ensure that the new WebContentsView begins at the same size as the
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // previous WebContentsView if it existed.  Otherwise, the initial WebKit
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // layout will be performed based on a width of 0 pixels, causing a
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // very long, narrow, inaccurate layout.  Because some scripts on pages (as
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // well as WebKit's anchor link location calculation) are run on the
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // initial layout and not recalculated later, we need to ensure the first
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // layout is performed with sane view dimensions even when we're opening a
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // new background tab.
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (WebContents* old_contents = GetActiveWebContents()) {
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((add_types & ADD_ACTIVE) == 0) {
7052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      contents->GetView()->SizeContents(
7062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          old_contents->GetView()->GetContainerSize());
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We need to hide the contents or else we get and execute paints for
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // background tabs. With enough background tabs they will steal the
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // backing store of the visible tab causing flashing. See bug 20831.
7102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      contents->WasHidden();
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::CloseSelectedTabs() {
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InternalCloseTabs(selection_model_.selected_indices(),
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    CLOSE_CREATE_HISTORICAL_TAB | CLOSE_USER_GESTURE);
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::SelectNextTab() {
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SelectRelativeTab(true);
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::SelectPreviousTab() {
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SelectRelativeTab(false);
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::SelectLastTab() {
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ActivateTabAt(count() - 1, true);
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::MoveTabNext() {
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO: this likely needs to be updated for multi-selection.
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int new_index = std::min(active_index() + 1, count() - 1);
7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MoveWebContentsAt(active_index(), new_index, true);
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::MoveTabPrevious() {
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO: this likely needs to be updated for multi-selection.
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int new_index = std::max(active_index() - 1, 0);
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MoveWebContentsAt(active_index(), new_index, true);
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Context menu functions.
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStripModel::IsContextMenuCommandEnabled(
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int context_index, ContextMenuCommand command_id) const {
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(command_id > CommandFirst && command_id < CommandLast);
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (command_id) {
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandNewTab:
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandCloseTab:
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandReload: {
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<int> indices = GetIndicesForCommand(context_index);
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t i = 0; i < indices.size(); ++i) {
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        WebContents* tab = GetWebContentsAt(indices[i]);
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (tab) {
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          CoreTabHelperDelegate* core_delegate =
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              CoreTabHelper::FromWebContents(tab)->delegate();
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!core_delegate || core_delegate->CanReloadContents(tab))
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return true;
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandCloseOtherTabs:
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandCloseTabsToRight:
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return !GetIndicesClosedByCommand(context_index, command_id).empty();
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandDuplicate: {
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<int> indices = GetIndicesForCommand(context_index);
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t i = 0; i < indices.size(); ++i) {
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (delegate_->CanDuplicateContentsAt(indices[i]))
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return true;
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandRestoreTab:
7812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return delegate_->GetRestoreTabType() !=
7822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          TabStripModelDelegate::RESTORE_NONE;
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandTogglePinned: {
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<int> indices = GetIndicesForCommand(context_index);
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t i = 0; i < indices.size(); ++i) {
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!IsAppTab(indices[i]))
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return true;
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandBookmarkAllTabs:
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return browser_defaults::bookmarks_enabled &&
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          delegate_->CanBookmarkAllTabs();
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandSelectByDomain:
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandSelectByOpener:
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::ExecuteContextMenuCommand(
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int context_index, ContextMenuCommand command_id) {
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(command_id > CommandFirst && command_id < CommandLast);
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (command_id) {
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandNewTab:
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::RecordAction(UserMetricsAction("TabContextMenu_NewTab"));
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_ENUMERATION("Tab.NewTab",
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                TabStripModel::NEW_TAB_CONTEXT_MENU,
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                TabStripModel::NEW_TAB_ENUM_COUNT);
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate()->AddBlankTabAt(context_index + 1, true);
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandReload: {
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::RecordAction(UserMetricsAction("TabContextMenu_Reload"));
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<int> indices = GetIndicesForCommand(context_index);
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t i = 0; i < indices.size(); ++i) {
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        WebContents* tab = GetWebContentsAt(indices[i]);
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (tab) {
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          CoreTabHelperDelegate* core_delegate =
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              CoreTabHelper::FromWebContents(tab)->delegate();
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!core_delegate || core_delegate->CanReloadContents(tab))
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            tab->GetController().Reload(true);
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandDuplicate: {
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::RecordAction(UserMetricsAction("TabContextMenu_Duplicate"));
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<int> indices = GetIndicesForCommand(context_index);
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Copy the WebContents off as the indices will change as tabs are
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // duplicated.
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<WebContents*> tabs;
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t i = 0; i < indices.size(); ++i)
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tabs.push_back(GetWebContentsAt(indices[i]));
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t i = 0; i < tabs.size(); ++i) {
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int index = GetIndexOfWebContents(tabs[i]);
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (index != -1 && delegate_->CanDuplicateContentsAt(index))
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          delegate_->DuplicateContentsAt(index);
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandCloseTab: {
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::RecordAction(UserMetricsAction("TabContextMenu_CloseTab"));
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      InternalCloseTabs(GetIndicesForCommand(context_index),
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        CLOSE_CREATE_HISTORICAL_TAB | CLOSE_USER_GESTURE);
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandCloseOtherTabs: {
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::RecordAction(
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          UserMetricsAction("TabContextMenu_CloseOtherTabs"));
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      InternalCloseTabs(GetIndicesClosedByCommand(context_index, command_id),
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        CLOSE_CREATE_HISTORICAL_TAB);
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandCloseTabsToRight: {
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::RecordAction(
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          UserMetricsAction("TabContextMenu_CloseTabsToRight"));
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      InternalCloseTabs(GetIndicesClosedByCommand(context_index, command_id),
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        CLOSE_CREATE_HISTORICAL_TAB);
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandRestoreTab: {
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::RecordAction(UserMetricsAction("TabContextMenu_RestoreTab"));
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_->RestoreTab();
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandTogglePinned: {
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::RecordAction(
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          UserMetricsAction("TabContextMenu_TogglePinned"));
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<int> indices = GetIndicesForCommand(context_index);
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool pin = WillContextMenuPin(context_index);
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (pin) {
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (size_t i = 0; i < indices.size(); ++i) {
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!IsAppTab(indices[i]))
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            SetTabPinned(indices[i], true);
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Unpin from the back so that the order is maintained (unpinning can
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // trigger moving a tab).
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (size_t i = indices.size(); i > 0; --i) {
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!IsAppTab(indices[i - 1]))
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            SetTabPinned(indices[i - 1], false);
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandBookmarkAllTabs: {
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::RecordAction(
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          UserMetricsAction("TabContextMenu_BookmarkAllTabs"));
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_->BookmarkAllTabs();
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandSelectByDomain:
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandSelectByOpener: {
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<int> indices;
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (command_id == CommandSelectByDomain)
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetIndicesWithSameDomain(context_index, &indices);
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetIndicesWithSameOpener(context_index, &indices);
9152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ui::ListSelectionModel selection_model;
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      selection_model.SetSelectedIndex(context_index);
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t i = 0; i < indices.size(); ++i)
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        selection_model.AddIndexToSelection(indices[i]);
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SetSelectionFromModel(selection_model);
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<int> TabStripModel::GetIndicesClosedByCommand(
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index,
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ContextMenuCommand id) const {
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ContainsIndex(index));
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(id == CommandCloseTabsToRight || id == CommandCloseOtherTabs);
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_selected = IsTabSelected(index);
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int start;
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (id == CommandCloseTabsToRight) {
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (is_selected) {
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      start = selection_model_.selected_indices()[
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          selection_model_.selected_indices().size() - 1] + 1;
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      start = index + 1;
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    start = 0;
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: callers expect the vector to be sorted in descending order.
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<int> indices;
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = count() - 1; i >= start; --i) {
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i != index && !IsMiniTab(i) && (!is_selected || !IsTabSelected(i)))
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      indices.push_back(i);
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return indices;
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStripModel::WillContextMenuPin(int index) {
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<int> indices = GetIndicesForCommand(index);
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If all tabs are pinned, then we unpin, otherwise we pin.
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool all_pinned = true;
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < indices.size() && all_pinned; ++i) {
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!IsAppTab(index))  // We never change app tabs.
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      all_pinned = IsTabPinned(indices[i]);
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !all_pinned;
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TabStripModel, content::NotificationObserver implementation:
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::Observe(int type,
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            const content::NotificationSource& source,
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            const content::NotificationDetails& details) {
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Sometimes, on qemu, it seems like a WebContents object can be destroyed
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // while we still have a reference to it. We need to break this reference
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // here so we don't crash later.
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int index = GetIndexOfWebContents(
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          content::Source<WebContents>(source).ptr());
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (index != TabStripModel::kNoTab) {
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Note that we only detach the contents here, not close it - it's
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // already been closed. We just want to undo our bookkeeping.
9812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        DetachWebContentsAt(index);
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStripModel::ContextMenuCommandToBrowserCommand(int cmd_id,
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       int* browser_cmd) {
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (cmd_id) {
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandNewTab:
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *browser_cmd = IDC_NEW_TAB;
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandReload:
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *browser_cmd = IDC_RELOAD;
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandDuplicate:
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *browser_cmd = IDC_DUPLICATE_TAB;
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandCloseTab:
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *browser_cmd = IDC_CLOSE_TAB;
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandRestoreTab:
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *browser_cmd = IDC_RESTORE_TAB;
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CommandBookmarkAllTabs:
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *browser_cmd = IDC_BOOKMARK_ALL_TABS;
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *browser_cmd = 0;
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TabStripModel, private:
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1024868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)std::vector<WebContents*> TabStripModel::GetWebContentsFromIndices(
1025868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const std::vector<int>& indices) const {
1026868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::vector<WebContents*> contents;
1027868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (size_t i = 0; i < indices.size(); ++i)
1028868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    contents.push_back(GetWebContentsAtImpl(indices[i]));
1029868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return contents;
1030868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
1031868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::GetIndicesWithSameDomain(int index,
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             std::vector<int>* indices) {
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string domain = GetWebContentsAt(index)->GetURL().host();
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (domain.empty())
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < count(); ++i) {
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i == index)
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (GetWebContentsAt(i)->GetURL().host() == domain)
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      indices->push_back(i);
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::GetIndicesWithSameOpener(int index,
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             std::vector<int>* indices) {
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebContents* opener = contents_data_[index]->group;
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!opener) {
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If there is no group, find all tabs with the selected tab as the opener.
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    opener = GetWebContentsAt(index);
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!opener)
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < count(); ++i) {
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i == index)
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (contents_data_[i]->group == opener ||
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetWebContentsAtImpl(i) == opener) {
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      indices->push_back(i);
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<int> TabStripModel::GetIndicesForCommand(int index) const {
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsTabSelected(index)) {
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<int> indices;
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    indices.push_back(index);
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return indices;
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return selection_model_.selected_indices();
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TabStripModel::IsNewTabAtEndOfTabStrip(WebContents* contents) const {
10742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const GURL& url = contents->GetURL();
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return url.SchemeIs(chrome::kChromeUIScheme) &&
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         url.host() == chrome::kChromeUINewTabHost &&
10772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         contents == GetWebContentsAtImpl(count() - 1) &&
10782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         contents->GetController().GetEntryCount() == 1;
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStripModel::InternalCloseTabs(const std::vector<int>& indices,
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      uint32 close_types) {
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (indices.empty())
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1086868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  CloseTracker close_tracker(GetWebContentsFromIndices(indices));
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only try the fast shutdown path if the whole browser process is *not*
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // shutting down. Fast shutdown during browser termination is handled in
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // BrowserShutdown.
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID) {
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Construct a map of processes to the number of associated tabs that are
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // closing.
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::map<content::RenderProcessHost*, size_t> processes;
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < indices.size(); ++i) {
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WebContents* closing_contents = GetWebContentsAtImpl(indices[i]);
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::RenderProcessHost* process =
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          closing_contents->GetRenderProcessHost();
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++processes[process];
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Try to fast shutdown the tabs that can close.
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (std::map<content::RenderProcessHost*, size_t>::iterator iter =
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         processes.begin(); iter != processes.end(); ++iter) {
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iter->first->FastShutdownForPageCount(iter->second);
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We now return to our regularly scheduled shutdown procedure.
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool retval = true;
1111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  while (close_tracker.HasNext()) {
1112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    WebContents* closing_contents = close_tracker.Next();
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index = GetIndexOfWebContents(closing_contents);
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make sure we still contain the tab.
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (index == kNoTab)
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    CoreTabHelper* core_tab_helper =
11197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        CoreTabHelper::FromWebContents(closing_contents);
11207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    core_tab_helper->OnCloseStarted();
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the explicitly closed state. If the unload handlers cancel the
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // close the state is reset in Browser. We don't update the explicitly
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // closed state if already marked as explicitly closed as unload handlers
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // call back to this if the close is allowed.
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!closing_contents->GetClosedByUserGesture()) {
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      closing_contents->SetClosedByUserGesture(
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          close_types & CLOSE_USER_GESTURE);
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (delegate_->RunUnloadListenerBeforeClosing(closing_contents)) {
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      retval = false;
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InternalCloseTab(closing_contents, index,
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     (close_types & CLOSE_CREATE_HISTORICAL_TAB) != 0);
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return retval;
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::InternalCloseTab(WebContents* contents,
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     int index,
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     bool create_historical_tabs) {
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    TabClosingAt(this, contents, index));
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ask the delegate to save an entry for this tab in the historical tab
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // database if applicable.
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (create_historical_tabs)
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->CreateHistoricalTab(contents);
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Deleting the WebContents will call back to us via
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NotificationObserver and detach it.
11562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete contents;
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebContents* TabStripModel::GetWebContentsAtImpl(int index) const {
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(ContainsIndex(index)) <<
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Failed to find: " << index << " in: " << count() << " entries.";
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return contents_data_[index]->contents;
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStripModel::NotifyIfTabDeactivated(WebContents* contents) {
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (contents) {
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TabDeactivated(contents));
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStripModel::NotifyIfActiveTabChanged(WebContents* old_contents,
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             NotifyTypes notify_types) {
11742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WebContents* new_contents = GetWebContentsAtImpl(active_index());
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (old_contents != new_contents) {
1176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int reason = notify_types == NOTIFY_USER_GESTURE
1177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 ? TabStripModelObserver::CHANGE_REASON_USER_GESTURE
1178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 : TabStripModelObserver::CHANGE_REASON_NONE;
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
1180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ActiveTabChanged(old_contents,
1181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         new_contents,
1182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         active_index(),
1183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         reason));
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Activating a discarded tab reloads it, so it is no longer discarded.
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contents_data_[active_index()]->discarded = false;
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::NotifyIfActiveOrSelectionChanged(
11902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WebContents* old_contents,
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NotifyTypes notify_types,
11922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ui::ListSelectionModel& old_model) {
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyIfActiveTabChanged(old_contents, notify_types);
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!selection_model().Equals(old_model)) {
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      TabSelectionChanged(this, old_model));
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::SetSelection(
12022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ui::ListSelectionModel& new_model,
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NotifyTypes notify_types) {
12042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WebContents* old_contents = GetActiveWebContents();
12052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::ListSelectionModel old_model;
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  old_model.Copy(selection_model_);
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (new_model.active() != selection_model_.active())
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NotifyIfTabDeactivated(old_contents);
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  selection_model_.Copy(new_model);
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyIfActiveOrSelectionChanged(old_contents, notify_types, old_model);
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::SelectRelativeTab(bool next) {
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This may happen during automated testing or if a user somehow buffers
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // many key accelerators.
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (contents_data_.empty())
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index = active_index();
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int delta = next ? 1 : -1;
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  index = (index + count() + delta) % count();
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ActivateTabAt(index, true);
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TabStripModel::MoveWebContentsAtImpl(int index,
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          int to_position,
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          bool select_after_move) {
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebContentsData* moved_data = contents_data_[index];
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contents_data_.erase(contents_data_.begin() + index);
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contents_data_.insert(contents_data_.begin() + to_position, moved_data);
12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  selection_model_.Move(index, to_position);
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!selection_model_.IsSelected(select_after_move) && select_after_move) {
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(sky): why doesn't this code notify observers?
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    selection_model_.SetSelectedIndex(to_position);
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
12392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    TabMoved(moved_data->contents, index, to_position));
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::MoveSelectedTabsToImpl(int index,
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           size_t start,
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           size_t length) {
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(start < selection_model_.selected_indices().size() &&
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         start + length <= selection_model_.selected_indices().size());
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t end = start + length;
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int count_before_index = 0;
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = start; i < end &&
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       selection_model_.selected_indices()[i] < index + count_before_index;
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++i) {
12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    count_before_index++;
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First move those before index. Any tabs before index end up moving in the
12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // selection model so we use start each time through.
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int target_index = index + count_before_index;
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t tab_index = start;
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (tab_index < end &&
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         selection_model_.selected_indices()[start] < index) {
12612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    MoveWebContentsAt(selection_model_.selected_indices()[start],
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      target_index - 1, false);
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tab_index++;
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Then move those after the index. These don't result in reordering the
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // selection.
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (tab_index < end) {
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (selection_model_.selected_indices()[tab_index] != target_index) {
12702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      MoveWebContentsAt(selection_model_.selected_indices()[tab_index],
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        target_index, false);
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tab_index++;
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    target_index++;
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TabStripModel::OpenerMatches(const WebContentsData* data,
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const WebContents* opener,
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  bool use_group) {
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return data->opener == opener || (use_group && data->group == opener);
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TabStripModel::ForgetOpenersAndGroupsReferencing(
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WebContents* tab) {
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (WebContentsDataVector::const_iterator i = contents_data_.begin();
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != contents_data_.end(); ++i) {
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((*i)->group == tab)
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (*i)->group = NULL;
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((*i)->opener == tab)
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (*i)->opener = NULL;
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1295