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 "ui/views/corewm/tooltip_controller.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "ui/aura/client/cursor_client.h"
9 #include "ui/aura/client/screen_position_client.h"
10 #include "ui/aura/env.h"
11 #include "ui/aura/test/aura_test_base.h"
12 #include "ui/aura/test/test_screen.h"
13 #include "ui/aura/test/test_window_delegate.h"
14 #include "ui/aura/window.h"
15 #include "ui/aura/window_event_dispatcher.h"
16 #include "ui/events/test/event_generator.h"
17 #include "ui/gfx/font.h"
18 #include "ui/gfx/point.h"
19 #include "ui/gfx/screen.h"
20 #include "ui/gfx/screen_type_delegate.h"
21 #include "ui/gfx/text_elider.h"
22 #include "ui/views/corewm/tooltip_aura.h"
23 #include "ui/views/corewm/tooltip_controller_test_helper.h"
24 #include "ui/views/test/desktop_test_views_delegate.h"
25 #include "ui/views/test/test_views_delegate.h"
26 #include "ui/views/view.h"
27 #include "ui/views/widget/tooltip_manager.h"
28 #include "ui/views/widget/widget.h"
29 #include "ui/wm/core/default_activation_client.h"
30 #include "ui/wm/core/wm_state.h"
31 #include "ui/wm/public/tooltip_client.h"
32 #include "ui/wm/public/window_types.h"
35 #include "ui/base/win/scoped_ole_initializer.h"
38 #if !defined(OS_CHROMEOS)
39 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
40 #include "ui/views/widget/desktop_aura/desktop_screen.h"
43 using base::ASCIIToUTF16
;
50 views::Widget
* CreateWidget(aura::Window
* root
) {
51 views::Widget
* widget
= new views::Widget
;
52 views::Widget::InitParams params
;
53 params
.type
= views::Widget::InitParams::TYPE_WINDOW_FRAMELESS
;
54 params
.accept_events
= true;
55 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
56 #if defined(OS_CHROMEOS)
59 params
.native_widget
= new DesktopNativeWidgetAura(widget
);
61 params
.bounds
= gfx::Rect(0, 0, 200, 100);
67 TooltipController
* GetController(Widget
* widget
) {
68 return static_cast<TooltipController
*>(
69 aura::client::GetTooltipClient(
70 widget
->GetNativeWindow()->GetRootWindow()));
75 class TooltipControllerTest
: public aura::test::AuraTestBase
{
77 TooltipControllerTest() : view_(NULL
) {}
78 virtual ~TooltipControllerTest() {}
80 virtual void SetUp() OVERRIDE
{
81 #if defined(OS_CHROMEOS)
82 views_delegate_
.reset(new TestViewsDelegate
);
84 views_delegate_
.reset(new DesktopTestViewsDelegate
);
87 aura::test::AuraTestBase::SetUp();
88 new wm::DefaultActivationClient(root_window());
89 #if defined(OS_CHROMEOS)
90 controller_
.reset(new TooltipController(
91 scoped_ptr
<views::corewm::Tooltip
>(
92 new views::corewm::TooltipAura(gfx::SCREEN_TYPE_ALTERNATE
))));
93 root_window()->AddPreTargetHandler(controller_
.get());
94 SetTooltipClient(root_window(), controller_
.get());
96 widget_
.reset(CreateWidget(root_window()));
97 widget_
->SetContentsView(new View
);
98 view_
= new TooltipTestView
;
99 widget_
->GetContentsView()->AddChildView(view_
);
100 view_
->SetBoundsRect(widget_
->GetContentsView()->GetLocalBounds());
101 helper_
.reset(new TooltipControllerTestHelper(
102 GetController(widget_
.get())));
103 generator_
.reset(new ui::test::EventGenerator(GetRootWindow()));
106 virtual void TearDown() OVERRIDE
{
107 #if defined(OS_CHROMEOS)
108 root_window()->RemovePreTargetHandler(controller_
.get());
109 aura::client::SetTooltipClient(root_window(), NULL
);
115 aura::test::AuraTestBase::TearDown();
116 views_delegate_
.reset();
120 aura::Window
* GetWindow() {
121 return widget_
->GetNativeWindow();
124 aura::Window
* GetRootWindow() {
125 return GetWindow()->GetRootWindow();
128 TooltipTestView
* PrepareSecondView() {
129 TooltipTestView
* view2
= new TooltipTestView
;
130 widget_
->GetContentsView()->AddChildView(view2
);
131 view_
->SetBounds(0, 0, 100, 100);
132 view2
->SetBounds(100, 0, 100, 100);
136 scoped_ptr
<views::Widget
> widget_
;
137 TooltipTestView
* view_
;
138 scoped_ptr
<TooltipControllerTestHelper
> helper_
;
139 scoped_ptr
<ui::test::EventGenerator
> generator_
;
142 scoped_ptr
<TooltipController
> controller_
;
144 scoped_ptr
<views::TestViewsDelegate
> views_delegate_
;
147 ui::ScopedOleInitializer ole_initializer_
;
150 DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest
);
153 TEST_F(TooltipControllerTest
, ViewTooltip
) {
154 view_
->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
155 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
156 EXPECT_EQ(NULL
, helper_
->GetTooltipWindow());
157 generator_
->MoveMouseToCenterOf(GetWindow());
159 EXPECT_EQ(GetWindow(), GetRootWindow()->GetEventHandlerForPoint(
160 generator_
->current_location()));
161 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text");
162 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(GetWindow()));
163 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
164 EXPECT_EQ(GetWindow(), helper_
->GetTooltipWindow());
166 // Fire tooltip timer so tooltip becomes visible.
167 helper_
->FireTooltipTimer();
169 EXPECT_TRUE(helper_
->IsTooltipVisible());
170 generator_
->MoveMouseBy(1, 0);
172 EXPECT_TRUE(helper_
->IsTooltipVisible());
173 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(GetWindow()));
174 EXPECT_EQ(expected_tooltip
, helper_
->GetTooltipText());
175 EXPECT_EQ(GetWindow(), helper_
->GetTooltipWindow());
178 TEST_F(TooltipControllerTest
, TooltipsInMultipleViews
) {
179 view_
->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
180 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
181 EXPECT_EQ(NULL
, helper_
->GetTooltipWindow());
184 aura::Window
* window
= GetWindow();
185 aura::Window
* root_window
= GetRootWindow();
187 // Fire tooltip timer so tooltip becomes visible.
188 generator_
->MoveMouseRelativeTo(window
, view_
->bounds().CenterPoint());
189 helper_
->FireTooltipTimer();
190 EXPECT_TRUE(helper_
->IsTooltipVisible());
191 for (int i
= 0; i
< 49; ++i
) {
192 generator_
->MoveMouseBy(1, 0);
193 EXPECT_TRUE(helper_
->IsTooltipVisible());
194 EXPECT_EQ(window
, root_window
->GetEventHandlerForPoint(
195 generator_
->current_location()));
196 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text");
197 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(window
));
198 EXPECT_EQ(expected_tooltip
, helper_
->GetTooltipText());
199 EXPECT_EQ(window
, helper_
->GetTooltipWindow());
201 for (int i
= 0; i
< 49; ++i
) {
202 generator_
->MoveMouseBy(1, 0);
203 EXPECT_FALSE(helper_
->IsTooltipVisible());
204 EXPECT_EQ(window
, root_window
->GetEventHandlerForPoint(
205 generator_
->current_location()));
206 base::string16 expected_tooltip
; // = ""
207 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(window
));
208 EXPECT_EQ(expected_tooltip
, helper_
->GetTooltipText());
209 EXPECT_EQ(window
, helper_
->GetTooltipWindow());
213 TEST_F(TooltipControllerTest
, EnableOrDisableTooltips
) {
214 view_
->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
215 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
216 EXPECT_EQ(NULL
, helper_
->GetTooltipWindow());
218 generator_
->MoveMouseRelativeTo(GetWindow(), view_
->bounds().CenterPoint());
219 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text");
221 // Fire tooltip timer so tooltip becomes visible.
222 helper_
->FireTooltipTimer();
223 EXPECT_TRUE(helper_
->IsTooltipVisible());
225 // Disable tooltips and check again.
226 helper_
->controller()->SetTooltipsEnabled(false);
227 EXPECT_FALSE(helper_
->IsTooltipVisible());
228 helper_
->FireTooltipTimer();
229 EXPECT_FALSE(helper_
->IsTooltipVisible());
231 // Enable tooltips back and check again.
232 helper_
->controller()->SetTooltipsEnabled(true);
233 EXPECT_FALSE(helper_
->IsTooltipVisible());
234 helper_
->FireTooltipTimer();
235 EXPECT_TRUE(helper_
->IsTooltipVisible());
238 // Verifies tooltip isn't shown if tooltip text consists entirely of whitespace.
239 TEST_F(TooltipControllerTest
, DontShowEmptyTooltips
) {
240 view_
->set_tooltip_text(ASCIIToUTF16(" "));
241 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
242 EXPECT_EQ(NULL
, helper_
->GetTooltipWindow());
244 generator_
->MoveMouseRelativeTo(GetWindow(), view_
->bounds().CenterPoint());
246 helper_
->FireTooltipTimer();
247 EXPECT_FALSE(helper_
->IsTooltipVisible());
250 TEST_F(TooltipControllerTest
, TooltipHidesOnKeyPressAndStaysHiddenUntilChange
) {
251 view_
->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 1"));
252 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
253 EXPECT_EQ(NULL
, helper_
->GetTooltipWindow());
255 TooltipTestView
* view2
= PrepareSecondView();
256 view2
->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 2"));
258 aura::Window
* window
= GetWindow();
260 // Fire tooltip timer so tooltip becomes visible.
261 generator_
->MoveMouseRelativeTo(window
, view_
->bounds().CenterPoint());
262 helper_
->FireTooltipTimer();
263 EXPECT_TRUE(helper_
->IsTooltipVisible());
264 EXPECT_TRUE(helper_
->IsTooltipShownTimerRunning());
266 generator_
->PressKey(ui::VKEY_1
, 0);
267 EXPECT_FALSE(helper_
->IsTooltipVisible());
268 EXPECT_FALSE(helper_
->IsTooltipTimerRunning());
269 EXPECT_FALSE(helper_
->IsTooltipShownTimerRunning());
271 // Moving the mouse inside |view1| should not change the state of the tooltip
273 for (int i
= 0; i
< 49; i
++) {
274 generator_
->MoveMouseBy(1, 0);
275 EXPECT_FALSE(helper_
->IsTooltipVisible());
276 EXPECT_FALSE(helper_
->IsTooltipTimerRunning());
277 EXPECT_FALSE(helper_
->IsTooltipShownTimerRunning());
279 GetRootWindow()->GetEventHandlerForPoint(
280 generator_
->current_location()));
281 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text for view 1");
282 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(window
));
283 EXPECT_EQ(expected_tooltip
, helper_
->GetTooltipText());
284 EXPECT_EQ(window
, helper_
->GetTooltipWindow());
287 // Now we move the mouse on to |view2|. It should re-start the tooltip timer.
288 generator_
->MoveMouseBy(1, 0);
289 EXPECT_TRUE(helper_
->IsTooltipTimerRunning());
290 helper_
->FireTooltipTimer();
291 EXPECT_TRUE(helper_
->IsTooltipVisible());
292 EXPECT_TRUE(helper_
->IsTooltipShownTimerRunning());
293 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text for view 2");
294 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(window
));
295 EXPECT_EQ(expected_tooltip
, helper_
->GetTooltipText());
296 EXPECT_EQ(window
, helper_
->GetTooltipWindow());
299 TEST_F(TooltipControllerTest
, TooltipHidesOnTimeoutAndStaysHiddenUntilChange
) {
300 view_
->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 1"));
301 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
302 EXPECT_EQ(NULL
, helper_
->GetTooltipWindow());
304 TooltipTestView
* view2
= PrepareSecondView();
305 view2
->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 2"));
307 aura::Window
* window
= GetWindow();
309 // Fire tooltip timer so tooltip becomes visible.
310 generator_
->MoveMouseRelativeTo(window
, view_
->bounds().CenterPoint());
311 helper_
->FireTooltipTimer();
312 EXPECT_TRUE(helper_
->IsTooltipVisible());
313 EXPECT_TRUE(helper_
->IsTooltipShownTimerRunning());
315 helper_
->FireTooltipShownTimer();
316 EXPECT_FALSE(helper_
->IsTooltipVisible());
317 EXPECT_FALSE(helper_
->IsTooltipTimerRunning());
318 EXPECT_FALSE(helper_
->IsTooltipShownTimerRunning());
320 // Moving the mouse inside |view1| should not change the state of the tooltip
322 for (int i
= 0; i
< 49; ++i
) {
323 generator_
->MoveMouseBy(1, 0);
324 EXPECT_FALSE(helper_
->IsTooltipVisible());
325 EXPECT_FALSE(helper_
->IsTooltipTimerRunning());
326 EXPECT_FALSE(helper_
->IsTooltipShownTimerRunning());
327 EXPECT_EQ(window
, GetRootWindow()->GetEventHandlerForPoint(
328 generator_
->current_location()));
329 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text for view 1");
330 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(window
));
331 EXPECT_EQ(expected_tooltip
, helper_
->GetTooltipText());
332 EXPECT_EQ(window
, helper_
->GetTooltipWindow());
335 // Now we move the mouse on to |view2|. It should re-start the tooltip timer.
336 generator_
->MoveMouseBy(1, 0);
337 EXPECT_TRUE(helper_
->IsTooltipTimerRunning());
338 helper_
->FireTooltipTimer();
339 EXPECT_TRUE(helper_
->IsTooltipVisible());
340 EXPECT_TRUE(helper_
->IsTooltipShownTimerRunning());
341 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text for view 2");
342 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(window
));
343 EXPECT_EQ(expected_tooltip
, helper_
->GetTooltipText());
344 EXPECT_EQ(window
, helper_
->GetTooltipWindow());
347 // Verifies a mouse exit event hides the tooltips.
348 TEST_F(TooltipControllerTest
, HideOnExit
) {
349 view_
->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
350 generator_
->MoveMouseToCenterOf(GetWindow());
351 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text");
352 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(GetWindow()));
353 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
354 EXPECT_EQ(GetWindow(), helper_
->GetTooltipWindow());
356 // Fire tooltip timer so tooltip becomes visible.
357 helper_
->FireTooltipTimer();
359 EXPECT_TRUE(helper_
->IsTooltipVisible());
360 generator_
->SendMouseExit();
361 EXPECT_FALSE(helper_
->IsTooltipVisible());
364 TEST_F(TooltipControllerTest
, ReshowOnClickAfterEnterExit
) {
366 TooltipTestView
* v1
= new TooltipTestView
;
367 TooltipTestView
* v2
= new TooltipTestView
;
368 view_
->AddChildView(v1
);
369 view_
->AddChildView(v2
);
370 gfx::Rect
view_bounds(view_
->GetLocalBounds());
371 view_bounds
.set_height(view_bounds
.height() / 2);
372 v1
->SetBoundsRect(view_bounds
);
373 view_bounds
.set_y(view_bounds
.height());
374 v2
->SetBoundsRect(view_bounds
);
375 const base::string16
v1_tt(ASCIIToUTF16("v1"));
376 const base::string16
v2_tt(ASCIIToUTF16("v2"));
377 v1
->set_tooltip_text(v1_tt
);
378 v2
->set_tooltip_text(v2_tt
);
380 gfx::Point
v1_point(1, 1);
381 View::ConvertPointToWidget(v1
, &v1_point
);
382 generator_
->MoveMouseRelativeTo(GetWindow(), v1_point
);
384 // Fire tooltip timer so tooltip becomes visible.
385 helper_
->FireTooltipTimer();
386 EXPECT_TRUE(helper_
->IsTooltipVisible());
387 EXPECT_EQ(v1_tt
, helper_
->GetTooltipText());
389 // Press the mouse, move to v2 and back to v1.
390 generator_
->ClickLeftButton();
392 gfx::Point
v2_point(1, 1);
393 View::ConvertPointToWidget(v2
, &v2_point
);
394 generator_
->MoveMouseRelativeTo(GetWindow(), v2_point
);
395 generator_
->MoveMouseRelativeTo(GetWindow(), v1_point
);
397 helper_
->FireTooltipTimer();
398 EXPECT_TRUE(helper_
->IsTooltipVisible());
399 EXPECT_EQ(v1_tt
, helper_
->GetTooltipText());
404 // Returns the index of |window| in its parent's children.
405 int IndexInParent(const aura::Window
* window
) {
406 aura::Window::Windows::const_iterator i
=
407 std::find(window
->parent()->children().begin(),
408 window
->parent()->children().end(),
410 return i
== window
->parent()->children().end() ? -1 :
411 static_cast<int>(i
- window
->parent()->children().begin());
414 class TestScreenPositionClient
: public aura::client::ScreenPositionClient
{
416 TestScreenPositionClient() {}
417 virtual ~TestScreenPositionClient() {}
419 // ScreenPositionClient overrides:
420 virtual void ConvertPointToScreen(const aura::Window
* window
,
421 gfx::Point
* point
) OVERRIDE
{
423 virtual void ConvertPointFromScreen(const aura::Window
* window
,
424 gfx::Point
* point
) OVERRIDE
{
426 virtual void ConvertHostPointToScreen(aura::Window
* root_gwindow
,
427 gfx::Point
* point
) OVERRIDE
{
430 virtual void SetBounds(aura::Window
* window
,
431 const gfx::Rect
& bounds
,
432 const gfx::Display
& display
) OVERRIDE
{
433 window
->SetBounds(bounds
);
437 DISALLOW_COPY_AND_ASSIGN(TestScreenPositionClient
);
442 class TooltipControllerCaptureTest
: public TooltipControllerTest
{
444 TooltipControllerCaptureTest() {}
445 virtual ~TooltipControllerCaptureTest() {}
447 virtual void SetUp() OVERRIDE
{
448 TooltipControllerTest::SetUp();
449 aura::client::SetScreenPositionClient(GetRootWindow(),
450 &screen_position_client_
);
451 #if !defined(OS_CHROMEOS)
452 desktop_screen_
.reset(CreateDesktopScreen());
453 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE
,
454 desktop_screen_
.get());
458 virtual void TearDown() OVERRIDE
{
459 #if !defined(OS_CHROMEOS)
460 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE
, test_screen());
461 desktop_screen_
.reset();
463 aura::client::SetScreenPositionClient(GetRootWindow(), NULL
);
464 TooltipControllerTest::TearDown();
468 TestScreenPositionClient screen_position_client_
;
469 scoped_ptr
<gfx::Screen
> desktop_screen_
;
471 DISALLOW_COPY_AND_ASSIGN(TooltipControllerCaptureTest
);
474 // Verifies when capture is released the TooltipController resets state.
475 // Flaky on all builders. http://crbug.com/388268
476 TEST_F(TooltipControllerCaptureTest
, DISABLED_CloseOnCaptureLost
) {
477 view_
->GetWidget()->SetCapture(view_
);
478 RunAllPendingInMessageLoop();
479 view_
->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
480 generator_
->MoveMouseToCenterOf(GetWindow());
481 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text");
482 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(GetWindow()));
483 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
484 EXPECT_EQ(GetWindow(), helper_
->GetTooltipWindow());
486 // Fire tooltip timer so tooltip becomes visible.
487 helper_
->FireTooltipTimer();
489 EXPECT_TRUE(helper_
->IsTooltipVisible());
490 view_
->GetWidget()->ReleaseCapture();
491 EXPECT_FALSE(helper_
->IsTooltipVisible());
492 EXPECT_TRUE(helper_
->GetTooltipWindow() == NULL
);
495 // Disabled on linux as DesktopScreenX11::GetWindowAtScreenPoint() doesn't
497 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
498 #define MAYBE_Capture DISABLED_Capture
500 #define MAYBE_Capture Capture
502 // Verifies the correct window is found for tooltips when there is a capture.
503 TEST_F(TooltipControllerCaptureTest
, MAYBE_Capture
) {
504 const base::string16
tooltip_text(ASCIIToUTF16("1"));
505 const base::string16
tooltip_text2(ASCIIToUTF16("2"));
507 widget_
->SetBounds(gfx::Rect(0, 0, 200, 200));
508 view_
->set_tooltip_text(tooltip_text
);
510 scoped_ptr
<views::Widget
> widget2(CreateWidget(root_window()));
511 widget2
->SetContentsView(new View
);
512 TooltipTestView
* view2
= new TooltipTestView
;
513 widget2
->GetContentsView()->AddChildView(view2
);
514 view2
->set_tooltip_text(tooltip_text2
);
515 widget2
->SetBounds(gfx::Rect(0, 0, 200, 200));
516 view2
->SetBoundsRect(widget2
->GetContentsView()->GetLocalBounds());
518 widget_
->SetCapture(view_
);
519 EXPECT_TRUE(widget_
->HasCapture());
521 EXPECT_GE(IndexInParent(widget2
->GetNativeWindow()),
522 IndexInParent(widget_
->GetNativeWindow()));
524 generator_
->MoveMouseRelativeTo(widget_
->GetNativeWindow(),
525 view_
->bounds().CenterPoint());
527 EXPECT_TRUE(helper_
->IsTooltipTimerRunning());
528 helper_
->FireTooltipTimer();
529 // Even though the mouse is over a window with a tooltip it shouldn't be
530 // picked up because the windows don't have the same value for
531 // |TooltipManager::kGroupingPropertyKey|.
532 EXPECT_TRUE(helper_
->GetTooltipText().empty());
534 // Now make both the windows have same transient value for
535 // kGroupingPropertyKey. In this case the tooltip should be picked up from
536 // |widget2| (because the mouse is over it).
537 const int grouping_key
= 1;
538 widget_
->SetNativeWindowProperty(TooltipManager::kGroupingPropertyKey
,
539 reinterpret_cast<void*>(grouping_key
));
540 widget2
->SetNativeWindowProperty(TooltipManager::kGroupingPropertyKey
,
541 reinterpret_cast<void*>(grouping_key
));
542 generator_
->MoveMouseBy(1, 10);
543 EXPECT_TRUE(helper_
->IsTooltipTimerRunning());
544 helper_
->FireTooltipTimer();
545 EXPECT_EQ(tooltip_text2
, helper_
->GetTooltipText());
552 class TestTooltip
: public Tooltip
{
554 TestTooltip() : is_visible_(false) {}
555 virtual ~TestTooltip() {}
557 const base::string16
& tooltip_text() const { return tooltip_text_
; }
560 virtual void SetText(aura::Window
* window
,
561 const base::string16
& tooltip_text
,
562 const gfx::Point
& location
) OVERRIDE
{
563 tooltip_text_
= tooltip_text
;
564 location_
= location
;
566 virtual void Show() OVERRIDE
{
569 virtual void Hide() OVERRIDE
{
572 virtual bool IsVisible() OVERRIDE
{
575 const gfx::Point
& location() { return location_
; }
579 base::string16 tooltip_text_
;
580 gfx::Point location_
;
582 DISALLOW_COPY_AND_ASSIGN(TestTooltip
);
587 // Use for tests that don't depend upon views.
588 class TooltipControllerTest2
: public aura::test::AuraTestBase
{
590 TooltipControllerTest2() : test_tooltip_(new TestTooltip
) {}
591 virtual ~TooltipControllerTest2() {}
593 virtual void SetUp() OVERRIDE
{
594 wm_state_
.reset(new wm::WMState
);
595 aura::test::AuraTestBase::SetUp();
596 new wm::DefaultActivationClient(root_window());
597 controller_
.reset(new TooltipController(
598 scoped_ptr
<corewm::Tooltip
>(test_tooltip_
)));
599 root_window()->AddPreTargetHandler(controller_
.get());
600 SetTooltipClient(root_window(), controller_
.get());
601 helper_
.reset(new TooltipControllerTestHelper(controller_
.get()));
602 generator_
.reset(new ui::test::EventGenerator(root_window()));
605 virtual void TearDown() OVERRIDE
{
606 root_window()->RemovePreTargetHandler(controller_
.get());
607 aura::client::SetTooltipClient(root_window(), NULL
);
611 aura::test::AuraTestBase::TearDown();
616 // Owned by |controller_|.
617 TestTooltip
* test_tooltip_
;
618 scoped_ptr
<TooltipControllerTestHelper
> helper_
;
619 scoped_ptr
<ui::test::EventGenerator
> generator_
;
622 scoped_ptr
<TooltipController
> controller_
;
623 scoped_ptr
<wm::WMState
> wm_state_
;
625 DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest2
);
628 TEST_F(TooltipControllerTest2
, VerifyLeadingTrailingWhitespaceStripped
) {
629 aura::test::TestWindowDelegate test_delegate
;
630 scoped_ptr
<aura::Window
> window(
631 CreateNormalWindow(100, root_window(), &test_delegate
));
632 window
->SetBounds(gfx::Rect(0, 0, 300, 300));
633 base::string16
tooltip_text(ASCIIToUTF16(" \nx "));
634 aura::client::SetTooltipText(window
.get(), &tooltip_text
);
635 generator_
->MoveMouseToCenterOf(window
.get());
636 helper_
->FireTooltipTimer();
637 EXPECT_EQ(ASCIIToUTF16("x"), test_tooltip_
->tooltip_text());
640 // Verifies that tooltip is hidden and tooltip window closed upon cancel mode.
641 TEST_F(TooltipControllerTest2
, CloseOnCancelMode
) {
642 aura::test::TestWindowDelegate test_delegate
;
643 scoped_ptr
<aura::Window
> window(
644 CreateNormalWindow(100, root_window(), &test_delegate
));
645 window
->SetBounds(gfx::Rect(0, 0, 300, 300));
646 base::string16
tooltip_text(ASCIIToUTF16("Tooltip Text"));
647 aura::client::SetTooltipText(window
.get(), &tooltip_text
);
648 generator_
->MoveMouseToCenterOf(window
.get());
650 // Fire tooltip timer so tooltip becomes visible.
651 helper_
->FireTooltipTimer();
652 EXPECT_TRUE(helper_
->IsTooltipVisible());
654 // Send OnCancelMode event and verify that tooltip becomes invisible and
655 // the tooltip window is closed.
656 ui::CancelModeEvent event
;
657 helper_
->controller()->OnCancelMode(&event
);
658 EXPECT_FALSE(helper_
->IsTooltipVisible());
659 EXPECT_TRUE(helper_
->GetTooltipWindow() == NULL
);
662 // Use for tests that need both views and a TestTooltip.
663 class TooltipControllerTest3
: public aura::test::AuraTestBase
{
665 TooltipControllerTest3() : test_tooltip_(new TestTooltip
) {}
666 virtual ~TooltipControllerTest3() {}
668 virtual void SetUp() OVERRIDE
{
669 wm_state_
.reset(new wm::WMState
);
670 aura::test::AuraTestBase::SetUp();
671 new wm::DefaultActivationClient(root_window());
673 widget_
.reset(CreateWidget(root_window()));
674 widget_
->SetContentsView(new View
);
675 view_
= new TooltipTestView
;
676 widget_
->GetContentsView()->AddChildView(view_
);
677 view_
->SetBoundsRect(widget_
->GetContentsView()->GetLocalBounds());
679 generator_
.reset(new ui::test::EventGenerator(GetRootWindow()));
680 controller_
.reset(new TooltipController(
681 scoped_ptr
<views::corewm::Tooltip
>(test_tooltip_
)));
682 GetRootWindow()->RemovePreTargetHandler(
683 static_cast<TooltipController
*>(aura::client::GetTooltipClient(
684 widget_
->GetNativeWindow()->GetRootWindow())));
685 GetRootWindow()->AddPreTargetHandler(controller_
.get());
686 helper_
.reset(new TooltipControllerTestHelper(controller_
.get()));
687 SetTooltipClient(GetRootWindow(), controller_
.get());
690 virtual void TearDown() OVERRIDE
{
691 GetRootWindow()->RemovePreTargetHandler(controller_
.get());
692 aura::client::SetTooltipClient(GetRootWindow(), NULL
);
698 aura::test::AuraTestBase::TearDown();
702 aura::Window
* GetWindow() { return widget_
->GetNativeWindow(); }
705 // Owned by |controller_|.
706 TestTooltip
* test_tooltip_
;
707 scoped_ptr
<TooltipControllerTestHelper
> helper_
;
708 scoped_ptr
<ui::test::EventGenerator
> generator_
;
709 scoped_ptr
<views::Widget
> widget_
;
710 TooltipTestView
* view_
;
713 scoped_ptr
<TooltipController
> controller_
;
714 scoped_ptr
<wm::WMState
> wm_state_
;
717 ui::ScopedOleInitializer ole_initializer_
;
720 aura::Window
* GetRootWindow() { return GetWindow()->GetRootWindow(); }
722 DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest3
);
725 TEST_F(TooltipControllerTest3
, TooltipPositionChangesOnTwoViewsWithSameLabel
) {
727 // These two views have the same tooltip text
728 TooltipTestView
* v1
= new TooltipTestView
;
729 TooltipTestView
* v2
= new TooltipTestView
;
730 // v1_1 is a view inside v1 that has an identical tooltip text to that of v1
732 TooltipTestView
* v1_1
= new TooltipTestView
;
733 // v2_1 is a view inside v2 that has an identical tooltip text to that of v1
735 TooltipTestView
* v2_1
= new TooltipTestView
;
736 // v2_2 is a view inside v2 with the tooltip text different from all the
738 TooltipTestView
* v2_2
= new TooltipTestView
;
740 // Setup all the views' relations
741 view_
->AddChildView(v1
);
742 view_
->AddChildView(v2
);
743 v1
->AddChildView(v1_1
);
744 v2
->AddChildView(v2_1
);
745 v2
->AddChildView(v2_2
);
746 const base::string16
reference_string(
747 base::ASCIIToUTF16("Identical Tooltip Text"));
748 const base::string16
alternative_string(
749 base::ASCIIToUTF16("Another Shrubbery"));
750 v1
->set_tooltip_text(reference_string
);
751 v2
->set_tooltip_text(reference_string
);
752 v1_1
->set_tooltip_text(reference_string
);
753 v2_1
->set_tooltip_text(reference_string
);
754 v2_2
->set_tooltip_text(alternative_string
);
757 gfx::Rect
view_bounds(view_
->GetLocalBounds());
758 view_bounds
.set_height(view_bounds
.height() / 2);
759 v1
->SetBoundsRect(view_bounds
);
760 v1_1
->SetBounds(0, 0, 3, 3);
761 view_bounds
.set_y(view_bounds
.height());
762 v2
->SetBoundsRect(view_bounds
);
763 v2_2
->SetBounds(view_bounds
.width() - 3, view_bounds
.height() - 3, 3, 3);
764 v2_1
->SetBounds(0, 0, 3, 3);
766 // Test whether a toolbar appears on v1
767 gfx::Point center
= v1
->bounds().CenterPoint();
768 generator_
->MoveMouseRelativeTo(GetWindow(), center
);
769 helper_
->FireTooltipTimer();
770 EXPECT_TRUE(helper_
->IsTooltipVisible());
771 EXPECT_EQ(reference_string
, helper_
->GetTooltipText());
772 gfx::Point tooltip_bounds1
= test_tooltip_
->location();
774 // Test whether the toolbar changes position on mouse over v2
775 center
= v2
->bounds().CenterPoint();
776 generator_
->MoveMouseRelativeTo(GetWindow(), center
);
777 helper_
->FireTooltipTimer();
778 EXPECT_TRUE(helper_
->IsTooltipVisible());
779 EXPECT_EQ(reference_string
, helper_
->GetTooltipText());
780 gfx::Point tooltip_bounds2
= test_tooltip_
->location();
782 EXPECT_NE(tooltip_bounds1
, gfx::Point());
783 EXPECT_NE(tooltip_bounds2
, gfx::Point());
784 EXPECT_NE(tooltip_bounds1
, tooltip_bounds2
);
786 // Test if the toolbar does not change position on encountering a contained
787 // view with the same tooltip text
788 center
= v2_1
->GetLocalBounds().CenterPoint();
789 views::View::ConvertPointToTarget(v2_1
, view_
, ¢er
);
790 generator_
->MoveMouseRelativeTo(GetWindow(), center
);
791 helper_
->FireTooltipTimer();
792 gfx::Point tooltip_bounds2_1
= test_tooltip_
->location();
794 EXPECT_NE(tooltip_bounds2
, tooltip_bounds2_1
);
795 EXPECT_TRUE(helper_
->IsTooltipVisible());
796 EXPECT_EQ(reference_string
, helper_
->GetTooltipText());
798 // Test if the toolbar changes position on encountering a contained
799 // view with a different tooltip text
800 center
= v2_2
->GetLocalBounds().CenterPoint();
801 views::View::ConvertPointToTarget(v2_2
, view_
, ¢er
);
802 generator_
->MoveMouseRelativeTo(GetWindow(), center
);
803 helper_
->FireTooltipTimer();
804 gfx::Point tooltip_bounds2_2
= test_tooltip_
->location();
806 EXPECT_NE(tooltip_bounds2_1
, tooltip_bounds2_2
);
807 EXPECT_TRUE(helper_
->IsTooltipVisible());
808 EXPECT_EQ(alternative_string
, helper_
->GetTooltipText());
810 // Test if moving from a view that is contained by a larger view, both with
811 // the same tooltip text, does not change tooltip's position.
812 center
= v1_1
->GetLocalBounds().CenterPoint();
813 views::View::ConvertPointToTarget(v1_1
, view_
, ¢er
);
814 generator_
->MoveMouseRelativeTo(GetWindow(), center
);
815 helper_
->FireTooltipTimer();
816 gfx::Point tooltip_bounds1_1
= test_tooltip_
->location();
818 EXPECT_TRUE(helper_
->IsTooltipVisible());
819 EXPECT_EQ(reference_string
, helper_
->GetTooltipText());
821 center
= v1
->bounds().CenterPoint();
822 generator_
->MoveMouseRelativeTo(GetWindow(), center
);
823 helper_
->FireTooltipTimer();
824 tooltip_bounds1
= test_tooltip_
->location();
826 EXPECT_NE(tooltip_bounds1_1
, tooltip_bounds1
);
827 EXPECT_EQ(reference_string
, helper_
->GetTooltipText());
831 } // namespace corewm