Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / dropdown_bar_host.cc
1 // Copyright (c) 2012 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/dropdown_bar_host.h"
6
7 #include <algorithm>
8
9 #include "chrome/browser/ui/view_ids.h"
10 #include "chrome/browser/ui/views/dropdown_bar_host_delegate.h"
11 #include "chrome/browser/ui/views/dropdown_bar_view.h"
12 #include "chrome/browser/ui/views/frame/browser_view.h"
13 #include "ui/events/keycodes/keyboard_codes.h"
14 #include "ui/gfx/animation/slide_animation.h"
15 #include "ui/gfx/scrollbar_size.h"
16 #include "ui/views/focus/external_focus_tracker.h"
17 #include "ui/views/focus/view_storage.h"
18 #include "ui/views/widget/widget.h"
19
20 // static
21 bool DropdownBarHost::disable_animations_during_testing_ = false;
22
23 ////////////////////////////////////////////////////////////////////////////////
24 // DropdownBarHost, public:
25
26 DropdownBarHost::DropdownBarHost(BrowserView* browser_view)
27     : browser_view_(browser_view),
28       view_(NULL),
29       delegate_(NULL),
30       animation_offset_(0),
31       focus_manager_(NULL),
32       esc_accel_target_registered_(false),
33       is_visible_(false) {
34 }
35
36 void DropdownBarHost::Init(views::View* host_view,
37                            views::View* view,
38                            DropdownBarHostDelegate* delegate) {
39   DCHECK(view);
40   DCHECK(delegate);
41
42   view_ = view;
43   delegate_ = delegate;
44
45   // Initialize the host.
46   host_.reset(new views::Widget);
47   views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
48   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
49   params.parent = browser_view_->GetWidget()->GetNativeView();
50   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
51   host_->Init(params);
52   host_->SetContentsView(view_);
53
54   SetHostViewNative(host_view);
55
56   // Start listening to focus changes, so we can register and unregister our
57   // own handler for Escape.
58   focus_manager_ = host_->GetFocusManager();
59   if (focus_manager_) {
60     focus_manager_->AddFocusChangeListener(this);
61   } else {
62     // In some cases (see bug http://crbug.com/17056) it seems we may not have
63     // a focus manager.  Please reopen the bug if you hit this.
64     NOTREACHED();
65   }
66
67   // Start the process of animating the opening of the widget.
68   animation_.reset(new gfx::SlideAnimation(this));
69 }
70
71 DropdownBarHost::~DropdownBarHost() {
72   focus_manager_->RemoveFocusChangeListener(this);
73   focus_tracker_.reset(NULL);
74 }
75
76 void DropdownBarHost::Show(bool animate) {
77   // Stores the currently focused view, and tracks focus changes so that we can
78   // restore focus when the dropdown widget is closed.
79   focus_tracker_.reset(new views::ExternalFocusTracker(view_, focus_manager_));
80
81   bool was_visible = is_visible_;
82   is_visible_ = true;
83   if (!animate || disable_animations_during_testing_) {
84     animation_->Reset(1);
85     AnimationProgressed(animation_.get());
86   } else if (!was_visible) {
87     // Don't re-start the animation.
88     animation_->Reset();
89     animation_->Show();
90   }
91
92   if (!was_visible)
93     OnVisibilityChanged();
94 }
95
96 void DropdownBarHost::SetFocusAndSelection() {
97   delegate_->SetFocusAndSelection(true);
98 }
99
100 bool DropdownBarHost::IsAnimating() const {
101   return animation_->is_animating();
102 }
103
104 void DropdownBarHost::Hide(bool animate) {
105   if (!IsVisible())
106     return;
107   if (animate && !disable_animations_during_testing_ &&
108       !animation_->IsClosing()) {
109     animation_->Hide();
110   } else {
111     if (animation_->IsClosing()) {
112       // If we're in the middle of a close animation, skip immediately to the
113       // end of the animation.
114       StopAnimation();
115     } else {
116       // Otherwise we need to set both the animation state to ended and the
117       // DropdownBarHost state to ended/hidden, otherwise the next time we try
118       // to show the bar, it might refuse to do so. Note that we call
119       // AnimationEnded ourselves as Reset does not call it if we are not
120       // animating here.
121       animation_->Reset();
122       AnimationEnded(animation_.get());
123     }
124   }
125 }
126
127 void DropdownBarHost::StopAnimation() {
128   animation_->End();
129 }
130
131 bool DropdownBarHost::IsVisible() const {
132   return is_visible_;
133 }
134
135 ////////////////////////////////////////////////////////////////////////////////
136 // DropdownBarHost, views::FocusChangeListener implementation:
137 void DropdownBarHost::OnWillChangeFocus(views::View* focused_before,
138                                         views::View* focused_now) {
139   // First we need to determine if one or both of the views passed in are child
140   // views of our view.
141   bool our_view_before = focused_before && view_->Contains(focused_before);
142   bool our_view_now = focused_now && view_->Contains(focused_now);
143
144   // When both our_view_before and our_view_now are false, it means focus is
145   // changing hands elsewhere in the application (and we shouldn't do anything).
146   // Similarly, when both are true, focus is changing hands within the dropdown
147   // widget (and again, we should not do anything). We therefore only need to
148   // look at when we gain initial focus and when we loose it.
149   if (!our_view_before && our_view_now) {
150     // We are gaining focus from outside the dropdown widget so we must register
151     // a handler for Escape.
152     RegisterAccelerators();
153   } else if (our_view_before && !our_view_now) {
154     // We are losing focus to something outside our widget so we restore the
155     // original handler for Escape.
156     UnregisterAccelerators();
157   }
158 }
159
160 void DropdownBarHost::OnDidChangeFocus(views::View* focused_before,
161                                        views::View* focused_now) {
162 }
163
164 ////////////////////////////////////////////////////////////////////////////////
165 // DropdownBarHost, gfx::AnimationDelegate implementation:
166
167 void DropdownBarHost::AnimationProgressed(const gfx::Animation* animation) {
168   // First, we calculate how many pixels to slide the widget.
169   gfx::Size pref_size = view_->GetPreferredSize();
170   animation_offset_ = static_cast<int>((1.0 - animation_->GetCurrentValue()) *
171                                        pref_size.height());
172
173   // This call makes sure it appears in the right location, the size and shape
174   // is correct and that it slides in the right direction.
175   gfx::Rect dlg_rect = GetDialogPosition(gfx::Rect());
176   SetDialogPosition(dlg_rect, false);
177
178   // Let the view know if we are animating, and at which offset to draw the
179   // edges.
180   delegate_->SetAnimationOffset(animation_offset_);
181   view_->SchedulePaint();
182 }
183
184 void DropdownBarHost::AnimationEnded(const gfx::Animation* animation) {
185   // Place the dropdown widget in its fully opened state.
186   animation_offset_ = 0;
187
188   if (!animation_->IsShowing()) {
189     // Animation has finished closing.
190     host_->Hide();
191     is_visible_ = false;
192     OnVisibilityChanged();
193   } else {
194     // Animation has finished opening.
195   }
196 }
197
198 ////////////////////////////////////////////////////////////////////////////////
199 // DropdownBarHost protected:
200
201 void DropdownBarHost::ResetFocusTracker() {
202   focus_tracker_.reset(NULL);
203 }
204
205 void DropdownBarHost::OnVisibilityChanged() {
206 }
207
208 void DropdownBarHost::GetWidgetBounds(gfx::Rect* bounds) {
209   DCHECK(bounds);
210   *bounds = browser_view_->bounds();
211 }
212
213 void DropdownBarHost::RegisterAccelerators() {
214   DCHECK(!esc_accel_target_registered_);
215   ui::Accelerator escape(ui::VKEY_ESCAPE, ui::EF_NONE);
216   focus_manager_->RegisterAccelerator(
217       escape, ui::AcceleratorManager::kNormalPriority, this);
218   esc_accel_target_registered_ = true;
219 }
220
221 void DropdownBarHost::UnregisterAccelerators() {
222   DCHECK(esc_accel_target_registered_);
223   ui::Accelerator escape(ui::VKEY_ESCAPE, ui::EF_NONE);
224   focus_manager_->UnregisterAccelerator(escape, this);
225   esc_accel_target_registered_ = false;
226 }