1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_UI_VIEWS_TABS_BASE_TAB_STRIP_H_
6#define CHROME_BROWSER_UI_VIEWS_TABS_BASE_TAB_STRIP_H_
7#pragma once
8
9#include <vector>
10
11#include "base/memory/scoped_ptr.h"
12#include "chrome/browser/ui/views/tabs/abstract_tab_strip_view.h"
13#include "chrome/browser/ui/views/tabs/base_tab.h"
14#include "chrome/browser/ui/views/tabs/tab_controller.h"
15#include "views/animation/bounds_animator.h"
16#include "views/view.h"
17
18class BaseTab;
19class DraggedTabController;
20class TabStripController;
21
22// Base class for the view tab strip implementations.
23class BaseTabStrip : public AbstractTabStripView,
24                     public TabController {
25 public:
26  enum Type {
27    HORIZONTAL_TAB_STRIP,
28    VERTICAL_TAB_STRIP
29  };
30
31  BaseTabStrip(TabStripController* controller, Type type);
32  virtual ~BaseTabStrip();
33
34  Type type() const { return type_; }
35
36  // Starts highlighting the tab at the specified index.
37  virtual void StartHighlight(int model_index) = 0;
38
39  // Stops all tab higlighting.
40  virtual void StopAllHighlighting() = 0;
41
42  // Retrieves the ideal bounds for the Tab at the specified index.
43  const gfx::Rect& ideal_bounds(int tab_data_index) {
44    return tab_data_[tab_data_index].ideal_bounds;
45  }
46
47  // Creates and returns a tab that can be used for dragging. Ownership passes
48  // to the caller.
49  virtual BaseTab* CreateTabForDragging() = 0;
50
51  // Adds a tab at the specified index.
52  void AddTabAt(int model_index, const TabRendererData& data);
53
54  // Invoked from the controller when the close initiates from the TabController
55  // (the user clicked the tab close button or middle clicked the tab). This is
56  // invoked from Close. Because of unload handlers Close is not always
57  // immediately followed by RemoveTabAt.
58  virtual void PrepareForCloseAt(int model_index) {}
59
60  // Removes a tab at the specified index.
61  virtual void RemoveTabAt(int model_index) = 0;
62
63  // Selects a tab at the specified index. |old_model_index| is the selected
64  // index prior to the selection change.
65  virtual void SelectTabAt(int old_model_index, int new_model_index) = 0;
66
67  // Moves a tab.
68  virtual void MoveTab(int from_model_index, int to_model_index);
69
70  // Invoked when the title of a tab changes and the tab isn't loading.
71  virtual void TabTitleChangedNotLoading(int model_index) = 0;
72
73  // Sets the tab data at the specified model index.
74  virtual void SetTabData(int model_index, const TabRendererData& data);
75
76  // Returns the tab at the specified model index.
77  virtual BaseTab* GetBaseTabAtModelIndex(int model_index) const;
78
79  // Returns the tab at the specified tab index.
80  BaseTab* base_tab_at_tab_index(int tab_index) const {
81    return tab_data_[tab_index].tab;
82  }
83
84  // Returns the index of the specified tab in the model coordiate system, or
85  // -1 if tab is closing or not valid.
86  int GetModelIndexOfBaseTab(const BaseTab* tab) const;
87
88  // Gets the number of Tabs in the tab strip.
89  // WARNING: this is the number of tabs displayed by the tabstrip, which if
90  // an animation is ongoing is not necessarily the same as the number of tabs
91  // in the model.
92  int tab_count() const { return static_cast<int>(tab_data_.size()); }
93
94  // Cover method for TabStripController::GetCount.
95  int GetModelCount() const;
96
97  // Cover method for TabStripController::IsValidIndex.
98  bool IsValidModelIndex(int model_index) const;
99
100  // Returns the index into |tab_data_| corresponding to the index from the
101  // TabStripModel, or |tab_data_.size()| if there is no tab representing
102  // |model_index|.
103  int ModelIndexToTabIndex(int model_index) const;
104
105  TabStripController* controller() const { return controller_.get(); }
106
107  // Returns true if a drag session is currently active.
108  bool IsDragSessionActive() const;
109
110  // Returns true if a tab is being dragged into this tab strip.
111  bool IsActiveDropTarget() const;
112
113  // AbstractTabStripView implementation
114  virtual bool IsTabStripEditable() const OVERRIDE;
115  virtual bool IsTabStripCloseable() const OVERRIDE;
116  virtual void UpdateLoadingAnimations() OVERRIDE;
117
118  // TabController overrides:
119  virtual void SelectTab(BaseTab* tab) OVERRIDE;
120  virtual void ExtendSelectionTo(BaseTab* tab) OVERRIDE;
121  virtual void ToggleSelected(BaseTab* tab) OVERRIDE;
122  virtual void AddSelectionFromAnchorTo(BaseTab* tab) OVERRIDE;
123  virtual void CloseTab(BaseTab* tab) OVERRIDE;
124  virtual void ShowContextMenuForTab(BaseTab* tab,
125                                     const gfx::Point& p) OVERRIDE;
126  virtual bool IsActiveTab(const BaseTab* tab) const OVERRIDE;
127  virtual bool IsTabSelected(const BaseTab* tab) const OVERRIDE;
128  virtual bool IsTabPinned(const BaseTab* tab) const OVERRIDE;
129  virtual bool IsTabCloseable(const BaseTab* tab) const OVERRIDE;
130  virtual void MaybeStartDrag(BaseTab* tab,
131                              const views::MouseEvent& event) OVERRIDE;
132  virtual void ContinueDrag(const views::MouseEvent& event) OVERRIDE;
133  virtual bool EndDrag(bool canceled) OVERRIDE;
134  virtual BaseTab* GetTabAt(BaseTab* tab,
135                            const gfx::Point& tab_in_tab_coordinates) OVERRIDE;
136
137  // View overrides:
138  virtual void Layout() OVERRIDE;
139
140 protected:
141  // The Tabs we contain, and their last generated "good" bounds.
142  struct TabData {
143    BaseTab* tab;
144    gfx::Rect ideal_bounds;
145  };
146
147  // View overrides.
148  virtual bool OnMouseDragged(const views::MouseEvent& event) OVERRIDE;
149  virtual void OnMouseReleased(const views::MouseEvent& event) OVERRIDE;
150  virtual void OnMouseCaptureLost() OVERRIDE;
151
152  // Creates and returns a new tab. The caller owners the returned tab.
153  virtual BaseTab* CreateTab() = 0;
154
155  // Invoked from |AddTabAt| after the newly created tab has been inserted.
156  // Subclasses should either start an animation, or layout.
157  virtual void StartInsertTabAnimation(int model_index) = 0;
158
159  // Invoked from |MoveTab| after |tab_data_| has been updated to animate the
160  // move.
161  virtual void StartMoveTabAnimation();
162
163  // Starts the remove tab animation.
164  virtual void StartRemoveTabAnimation(int model_index);
165
166  // Starts the mini-tab animation.
167  virtual void StartMiniTabAnimation();
168
169  // Returns whether the highlight button should be highlighted after a remove.
170  virtual bool ShouldHighlightCloseButtonAfterRemove();
171
172  // Animates all the views to their ideal bounds.
173  // NOTE: this does *not* invoke GenerateIdealBounds, it uses the bounds
174  // currently set in ideal_bounds.
175  virtual void AnimateToIdealBounds() = 0;
176
177  // Cleans up the Tab from the TabStrip. This is called from the tab animation
178  // code and is not a general-purpose method.
179  void RemoveAndDeleteTab(BaseTab* tab);
180
181  // Resets the bounds of all non-closing tabs.
182  virtual void GenerateIdealBounds() = 0;
183
184  // Invoked during drag to layout the tabs being dragged in |tabs| at
185  // |location|. If |initial_drag| is true, this is the initial layout after the
186  // user moved the mouse far enough to trigger a drag.
187  virtual void LayoutDraggedTabsAt(const std::vector<BaseTab*>& tabs,
188                                   BaseTab* active_tab,
189                                   const gfx::Point& location,
190                                   bool initial_drag) = 0;
191
192  // Calculates the bounds needed for each of the tabs, placing the result in
193  // |bounds|.
194  virtual void CalculateBoundsForDraggedTabs(
195      const std::vector<BaseTab*>& tabs,
196      std::vector<gfx::Rect>* bounds) = 0;
197
198  void set_ideal_bounds(int index, const gfx::Rect& bounds) {
199    tab_data_[index].ideal_bounds = bounds;
200  }
201
202  // Returns the index into |tab_data_| corresponding to the specified tab, or
203  // -1 if the tab isn't in |tab_data_|.
204  int TabIndexOfTab(BaseTab* tab) const;
205
206  // Stops any ongoing animations. If |layout| is true and an animation is
207  // ongoing this does a layout.
208  virtual void StopAnimating(bool layout);
209
210  // Destroys the active drag controller.
211  void DestroyDragController();
212
213  // Used by DraggedTabController when the user starts or stops dragging tabs.
214  void StartedDraggingTabs(const std::vector<BaseTab*>& tabs);
215  void StoppedDraggingTabs(const std::vector<BaseTab*>& tabs);
216
217  // Returns the size needed for the specified tabs. This is invoked during drag
218  // and drop to calculate offsets and positioning.
219  virtual int GetSizeNeededForTabs(const std::vector<BaseTab*>& tabs) = 0;
220
221  // See description above field for details.
222  bool attaching_dragged_tab() const { return attaching_dragged_tab_; }
223
224  views::BoundsAnimator& bounds_animator() { return bounds_animator_; }
225
226  // Invoked prior to starting a new animation.
227  virtual void PrepareForAnimation();
228
229  // Creates an AnimationDelegate that resets state after a remove animation
230  // completes. The caller owns the returned object.
231  ui::AnimationDelegate* CreateRemoveTabDelegate(BaseTab* tab);
232
233  // Invoked from Layout if the size changes or layout is really needed.
234  virtual void DoLayout();
235
236  // Returns true if Tabs in this TabStrip are currently changing size or
237  // position.
238  bool IsAnimating() const;
239
240  // Get tab at a point in local view coordinates.
241  BaseTab* GetTabAtLocal(const gfx::Point& local_point);
242
243 private:
244  class RemoveTabDelegate;
245
246  friend class DraggedTabController;
247
248  // Invoked from StoppedDraggingTabs to cleanup |tab|. If |tab| is known
249  // |is_first_tab| is set to true.
250  void StoppedDraggingTab(BaseTab* tab, bool* is_first_tab);
251
252  // See description above field for details.
253  void set_attaching_dragged_tab(bool value) { attaching_dragged_tab_ = value; }
254
255  scoped_ptr<TabStripController> controller_;
256
257  const Type type_;
258
259  std::vector<TabData> tab_data_;
260
261  // The controller for a drag initiated from a Tab. Valid for the lifetime of
262  // the drag session.
263  scoped_ptr<DraggedTabController> drag_controller_;
264
265  // If true, the insert is a result of a drag attaching the tab back to the
266  // model.
267  bool attaching_dragged_tab_;
268
269  views::BoundsAnimator bounds_animator_;
270
271  // Size we last layed out at.
272  gfx::Size last_layout_size_;
273};
274
275#endif  // CHROME_BROWSER_UI_VIEWS_TABS_BASE_TAB_STRIP_H_
276