172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/tabs/base_tab_strip.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/view_ids.h"
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/views/tabs/dragged_tab_controller.h"
1021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/root_view.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/window/window.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/widget_win.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Animation delegate used when a dragged tab is released. When done sets the
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// dragging state to false.
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass ResetDraggingStateDelegate
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : public views::BoundsAnimator::OwnedAnimationDelegate {
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit ResetDraggingStateDelegate(BaseTab* tab) : tab_(tab) {
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
283f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  virtual void AnimationEnded(const ui::Animation* animation) {
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tab_->set_dragging(false);
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
323f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  virtual void AnimationCanceled(const ui::Animation* animation) {
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tab_->set_dragging(false);
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BaseTab* tab_;
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(ResetDraggingStateDelegate);
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// AnimationDelegate used when removing a tab. Does the necessary cleanup when
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// done.
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass BaseTabStrip::RemoveTabDelegate
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : public views::BoundsAnimator::OwnedAnimationDelegate {
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RemoveTabDelegate(BaseTabStrip* tab_strip, BaseTab* tab)
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : tabstrip_(tab_strip),
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tab_(tab) {
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
543f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  virtual void AnimationEnded(const ui::Animation* animation) {
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompleteRemove();
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
583f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  virtual void AnimationCanceled(const ui::Animation* animation) {
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We can be canceled for two interesting reasons:
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // . The tab we reference was dragged back into the tab strip. In this case
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //   we don't want to remove the tab (closing is false).
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // . The drag was completed before the animation completed
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //   (DestroyDraggedSourceTab). In this case we need to remove the tab
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //   (closing is true).
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (tab_->closing())
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CompleteRemove();
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void CompleteRemove() {
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!tab_->closing()) {
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The tab was added back yet we weren't canceled. This shouldn't happen.
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tabstrip_->RemoveAndDeleteTab(tab_);
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    HighlightCloseButton();
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // When the animation completes, we send the Container a message to simulate
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // a mouse moved event at the current mouse position. This tickles the Tab
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the mouse is currently over to show the "hot" state of the close button.
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void HighlightCloseButton() {
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (tabstrip_->IsDragSessionActive() ||
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !tabstrip_->ShouldHighlightCloseButtonAfterRemove()) {
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // This function is not required (and indeed may crash!) for removes
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // spawned by non-mouse closes and drag-detaches.
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    views::Widget* widget = tabstrip_->GetWidget();
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This can be null during shutdown. See http://crbug.com/42737.
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!widget)
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Force the close button (that slides under the mouse) to highlight by
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // saying the mouse just moved, but sending the same coordinates.
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DWORD pos = GetMessagePos();
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    POINT cursor_point = {GET_X_LPARAM(pos), GET_Y_LPARAM(pos)};
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MapWindowPoints(NULL, widget->GetNativeView(), &cursor_point, 1);
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    static_cast<views::WidgetWin*>(widget)->ResetLastMouseMoveFlag();
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Return to message loop - otherwise we may disrupt some operation that's
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // in progress.
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendMessage(widget->GetNativeView(), WM_MOUSEMOVE, 0,
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                MAKELPARAM(cursor_point.x, cursor_point.y));
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTIMPLEMENTED();
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BaseTabStrip* tabstrip_;
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BaseTab* tab_;
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(RemoveTabDelegate);
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBaseTabStrip::BaseTabStrip(TabStripController* controller, Type type)
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : controller_(controller),
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      type_(type),
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      attaching_dragged_tab_(false),
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ALLOW_THIS_IN_INITIALIZER_LIST(bounds_animator_(this)) {
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBaseTabStrip::~BaseTabStrip() {
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTabStrip::AddTabAt(int model_index, const TabRendererData& data) {
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BaseTab* tab = CreateTab();
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab->SetData(data);
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabData d = { tab, gfx::Rect() };
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_data_.insert(tab_data_.begin() + ModelIndexToTabIndex(model_index), d);
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddChildView(tab);
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Don't animate the first tab, it looks weird, and don't animate anything
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // if the containing window isn't visible yet.
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tab_count() > 1 && GetWindow() && GetWindow()->IsVisible())
140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    StartInsertTabAnimation(model_index);
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
142731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    DoLayout();
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTabStrip::MoveTab(int from_model_index, int to_model_index) {
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int from_tab_data_index = ModelIndexToTabIndex(from_model_index);
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BaseTab* tab = tab_data_[from_tab_data_index].tab;
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_data_.erase(tab_data_.begin() + from_tab_data_index);
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabData data = {tab, gfx::Rect()};
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int to_tab_data_index = ModelIndexToTabIndex(to_model_index);
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_data_.insert(tab_data_.begin() + to_tab_data_index, data);
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StartMoveTabAnimation();
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTabStrip::SetTabData(int model_index, const TabRendererData& data) {
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BaseTab* tab = GetBaseTabAtModelIndex(model_index);
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool mini_state_changed = tab->data().mini != data.mini;
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab->SetData(data);
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (mini_state_changed) {
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (GetWindow() && GetWindow()->IsVisible())
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      StartMiniTabAnimation();
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
166731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      DoLayout();
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBaseTab* BaseTabStrip::GetBaseTabAtModelIndex(int model_index) const {
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return base_tab_at_tab_index(ModelIndexToTabIndex(model_index));
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BaseTabStrip::GetModelIndexOfBaseTab(const BaseTab* tab) const {
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0, model_index = 0; i < tab_count(); ++i) {
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BaseTab* current_tab = base_tab_at_tab_index(i);
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!current_tab->closing()) {
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (current_tab == tab)
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return model_index;
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      model_index++;
181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else if (current_tab == tab) {
182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return -1;
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return -1;
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BaseTabStrip::GetModelCount() const {
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return controller_->GetCount();
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BaseTabStrip::IsValidModelIndex(int model_index) const {
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return controller_->IsValidIndex(model_index);
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BaseTabStrip::ModelIndexToTabIndex(int model_index) const {
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int current_model_index = 0;
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < tab_count(); ++i) {
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!base_tab_at_tab_index(i)->closing()) {
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (current_model_index == model_index)
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return i;
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      current_model_index++;
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return static_cast<int>(tab_data_.size());
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BaseTabStrip::IsDragSessionActive() const {
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return drag_controller_.get() != NULL;
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
21221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool BaseTabStrip::IsActiveDropTarget() const {
21321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  for (int i = 0; i < tab_count(); ++i) {
21421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    BaseTab* tab = base_tab_at_tab_index(i);
21521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (tab->dragging())
21621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return true;
21721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
21821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return false;
21921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
22021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool BaseTabStrip::IsTabStripEditable() const {
222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return !IsDragSessionActive() && !IsActiveDropTarget();
223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool BaseTabStrip::IsTabStripCloseable() const {
226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return !IsDragSessionActive();
227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTabStrip::UpdateLoadingAnimations() {
230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  controller_->UpdateLoadingAnimations();
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTabStrip::SelectTab(BaseTab* tab) {
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int model_index = GetModelIndexOfBaseTab(tab);
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (IsValidModelIndex(model_index))
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    controller_->SelectTab(model_index);
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTabStrip::ExtendSelectionTo(BaseTab* tab) {
240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int model_index = GetModelIndexOfBaseTab(tab);
241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsValidModelIndex(model_index))
242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    controller_->ExtendSelectionTo(model_index);
243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTabStrip::ToggleSelected(BaseTab* tab) {
246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int model_index = GetModelIndexOfBaseTab(tab);
247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsValidModelIndex(model_index))
248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    controller_->ToggleSelected(model_index);
249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTabStrip::AddSelectionFromAnchorTo(BaseTab* tab) {
252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int model_index = GetModelIndexOfBaseTab(tab);
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsValidModelIndex(model_index))
254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    controller_->AddSelectionFromAnchorTo(model_index);
255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTabStrip::CloseTab(BaseTab* tab) {
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Find the closest model index. We do this so that the user can rapdily close
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // tabs and have the close click close the next tab.
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int model_index = 0;
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < tab_count(); ++i) {
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BaseTab* current_tab = base_tab_at_tab_index(i);
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (current_tab == tab)
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!current_tab->closing())
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      model_index++;
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (IsValidModelIndex(model_index))
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    controller_->CloseTab(model_index);
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
273dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid BaseTabStrip::ShowContextMenuForTab(BaseTab* tab, const gfx::Point& p) {
274dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  controller_->ShowContextMenuForTab(tab, p);
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool BaseTabStrip::IsActiveTab(const BaseTab* tab) const {
278ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int model_index = GetModelIndexOfBaseTab(tab);
279ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return IsValidModelIndex(model_index) &&
280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      controller_->IsActiveTab(model_index);
281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BaseTabStrip::IsTabSelected(const BaseTab* tab) const {
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int model_index = GetModelIndexOfBaseTab(tab);
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return IsValidModelIndex(model_index) &&
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      controller_->IsTabSelected(model_index);
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BaseTabStrip::IsTabPinned(const BaseTab* tab) const {
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tab->closing())
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int model_index = GetModelIndexOfBaseTab(tab);
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return IsValidModelIndex(model_index) &&
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      controller_->IsTabPinned(model_index);
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BaseTabStrip::IsTabCloseable(const BaseTab* tab) const {
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int model_index = GetModelIndexOfBaseTab(tab);
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return !IsValidModelIndex(model_index) ||
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      controller_->IsTabCloseable(model_index);
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTabStrip::MaybeStartDrag(BaseTab* tab,
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  const views::MouseEvent& event) {
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Don't accidentally start any drag operations during animations if the
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // mouse is down... during an animation tabs are being resized automatically,
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // so the View system can misinterpret this easily if the mouse is down that
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the user is dragging.
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (IsAnimating() || tab->closing() ||
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      controller_->HasAvailableDragActions() == 0) {
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int model_index = GetModelIndexOfBaseTab(tab);
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!IsValidModelIndex(model_index)) {
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CHECK(false);
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  drag_controller_.reset(new DraggedTabController());
320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<BaseTab*> tabs;
321ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int size_to_selected = 0;
322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int x = tab->GetMirroredXInView(event.x());
323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int y = event.y();
324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Build the set of selected tabs to drag and calculate the offset from the
325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // first selected tab.
326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (int i = 0; i < tab_count(); ++i) {
327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    BaseTab* other_tab = base_tab_at_tab_index(i);
328ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (IsTabSelected(other_tab) && !other_tab->closing()) {
329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      tabs.push_back(other_tab);
330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (other_tab == tab) {
331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        size_to_selected = GetSizeNeededForTabs(tabs);
332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (type() == HORIZONTAL_TAB_STRIP)
333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          x = size_to_selected - tab->width() + x;
334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        else
335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          y = size_to_selected - tab->height() + y;
336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
337ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
338ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
339ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(!tabs.empty());
340ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(std::find(tabs.begin(), tabs.end(), tab) != tabs.end());
341ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  drag_controller_->Init(this, tab, tabs, gfx::Point(x, y),
342ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                         tab->GetMirroredXInView(event.x()));
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTabStrip::ContinueDrag(const views::MouseEvent& event) {
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We can get called even if |MaybeStartDrag| wasn't called in the event of
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // a TabStrip animation when the mouse button is down. In this case we should
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // _not_ continue the drag because it can lead to weird bugs.
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (drag_controller_.get()) {
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool started_drag = drag_controller_->started_drag();
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    drag_controller_->Drag();
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (drag_controller_->started_drag() && !started_drag) {
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The drag just started. Redirect mouse events to us to that the tab that
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // originated the drag can be safely deleted.
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GetRootView()->SetMouseHandler(this);
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BaseTabStrip::EndDrag(bool canceled) {
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!drag_controller_.get())
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool started_drag = drag_controller_->started_drag();
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  drag_controller_->EndDrag(canceled);
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return started_drag;
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBaseTab* BaseTabStrip::GetTabAt(BaseTab* tab,
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                const gfx::Point& tab_in_tab_coordinates) {
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Point local_point = tab_in_tab_coordinates;
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ConvertPointToView(tab, this, &local_point);
372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return GetTabAtLocal(local_point);
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTabStrip::Layout() {
376731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Only do a layout if our size changed.
377731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (last_layout_size_ == size())
378731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return;
379731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DoLayout();
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool BaseTabStrip::OnMouseDragged(const views::MouseEvent&  event) {
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (drag_controller_.get())
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    drag_controller_->Drag();
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
388ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTabStrip::OnMouseReleased(const views::MouseEvent& event) {
389ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EndDrag(false);
390ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
391ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
392ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTabStrip::OnMouseCaptureLost() {
393ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EndDrag(true);
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
39672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid BaseTabStrip::StartMoveTabAnimation() {
39772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  PrepareForAnimation();
39872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  GenerateIdealBounds();
39972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  AnimateToIdealBounds();
40072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
40172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTabStrip::StartRemoveTabAnimation(int model_index) {
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PrepareForAnimation();
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Mark the tab as closing.
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BaseTab* tab = GetBaseTabAtModelIndex(model_index);
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab->set_closing(true);
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Start an animation for the tabs.
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GenerateIdealBounds();
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AnimateToIdealBounds();
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Animate the tab being closed to 0x0.
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect tab_bounds = tab->bounds();
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (type() == HORIZONTAL_TAB_STRIP)
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tab_bounds.set_width(0);
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tab_bounds.set_height(0);
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bounds_animator_.AnimateViewTo(tab, tab_bounds);
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Register delegate to do cleanup when done, BoundsAnimator takes
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // ownership of RemoveTabDelegate.
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bounds_animator_.SetAnimationDelegate(tab, new RemoveTabDelegate(this, tab),
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        true);
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTabStrip::StartMiniTabAnimation() {
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PrepareForAnimation();
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GenerateIdealBounds();
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AnimateToIdealBounds();
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
434dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool BaseTabStrip::ShouldHighlightCloseButtonAfterRemove() {
435dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return true;
436dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
437dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTabStrip::RemoveAndDeleteTab(BaseTab* tab) {
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_data_index = TabIndexOfTab(tab);
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(tab_data_index != -1);
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Remove the Tab from the TabStrip's list...
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_data_.erase(tab_data_.begin() + tab_data_index);
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete tab;
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BaseTabStrip::TabIndexOfTab(BaseTab* tab) const {
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < tab_count(); ++i) {
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (base_tab_at_tab_index(i) == tab)
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return i;
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return -1;
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
45772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid BaseTabStrip::StopAnimating(bool layout) {
45872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!IsAnimating())
45972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return;
46072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
46172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  bounds_animator().Cancel();
46272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
46372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (layout)
46472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    DoLayout();
46572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
46672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTabStrip::DestroyDragController() {
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (IsDragSessionActive())
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    drag_controller_.reset(NULL);
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
472ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTabStrip::StartedDraggingTabs(const std::vector<BaseTab*>& tabs) {
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PrepareForAnimation();
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
475ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Reset dragging state of existing tabs.
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < tab_count(); ++i)
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base_tab_at_tab_index(i)->set_dragging(false);
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
479ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < tabs.size(); ++i) {
480ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    tabs[i]->set_dragging(true);
481ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bounds_animator_.StopAnimatingView(tabs[i]);
482ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
484ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Move the dragged tabs to their ideal bounds.
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GenerateIdealBounds();
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
487ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Sets the bounds of the dragged tabs.
488ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < tabs.size(); ++i) {
489ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int tab_data_index = TabIndexOfTab(tabs[i]);
490ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK(tab_data_index != -1);
491ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    tabs[i]->SetBoundsRect(ideal_bounds(tab_data_index));
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
493ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SchedulePaint();
494ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
496ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTabStrip::StoppedDraggingTabs(const std::vector<BaseTab*>& tabs) {
497ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool is_first_tab = true;
498ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < tabs.size(); ++i)
499ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    StoppedDraggingTab(tabs[i], &is_first_tab);
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BaseTabStrip::PrepareForAnimation() {
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!IsDragSessionActive() && !DraggedTabController::IsAttachedTo(this)) {
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (int i = 0; i < tab_count(); ++i)
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      base_tab_at_tab_index(i)->set_dragging(false);
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5093f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenui::AnimationDelegate* BaseTabStrip::CreateRemoveTabDelegate(BaseTab* tab) {
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new RemoveTabDelegate(this, tab);
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
512731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
513731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid BaseTabStrip::DoLayout() {
514731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  last_layout_size_ = size();
515731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
516731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  StopAnimating(false);
517731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
518731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  GenerateIdealBounds();
519731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
520731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (int i = 0; i < tab_count(); ++i)
52172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    tab_data_[i].tab->SetBoundsRect(tab_data_[i].ideal_bounds);
522731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
523731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  SchedulePaint();
524731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
525ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
526ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool BaseTabStrip::IsAnimating() const {
527ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return bounds_animator_.IsAnimating();
528ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
529ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
530ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenBaseTab* BaseTabStrip::GetTabAtLocal(const gfx::Point& local_point) {
531ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  views::View* view = GetEventHandlerForPoint(local_point);
532ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!view)
533ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return NULL;  // No tab contains the point.
534ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
535ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Walk up the view hierarchy until we find a tab, or the TabStrip.
536ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  while (view && view != this && view->GetID() != VIEW_ID_TAB)
537ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    view = view->parent();
538ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
539ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return view && view->GetID() == VIEW_ID_TAB ?
540ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      static_cast<BaseTab*>(view) : NULL;
541ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
542ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
543ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BaseTabStrip::StoppedDraggingTab(BaseTab* tab, bool* is_first_tab) {
544ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int tab_data_index = TabIndexOfTab(tab);
545ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (tab_data_index == -1) {
546ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // The tab was removed before the drag completed. Don't do anything.
547ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
548ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
549ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
550ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (*is_first_tab) {
551ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    *is_first_tab = false;
552ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    PrepareForAnimation();
553ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
554ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Animate the view back to its correct position.
555ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    GenerateIdealBounds();
556ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    AnimateToIdealBounds();
557ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
558ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bounds_animator_.AnimateViewTo(tab, ideal_bounds(TabIndexOfTab(tab)));
559ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Install a delegate to reset the dragging state when done. We have to leave
560ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // dragging true for the tab otherwise it'll draw beneath the new tab button.
561ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bounds_animator_.SetAnimationDelegate(
562ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      tab, new ResetDraggingStateDelegate(tab), true);
563ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
564