Add a minor text member to ui::MenuModel.
[chromium-blink-merge.git] / chrome / browser / ui / views / ash / tab_scrubber.cc
blob5b106d2acaa910a70e9399159b83eac883ee9824
1 // Copyright (c) 2013 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.
5 #include "chrome/browser/ui/views/ash/tab_scrubber.h"
7 #include "ash/shell.h"
8 #include "ash/wm/window_util.h"
9 #include "base/metrics/histogram.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/browser_finder.h"
13 #include "chrome/browser/ui/tabs/tab_strip_model.h"
14 #include "chrome/browser/ui/views/frame/browser_view.h"
15 #include "chrome/browser/ui/views/tabs/tab.h"
16 #include "chrome/browser/ui/views/tabs/tab_strip.h"
17 #include "chrome/common/pref_names.h"
18 #include "content/public/browser/notification_service.h"
19 #include "content/public/browser/notification_source.h"
20 #include "ui/aura/window.h"
21 #include "ui/base/events/event.h"
22 #include "ui/base/events/event_utils.h"
23 #include "ui/base/gestures/gesture_configuration.h"
24 #include "ui/views/controls/glow_hover_controller.h"
26 namespace {
27 const int64 kActivationDelayMS = 200;
30 // static
31 TabScrubber* TabScrubber::GetInstance() {
32 static TabScrubber* instance = NULL;
33 if (!instance)
34 instance = new TabScrubber();
35 return instance;
38 // static
39 gfx::Point TabScrubber::GetStartPoint(
40 TabStrip* tab_strip,
41 int index,
42 TabScrubber::Direction direction) {
43 int initial_tab_offset = Tab::GetMiniWidth() / 2;
44 gfx::Rect tab_bounds = tab_strip->tab_at(index)->bounds();
45 float x = direction == LEFT ?
46 tab_bounds.x() + initial_tab_offset :
47 tab_bounds.right() - initial_tab_offset;
48 return gfx::Point(x, tab_bounds.CenterPoint().y());
51 bool TabScrubber::IsActivationPending() {
52 return activate_timer_.IsRunning();
55 TabScrubber::TabScrubber()
56 : scrubbing_(false),
57 browser_(NULL),
58 swipe_x_(-1),
59 swipe_y_(-1),
60 swipe_direction_(LEFT),
61 highlighted_tab_(-1),
62 activate_timer_(true, false),
63 activation_delay_(kActivationDelayMS),
64 use_default_activation_delay_(true),
65 weak_ptr_factory_(this) {
66 ash::Shell::GetInstance()->AddPreTargetHandler(this);
67 registrar_.Add(
68 this,
69 chrome::NOTIFICATION_BROWSER_CLOSED,
70 content::NotificationService::AllSources());
73 TabScrubber::~TabScrubber() {
74 // Note: The weak_ptr_factory_ should invalidate its weak pointers before
75 // any other members are destroyed.
76 weak_ptr_factory_.InvalidateWeakPtrs();
79 void TabScrubber::OnScrollEvent(ui::ScrollEvent* event) {
80 if (event->type() == ui::ET_SCROLL_FLING_CANCEL ||
81 event->type() == ui::ET_SCROLL_FLING_START) {
82 FinishScrub(true);
83 immersive_reveal_lock_.reset();
84 return;
87 if (event->finger_count() != 3)
88 return;
90 Browser* browser = GetActiveBrowser();
91 if (!browser || (scrubbing_ && browser_ && browser != browser_) ||
92 (highlighted_tab_ != -1 &&
93 highlighted_tab_ >= browser->tab_strip_model()->count())) {
94 FinishScrub(false);
95 return;
98 BrowserView* browser_view =
99 BrowserView::GetBrowserViewForNativeWindow(
100 browser->window()->GetNativeWindow());
101 TabStrip* tab_strip = browser_view->tabstrip();
103 if (tab_strip->IsAnimating()) {
104 FinishScrub(false);
105 return;
108 // We are handling the event.
109 event->StopPropagation();
111 float x_offset = event->x_offset();
112 if (!ui::IsNaturalScrollEnabled())
113 x_offset = -x_offset;
114 int last_tab_index = highlighted_tab_ == -1 ?
115 browser->tab_strip_model()->active_index() : highlighted_tab_;
116 if (!scrubbing_) {
117 swipe_direction_ = (x_offset < 0) ? LEFT : RIGHT;
118 const gfx::Point start_point =
119 GetStartPoint(tab_strip,
120 browser->tab_strip_model()->active_index(),
121 swipe_direction_);
122 browser_ = browser;
123 scrubbing_ = true;
125 swipe_x_ = start_point.x();
126 swipe_y_ = start_point.y();
127 ImmersiveModeController* immersive_controller =
128 browser_view->immersive_mode_controller();
129 if (immersive_controller->IsEnabled()) {
130 immersive_reveal_lock_.reset(immersive_controller->GetRevealedLock(
131 ImmersiveModeController::ANIMATE_REVEAL_YES));
133 tab_strip->AddObserver(this);
134 } else if (highlighted_tab_ == -1) {
135 Direction direction = (x_offset < 0) ? LEFT : RIGHT;
136 if (direction != swipe_direction_) {
137 const gfx::Point start_point =
138 GetStartPoint(tab_strip,
139 browser->tab_strip_model()->active_index(),
140 direction);
141 swipe_x_ = start_point.x();
142 swipe_y_ = start_point.y();
143 swipe_direction_ = direction;
147 swipe_x_ += x_offset;
148 Tab* first_tab = tab_strip->tab_at(0);
149 int first_tab_center = first_tab->bounds().CenterPoint().x();
150 Tab* last_tab = tab_strip->tab_at(tab_strip->tab_count() - 1);
151 int last_tab_tab_center = last_tab->bounds().CenterPoint().x();
152 if (swipe_x_ < first_tab_center)
153 swipe_x_ = first_tab_center;
154 if (swipe_x_ > last_tab_tab_center)
155 swipe_x_ = last_tab_tab_center;
157 Tab* initial_tab = tab_strip->tab_at(last_tab_index);
158 gfx::Point tab_point(swipe_x_, swipe_y_);
159 views::View::ConvertPointToTarget(tab_strip, initial_tab, &tab_point);
160 Tab* new_tab = tab_strip->GetTabAt(initial_tab, tab_point);
161 if (!new_tab)
162 return;
164 int new_index = tab_strip->GetModelIndexOfTab(new_tab);
165 if (highlighted_tab_ == -1 &&
166 new_index == browser->tab_strip_model()->active_index())
167 return;
169 if (new_index != highlighted_tab_) {
170 if (activate_timer_.IsRunning()) {
171 activate_timer_.Reset();
172 } else {
173 int delay = use_default_activation_delay_ ?
174 ui::GestureConfiguration::tab_scrub_activation_delay_in_ms() :
175 activation_delay_;
176 if (delay >= 0) {
177 activate_timer_.Start(FROM_HERE,
178 base::TimeDelta::FromMilliseconds(delay),
179 base::Bind(&TabScrubber::FinishScrub,
180 weak_ptr_factory_.GetWeakPtr(),
181 true));
184 if (highlighted_tab_ != -1) {
185 Tab* tab = tab_strip->tab_at(highlighted_tab_);
186 tab->hover_controller()->HideImmediately();
188 if (new_index == browser->tab_strip_model()->active_index()) {
189 highlighted_tab_ = -1;
190 } else {
191 highlighted_tab_ = new_index;
192 new_tab->hover_controller()->Show(views::GlowHoverController::PRONOUNCED);
195 if (highlighted_tab_ != -1) {
196 gfx::Point hover_point(swipe_x_, swipe_y_);
197 views::View::ConvertPointToTarget(tab_strip, new_tab, &hover_point);
198 new_tab->hover_controller()->SetLocation(hover_point);
202 void TabScrubber::Observe(int type,
203 const content::NotificationSource& source,
204 const content::NotificationDetails& details) {
205 if (content::Source<Browser>(source).ptr() == browser_) {
206 activate_timer_.Stop();
207 swipe_x_ = -1;
208 swipe_y_ = -1;
209 scrubbing_ = false;
210 highlighted_tab_ = -1;
211 browser_ = NULL;
215 void TabScrubber::TabStripAddedTabAt(TabStrip* tab_strip, int index) {
216 if (highlighted_tab_ == -1)
217 return;
219 if (index < highlighted_tab_)
220 ++highlighted_tab_;
223 void TabScrubber::TabStripMovedTab(TabStrip* tab_strip,
224 int from_index,
225 int to_index) {
226 if (highlighted_tab_ == -1)
227 return;
229 if (from_index == highlighted_tab_)
230 highlighted_tab_ = to_index;
231 else if (from_index < highlighted_tab_&& highlighted_tab_<= to_index)
232 --highlighted_tab_;
233 else if (from_index > highlighted_tab_ && highlighted_tab_ >= to_index)
234 ++highlighted_tab_;
237 void TabScrubber::TabStripRemovedTabAt(TabStrip* tab_strip, int index) {
238 if (highlighted_tab_ == -1)
239 return;
240 if (index == highlighted_tab_) {
241 FinishScrub(false);
242 return;
244 if (index < highlighted_tab_)
245 --highlighted_tab_;
248 void TabScrubber::TabStripDeleted(TabStrip* tab_strip) {
249 if (highlighted_tab_ == -1)
250 return;
253 Browser* TabScrubber::GetActiveBrowser() {
254 aura::Window* active_window = ash::wm::GetActiveWindow();
255 if (!active_window)
256 return NULL;
258 Browser* browser = chrome::FindBrowserWithWindow(active_window);
259 if (!browser || browser->type() != Browser::TYPE_TABBED)
260 return NULL;
262 return browser;
265 void TabScrubber::FinishScrub(bool activate) {
266 activate_timer_.Stop();
268 if (browser_ && browser_->window()) {
269 BrowserView* browser_view =
270 BrowserView::GetBrowserViewForNativeWindow(
271 browser_->window()->GetNativeWindow());
272 TabStrip* tab_strip = browser_view->tabstrip();
273 if (activate && highlighted_tab_ != -1) {
274 Tab* tab = tab_strip->tab_at(highlighted_tab_);
275 tab->hover_controller()->HideImmediately();
276 int distance =
277 std::abs(
278 highlighted_tab_ - browser_->tab_strip_model()->active_index());
279 UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.ScrubDistance", distance, 0, 20, 20);
280 browser_->tab_strip_model()->ActivateTabAt(highlighted_tab_, true);
282 tab_strip->RemoveObserver(this);
284 swipe_x_ = -1;
285 swipe_y_ = -1;
286 scrubbing_ = false;
287 highlighted_tab_ = -1;