Don't leave aborted URLs in the omnibox unless we're on the NTP.
[chromium-blink-merge.git] / ash / shelf / shelf_tooltip_manager.cc
blobecfcaa3c3a9bc1c79e85d2c3f5d15eded12df9e3
1 // Copyright 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 "ash/shelf/shelf_tooltip_manager.h"
7 #include "ash/shelf/shelf_layout_manager.h"
8 #include "ash/shelf/shelf_view.h"
9 #include "ash/shell.h"
10 #include "ash/shell_window_ids.h"
11 #include "ash/wm/window_animations.h"
12 #include "base/bind.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/time/time.h"
15 #include "base/timer/timer.h"
16 #include "ui/aura/window.h"
17 #include "ui/aura/window_event_dispatcher.h"
18 #include "ui/events/event.h"
19 #include "ui/events/event_constants.h"
20 #include "ui/gfx/insets.h"
21 #include "ui/views/bubble/bubble_delegate.h"
22 #include "ui/views/bubble/bubble_frame_view.h"
23 #include "ui/views/controls/label.h"
24 #include "ui/views/layout/fill_layout.h"
25 #include "ui/views/widget/widget.h"
27 namespace ash {
28 namespace {
29 const int kTooltipTopBottomMargin = 3;
30 const int kTooltipLeftRightMargin = 10;
31 const int kTooltipAppearanceDelay = 1000; // msec
32 const int kTooltipMinHeight = 29 - 2 * kTooltipTopBottomMargin;
33 const SkColor kTooltipTextColor = SkColorSetRGB(0x22, 0x22, 0x22);
35 // The maximum width of the tooltip bubble. Borrowed the value from
36 // ash/tooltip/tooltip_controller.cc
37 const int kTooltipMaxWidth = 250;
39 // The offset for the tooltip bubble - making sure that the bubble is flush
40 // with the shelf. The offset includes the arrow size in pixels as well as
41 // the activation bar and other spacing elements.
42 const int kArrowOffsetLeftRight = 11;
43 const int kArrowOffsetTopBottom = 7;
45 } // namespace
47 // The implementation of tooltip of the launcher.
48 class ShelfTooltipManager::ShelfTooltipBubble
49 : public views::BubbleDelegateView {
50 public:
51 ShelfTooltipBubble(views::View* anchor,
52 views::BubbleBorder::Arrow arrow,
53 ShelfTooltipManager* host);
55 void SetText(const base::string16& text);
56 void Close();
58 private:
59 // views::WidgetDelegate overrides:
60 virtual void WindowClosing() OVERRIDE;
62 // views::View overrides:
63 virtual gfx::Size GetPreferredSize() OVERRIDE;
65 ShelfTooltipManager* host_;
66 views::Label* label_;
68 DISALLOW_COPY_AND_ASSIGN(ShelfTooltipBubble);
71 ShelfTooltipManager::ShelfTooltipBubble::ShelfTooltipBubble(
72 views::View* anchor,
73 views::BubbleBorder::Arrow arrow,
74 ShelfTooltipManager* host)
75 : views::BubbleDelegateView(anchor, arrow), host_(host) {
76 // Make sure that the bubble follows the animation of the shelf.
77 set_move_with_anchor(true);
78 gfx::Insets insets = gfx::Insets(kArrowOffsetTopBottom,
79 kArrowOffsetLeftRight,
80 kArrowOffsetTopBottom,
81 kArrowOffsetLeftRight);
82 // Shelf items can have an asymmetrical border for spacing reasons.
83 // Adjust anchor location for this.
84 if (anchor->border())
85 insets += anchor->border()->GetInsets();
87 set_anchor_view_insets(insets);
88 set_close_on_esc(false);
89 set_close_on_deactivate(false);
90 set_use_focusless(true);
91 set_accept_events(false);
92 set_margins(gfx::Insets(kTooltipTopBottomMargin, kTooltipLeftRightMargin,
93 kTooltipTopBottomMargin, kTooltipLeftRightMargin));
94 set_shadow(views::BubbleBorder::SMALL_SHADOW);
95 SetLayoutManager(new views::FillLayout());
96 // The anchor may not have the widget in tests.
97 if (anchor->GetWidget() && anchor->GetWidget()->GetNativeView()) {
98 aura::Window* root_window =
99 anchor->GetWidget()->GetNativeView()->GetRootWindow();
100 set_parent_window(ash::Shell::GetInstance()->GetContainer(
101 root_window, ash::kShellWindowId_SettingBubbleContainer));
103 label_ = new views::Label;
104 label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
105 label_->SetEnabledColor(kTooltipTextColor);
106 AddChildView(label_);
107 views::BubbleDelegateView::CreateBubble(this);
110 void ShelfTooltipManager::ShelfTooltipBubble::SetText(
111 const base::string16& text) {
112 label_->SetText(text);
113 SizeToContents();
116 void ShelfTooltipManager::ShelfTooltipBubble::Close() {
117 if (GetWidget()) {
118 host_ = NULL;
119 GetWidget()->Close();
123 void ShelfTooltipManager::ShelfTooltipBubble::WindowClosing() {
124 views::BubbleDelegateView::WindowClosing();
125 if (host_)
126 host_->OnBubbleClosed(this);
129 gfx::Size ShelfTooltipManager::ShelfTooltipBubble::GetPreferredSize() {
130 gfx::Size pref_size = views::BubbleDelegateView::GetPreferredSize();
131 if (pref_size.height() < kTooltipMinHeight)
132 pref_size.set_height(kTooltipMinHeight);
133 if (pref_size.width() > kTooltipMaxWidth)
134 pref_size.set_width(kTooltipMaxWidth);
135 return pref_size;
138 ShelfTooltipManager::ShelfTooltipManager(
139 ShelfLayoutManager* shelf_layout_manager,
140 ShelfView* shelf_view)
141 : view_(NULL),
142 widget_(NULL),
143 anchor_(NULL),
144 shelf_layout_manager_(shelf_layout_manager),
145 shelf_view_(shelf_view),
146 weak_factory_(this) {
147 if (shelf_layout_manager)
148 shelf_layout_manager->AddObserver(this);
149 if (Shell::HasInstance())
150 Shell::GetInstance()->AddPreTargetHandler(this);
153 ShelfTooltipManager::~ShelfTooltipManager() {
154 CancelHidingAnimation();
155 Close();
156 if (shelf_layout_manager_)
157 shelf_layout_manager_->RemoveObserver(this);
158 if (Shell::HasInstance())
159 Shell::GetInstance()->RemovePreTargetHandler(this);
162 void ShelfTooltipManager::ShowDelayed(views::View* anchor,
163 const base::string16& text) {
164 if (view_) {
165 if (timer_.get() && timer_->IsRunning()) {
166 return;
167 } else {
168 CancelHidingAnimation();
169 Close();
173 if (shelf_layout_manager_ && !shelf_layout_manager_->IsVisible())
174 return;
176 CreateBubble(anchor, text);
177 ResetTimer();
180 void ShelfTooltipManager::ShowImmediately(views::View* anchor,
181 const base::string16& text) {
182 if (view_) {
183 if (timer_.get() && timer_->IsRunning())
184 StopTimer();
185 CancelHidingAnimation();
186 Close();
189 if (shelf_layout_manager_ && !shelf_layout_manager_->IsVisible())
190 return;
192 CreateBubble(anchor, text);
193 ShowInternal();
196 void ShelfTooltipManager::Close() {
197 StopTimer();
198 if (view_) {
199 view_->Close();
200 view_ = NULL;
201 widget_ = NULL;
205 void ShelfTooltipManager::OnBubbleClosed(views::BubbleDelegateView* view) {
206 if (view == view_) {
207 view_ = NULL;
208 widget_ = NULL;
212 void ShelfTooltipManager::UpdateArrow() {
213 if (view_) {
214 CancelHidingAnimation();
215 Close();
216 ShowImmediately(anchor_, text_);
220 void ShelfTooltipManager::ResetTimer() {
221 if (timer_.get() && timer_->IsRunning()) {
222 timer_->Reset();
223 return;
226 // We don't start the timer if the shelf isn't visible.
227 if (shelf_layout_manager_ && !shelf_layout_manager_->IsVisible())
228 return;
230 CreateTimer(kTooltipAppearanceDelay);
233 void ShelfTooltipManager::StopTimer() {
234 timer_.reset();
237 bool ShelfTooltipManager::IsVisible() {
238 if (timer_.get() && timer_->IsRunning())
239 return false;
241 return widget_ && widget_->IsVisible();
244 void ShelfTooltipManager::CreateZeroDelayTimerForTest() {
245 CreateTimer(0);
248 void ShelfTooltipManager::OnMouseEvent(ui::MouseEvent* event) {
249 DCHECK(event);
250 DCHECK(event->target());
251 if (!widget_ || !widget_->IsVisible())
252 return;
254 DCHECK(view_);
255 DCHECK(shelf_view_);
257 // Pressing the mouse button anywhere should close the tooltip.
258 if (event->type() == ui::ET_MOUSE_PRESSED) {
259 CloseSoon();
260 return;
263 aura::Window* target = static_cast<aura::Window*>(event->target());
264 if (widget_->GetNativeWindow()->GetRootWindow() != target->GetRootWindow()) {
265 CloseSoon();
266 return;
269 gfx::Point location_in_shelf_view = event->location();
270 aura::Window::ConvertPointToTarget(
271 target, shelf_view_->GetWidget()->GetNativeWindow(),
272 &location_in_shelf_view);
274 if (shelf_view_->ShouldHideTooltip(location_in_shelf_view)) {
275 // Because this mouse event may arrive to |view_|, here we just schedule
276 // the closing event rather than directly calling Close().
277 CloseSoon();
281 void ShelfTooltipManager::OnTouchEvent(ui::TouchEvent* event) {
282 aura::Window* target = static_cast<aura::Window*>(event->target());
283 if (widget_ && widget_->IsVisible() && widget_->GetNativeWindow() != target)
284 Close();
287 void ShelfTooltipManager::OnGestureEvent(ui::GestureEvent* event) {
288 if (widget_ && widget_->IsVisible()) {
289 // Because this mouse event may arrive to |view_|, here we just schedule
290 // the closing event rather than directly calling Close().
291 CloseSoon();
295 void ShelfTooltipManager::OnCancelMode(ui::CancelModeEvent* event) {
296 Close();
299 void ShelfTooltipManager::WillDeleteShelf() {
300 shelf_layout_manager_ = NULL;
303 void ShelfTooltipManager::WillChangeVisibilityState(
304 ShelfVisibilityState new_state) {
305 if (new_state == SHELF_HIDDEN) {
306 StopTimer();
307 Close();
311 void ShelfTooltipManager::OnAutoHideStateChanged(ShelfAutoHideState new_state) {
312 if (new_state == SHELF_AUTO_HIDE_HIDDEN) {
313 StopTimer();
314 // AutoHide state change happens during an event filter, so immediate close
315 // may cause a crash in the HandleMouseEvent() after the filter. So we just
316 // schedule the Close here.
317 CloseSoon();
321 void ShelfTooltipManager::CancelHidingAnimation() {
322 if (!widget_ || !widget_->GetNativeView())
323 return;
325 gfx::NativeView native_view = widget_->GetNativeView();
326 wm::SetWindowVisibilityAnimationTransition(
327 native_view, wm::ANIMATE_NONE);
330 void ShelfTooltipManager::CloseSoon() {
331 base::MessageLoopForUI::current()->PostTask(
332 FROM_HERE,
333 base::Bind(&ShelfTooltipManager::Close, weak_factory_.GetWeakPtr()));
336 void ShelfTooltipManager::ShowInternal() {
337 if (view_)
338 view_->GetWidget()->Show();
340 timer_.reset();
343 void ShelfTooltipManager::CreateBubble(views::View* anchor,
344 const base::string16& text) {
345 DCHECK(!view_);
347 anchor_ = anchor;
348 text_ = text;
349 views::BubbleBorder::Arrow arrow =
350 shelf_layout_manager_->SelectValueForShelfAlignment(
351 views::BubbleBorder::BOTTOM_CENTER,
352 views::BubbleBorder::LEFT_CENTER,
353 views::BubbleBorder::RIGHT_CENTER,
354 views::BubbleBorder::TOP_CENTER);
356 view_ = new ShelfTooltipBubble(anchor, arrow, this);
357 widget_ = view_->GetWidget();
358 view_->SetText(text_);
360 gfx::NativeView native_view = widget_->GetNativeView();
361 wm::SetWindowVisibilityAnimationType(
362 native_view, wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL);
363 wm::SetWindowVisibilityAnimationTransition(
364 native_view, wm::ANIMATE_HIDE);
367 void ShelfTooltipManager::CreateTimer(int delay_in_ms) {
368 base::OneShotTimer<ShelfTooltipManager>* new_timer =
369 new base::OneShotTimer<ShelfTooltipManager>();
370 new_timer->Start(FROM_HERE,
371 base::TimeDelta::FromMilliseconds(delay_in_ms),
372 this,
373 &ShelfTooltipManager::ShowInternal);
374 timer_.reset(new_timer);
377 } // namespace ash