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