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/event_generator.h"
13 #include "ui/aura/test/test_screen.h"
14 #include "ui/aura/test/test_window_delegate.h"
15 #include "ui/aura/window.h"
16 #include "ui/aura/window_event_dispatcher.h"
17 #include "ui/base/resource/resource_bundle.h"
18 #include "ui/gfx/font.h"
19 #include "ui/gfx/point.h"
20 #include "ui/gfx/screen.h"
21 #include "ui/gfx/screen_type_delegate.h"
22 #include "ui/gfx/text_elider.h"
23 #include "ui/views/corewm/tooltip_aura.h"
24 #include "ui/views/corewm/tooltip_controller_test_helper.h"
25 #include "ui/views/test/desktop_test_views_delegate.h"
26 #include "ui/views/test/test_views_delegate.h"
27 #include "ui/views/view.h"
28 #include "ui/views/widget/tooltip_manager.h"
29 #include "ui/views/widget/widget.h"
30 #include "ui/wm/core/default_activation_client.h"
31 #include "ui/wm/core/wm_state.h"
32 #include "ui/wm/public/tooltip_client.h"
33 #include "ui/wm/public/window_types.h"
36 #include "ui/base/win/scoped_ole_initializer.h"
39 #if !defined(OS_CHROMEOS)
40 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
41 #include "ui/views/widget/desktop_aura/desktop_screen.h"
44 using base::ASCIIToUTF16
;
51 views::Widget
* CreateWidget(aura::Window
* root
) {
52 views::Widget
* widget
= new views::Widget
;
53 views::Widget::InitParams params
;
54 params
.type
= views::Widget::InitParams::TYPE_WINDOW_FRAMELESS
;
55 params
.accept_events
= true;
56 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
57 #if defined(OS_CHROMEOS)
60 params
.native_widget
= new DesktopNativeWidgetAura(widget
);
62 params
.bounds
= gfx::Rect(0, 0, 200, 100);
68 TooltipController
* GetController(Widget
* widget
) {
69 return static_cast<TooltipController
*>(
70 aura::client::GetTooltipClient(
71 widget
->GetNativeWindow()->GetRootWindow()));
76 class TooltipControllerTest
: public aura::test::AuraTestBase
{
78 TooltipControllerTest() : view_(NULL
) {}
79 virtual ~TooltipControllerTest() {}
81 virtual void SetUp() OVERRIDE
{
82 #if defined(OS_CHROMEOS)
83 views_delegate_
.reset(new TestViewsDelegate
);
85 views_delegate_
.reset(new DesktopTestViewsDelegate
);
88 aura::test::AuraTestBase::SetUp();
89 new wm::DefaultActivationClient(root_window());
90 #if defined(OS_CHROMEOS)
91 controller_
.reset(new TooltipController(
92 scoped_ptr
<views::corewm::Tooltip
>(
93 new views::corewm::TooltipAura(gfx::SCREEN_TYPE_ALTERNATE
))));
94 root_window()->AddPreTargetHandler(controller_
.get());
95 SetTooltipClient(root_window(), controller_
.get());
97 widget_
.reset(CreateWidget(root_window()));
98 widget_
->SetContentsView(new View
);
99 view_
= new TooltipTestView
;
100 widget_
->GetContentsView()->AddChildView(view_
);
101 view_
->SetBoundsRect(widget_
->GetContentsView()->GetLocalBounds());
102 helper_
.reset(new TooltipControllerTestHelper(
103 GetController(widget_
.get())));
104 generator_
.reset(new aura::test::EventGenerator(GetRootWindow()));
107 virtual void TearDown() OVERRIDE
{
108 #if defined(OS_CHROMEOS)
109 root_window()->RemovePreTargetHandler(controller_
.get());
110 aura::client::SetTooltipClient(root_window(), NULL
);
116 aura::test::AuraTestBase::TearDown();
117 views_delegate_
.reset();
121 aura::Window
* GetWindow() {
122 return widget_
->GetNativeWindow();
125 aura::Window
* GetRootWindow() {
126 return GetWindow()->GetRootWindow();
129 TooltipTestView
* PrepareSecondView() {
130 TooltipTestView
* view2
= new TooltipTestView
;
131 widget_
->GetContentsView()->AddChildView(view2
);
132 view_
->SetBounds(0, 0, 100, 100);
133 view2
->SetBounds(100, 0, 100, 100);
137 scoped_ptr
<views::Widget
> widget_
;
138 TooltipTestView
* view_
;
139 scoped_ptr
<TooltipControllerTestHelper
> helper_
;
140 scoped_ptr
<aura::test::EventGenerator
> generator_
;
143 scoped_ptr
<TooltipController
> controller_
;
145 scoped_ptr
<views::TestViewsDelegate
> views_delegate_
;
148 ui::ScopedOleInitializer ole_initializer_
;
151 DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest
);
154 TEST_F(TooltipControllerTest
, ViewTooltip
) {
155 view_
->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
156 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
157 EXPECT_EQ(NULL
, helper_
->GetTooltipWindow());
158 generator_
->MoveMouseToCenterOf(GetWindow());
160 EXPECT_EQ(GetWindow(), GetRootWindow()->GetEventHandlerForPoint(
161 generator_
->current_location()));
162 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text");
163 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(GetWindow()));
164 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
165 EXPECT_EQ(GetWindow(), helper_
->GetTooltipWindow());
167 // Fire tooltip timer so tooltip becomes visible.
168 helper_
->FireTooltipTimer();
170 EXPECT_TRUE(helper_
->IsTooltipVisible());
171 generator_
->MoveMouseBy(1, 0);
173 EXPECT_TRUE(helper_
->IsTooltipVisible());
174 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(GetWindow()));
175 EXPECT_EQ(expected_tooltip
, helper_
->GetTooltipText());
176 EXPECT_EQ(GetWindow(), helper_
->GetTooltipWindow());
179 TEST_F(TooltipControllerTest
, TooltipsInMultipleViews
) {
180 view_
->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
181 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
182 EXPECT_EQ(NULL
, helper_
->GetTooltipWindow());
185 aura::Window
* window
= GetWindow();
186 aura::Window
* root_window
= GetRootWindow();
188 // Fire tooltip timer so tooltip becomes visible.
189 generator_
->MoveMouseRelativeTo(window
, view_
->bounds().CenterPoint());
190 helper_
->FireTooltipTimer();
191 EXPECT_TRUE(helper_
->IsTooltipVisible());
192 for (int i
= 0; i
< 49; ++i
) {
193 generator_
->MoveMouseBy(1, 0);
194 EXPECT_TRUE(helper_
->IsTooltipVisible());
195 EXPECT_EQ(window
, root_window
->GetEventHandlerForPoint(
196 generator_
->current_location()));
197 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text");
198 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(window
));
199 EXPECT_EQ(expected_tooltip
, helper_
->GetTooltipText());
200 EXPECT_EQ(window
, helper_
->GetTooltipWindow());
202 for (int i
= 0; i
< 49; ++i
) {
203 generator_
->MoveMouseBy(1, 0);
204 EXPECT_FALSE(helper_
->IsTooltipVisible());
205 EXPECT_EQ(window
, root_window
->GetEventHandlerForPoint(
206 generator_
->current_location()));
207 base::string16 expected_tooltip
; // = ""
208 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(window
));
209 EXPECT_EQ(expected_tooltip
, helper_
->GetTooltipText());
210 EXPECT_EQ(window
, helper_
->GetTooltipWindow());
214 TEST_F(TooltipControllerTest
, EnableOrDisableTooltips
) {
215 view_
->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
216 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
217 EXPECT_EQ(NULL
, helper_
->GetTooltipWindow());
219 generator_
->MoveMouseRelativeTo(GetWindow(), view_
->bounds().CenterPoint());
220 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text");
222 // Fire tooltip timer so tooltip becomes visible.
223 helper_
->FireTooltipTimer();
224 EXPECT_TRUE(helper_
->IsTooltipVisible());
226 // Disable tooltips and check again.
227 helper_
->controller()->SetTooltipsEnabled(false);
228 EXPECT_FALSE(helper_
->IsTooltipVisible());
229 helper_
->FireTooltipTimer();
230 EXPECT_FALSE(helper_
->IsTooltipVisible());
232 // Enable tooltips back and check again.
233 helper_
->controller()->SetTooltipsEnabled(true);
234 EXPECT_FALSE(helper_
->IsTooltipVisible());
235 helper_
->FireTooltipTimer();
236 EXPECT_TRUE(helper_
->IsTooltipVisible());
239 // Verifies tooltip isn't shown if tooltip text consists entirely of whitespace.
240 TEST_F(TooltipControllerTest
, DontShowEmptyTooltips
) {
241 view_
->set_tooltip_text(ASCIIToUTF16(" "));
242 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
243 EXPECT_EQ(NULL
, helper_
->GetTooltipWindow());
245 generator_
->MoveMouseRelativeTo(GetWindow(), view_
->bounds().CenterPoint());
247 helper_
->FireTooltipTimer();
248 EXPECT_FALSE(helper_
->IsTooltipVisible());
251 TEST_F(TooltipControllerTest
, TooltipHidesOnKeyPressAndStaysHiddenUntilChange
) {
252 view_
->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 1"));
253 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
254 EXPECT_EQ(NULL
, helper_
->GetTooltipWindow());
256 TooltipTestView
* view2
= PrepareSecondView();
257 view2
->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 2"));
259 aura::Window
* window
= GetWindow();
261 // Fire tooltip timer so tooltip becomes visible.
262 generator_
->MoveMouseRelativeTo(window
, view_
->bounds().CenterPoint());
263 helper_
->FireTooltipTimer();
264 EXPECT_TRUE(helper_
->IsTooltipVisible());
265 EXPECT_TRUE(helper_
->IsTooltipShownTimerRunning());
267 generator_
->PressKey(ui::VKEY_1
, 0);
268 EXPECT_FALSE(helper_
->IsTooltipVisible());
269 EXPECT_FALSE(helper_
->IsTooltipTimerRunning());
270 EXPECT_FALSE(helper_
->IsTooltipShownTimerRunning());
272 // Moving the mouse inside |view1| should not change the state of the tooltip
274 for (int i
= 0; i
< 49; i
++) {
275 generator_
->MoveMouseBy(1, 0);
276 EXPECT_FALSE(helper_
->IsTooltipVisible());
277 EXPECT_FALSE(helper_
->IsTooltipTimerRunning());
278 EXPECT_FALSE(helper_
->IsTooltipShownTimerRunning());
280 GetRootWindow()->GetEventHandlerForPoint(
281 generator_
->current_location()));
282 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text for view 1");
283 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(window
));
284 EXPECT_EQ(expected_tooltip
, helper_
->GetTooltipText());
285 EXPECT_EQ(window
, helper_
->GetTooltipWindow());
288 // Now we move the mouse on to |view2|. It should re-start the tooltip timer.
289 generator_
->MoveMouseBy(1, 0);
290 EXPECT_TRUE(helper_
->IsTooltipTimerRunning());
291 helper_
->FireTooltipTimer();
292 EXPECT_TRUE(helper_
->IsTooltipVisible());
293 EXPECT_TRUE(helper_
->IsTooltipShownTimerRunning());
294 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text for view 2");
295 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(window
));
296 EXPECT_EQ(expected_tooltip
, helper_
->GetTooltipText());
297 EXPECT_EQ(window
, helper_
->GetTooltipWindow());
300 TEST_F(TooltipControllerTest
, TooltipHidesOnTimeoutAndStaysHiddenUntilChange
) {
301 view_
->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 1"));
302 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
303 EXPECT_EQ(NULL
, helper_
->GetTooltipWindow());
305 TooltipTestView
* view2
= PrepareSecondView();
306 view2
->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 2"));
308 aura::Window
* window
= GetWindow();
310 // Fire tooltip timer so tooltip becomes visible.
311 generator_
->MoveMouseRelativeTo(window
, view_
->bounds().CenterPoint());
312 helper_
->FireTooltipTimer();
313 EXPECT_TRUE(helper_
->IsTooltipVisible());
314 EXPECT_TRUE(helper_
->IsTooltipShownTimerRunning());
316 helper_
->FireTooltipShownTimer();
317 EXPECT_FALSE(helper_
->IsTooltipVisible());
318 EXPECT_FALSE(helper_
->IsTooltipTimerRunning());
319 EXPECT_FALSE(helper_
->IsTooltipShownTimerRunning());
321 // Moving the mouse inside |view1| should not change the state of the tooltip
323 for (int i
= 0; i
< 49; ++i
) {
324 generator_
->MoveMouseBy(1, 0);
325 EXPECT_FALSE(helper_
->IsTooltipVisible());
326 EXPECT_FALSE(helper_
->IsTooltipTimerRunning());
327 EXPECT_FALSE(helper_
->IsTooltipShownTimerRunning());
328 EXPECT_EQ(window
, GetRootWindow()->GetEventHandlerForPoint(
329 generator_
->current_location()));
330 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text for view 1");
331 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(window
));
332 EXPECT_EQ(expected_tooltip
, helper_
->GetTooltipText());
333 EXPECT_EQ(window
, helper_
->GetTooltipWindow());
336 // Now we move the mouse on to |view2|. It should re-start the tooltip timer.
337 generator_
->MoveMouseBy(1, 0);
338 EXPECT_TRUE(helper_
->IsTooltipTimerRunning());
339 helper_
->FireTooltipTimer();
340 EXPECT_TRUE(helper_
->IsTooltipVisible());
341 EXPECT_TRUE(helper_
->IsTooltipShownTimerRunning());
342 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text for view 2");
343 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(window
));
344 EXPECT_EQ(expected_tooltip
, helper_
->GetTooltipText());
345 EXPECT_EQ(window
, helper_
->GetTooltipWindow());
348 // Verifies a mouse exit event hides the tooltips.
349 TEST_F(TooltipControllerTest
, HideOnExit
) {
350 view_
->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
351 generator_
->MoveMouseToCenterOf(GetWindow());
352 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text");
353 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(GetWindow()));
354 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
355 EXPECT_EQ(GetWindow(), helper_
->GetTooltipWindow());
357 // Fire tooltip timer so tooltip becomes visible.
358 helper_
->FireTooltipTimer();
360 EXPECT_TRUE(helper_
->IsTooltipVisible());
361 generator_
->SendMouseExit();
362 EXPECT_FALSE(helper_
->IsTooltipVisible());
365 TEST_F(TooltipControllerTest
, ReshowOnClickAfterEnterExit
) {
367 TooltipTestView
* v1
= new TooltipTestView
;
368 TooltipTestView
* v2
= new TooltipTestView
;
369 view_
->AddChildView(v1
);
370 view_
->AddChildView(v2
);
371 gfx::Rect
view_bounds(view_
->GetLocalBounds());
372 view_bounds
.set_height(view_bounds
.height() / 2);
373 v1
->SetBoundsRect(view_bounds
);
374 view_bounds
.set_y(view_bounds
.height());
375 v2
->SetBoundsRect(view_bounds
);
376 const base::string16
v1_tt(ASCIIToUTF16("v1"));
377 const base::string16
v2_tt(ASCIIToUTF16("v2"));
378 v1
->set_tooltip_text(v1_tt
);
379 v2
->set_tooltip_text(v2_tt
);
381 gfx::Point
v1_point(1, 1);
382 View::ConvertPointToWidget(v1
, &v1_point
);
383 generator_
->MoveMouseRelativeTo(GetWindow(), v1_point
);
385 // Fire tooltip timer so tooltip becomes visible.
386 helper_
->FireTooltipTimer();
387 EXPECT_TRUE(helper_
->IsTooltipVisible());
388 EXPECT_EQ(v1_tt
, helper_
->GetTooltipText());
390 // Press the mouse, move to v2 and back to v1.
391 generator_
->ClickLeftButton();
393 gfx::Point
v2_point(1, 1);
394 View::ConvertPointToWidget(v2
, &v2_point
);
395 generator_
->MoveMouseRelativeTo(GetWindow(), v2_point
);
396 generator_
->MoveMouseRelativeTo(GetWindow(), v1_point
);
398 helper_
->FireTooltipTimer();
399 EXPECT_TRUE(helper_
->IsTooltipVisible());
400 EXPECT_EQ(v1_tt
, helper_
->GetTooltipText());
405 // Returns the index of |window| in its parent's children.
406 int IndexInParent(const aura::Window
* window
) {
407 aura::Window::Windows::const_iterator i
=
408 std::find(window
->parent()->children().begin(),
409 window
->parent()->children().end(),
411 return i
== window
->parent()->children().end() ? -1 :
412 static_cast<int>(i
- window
->parent()->children().begin());
415 class TestScreenPositionClient
: public aura::client::ScreenPositionClient
{
417 TestScreenPositionClient() {}
418 virtual ~TestScreenPositionClient() {}
420 // ScreenPositionClient overrides:
421 virtual void ConvertPointToScreen(const aura::Window
* window
,
422 gfx::Point
* point
) OVERRIDE
{
424 virtual void ConvertPointFromScreen(const aura::Window
* window
,
425 gfx::Point
* point
) OVERRIDE
{
427 virtual void ConvertHostPointToScreen(aura::Window
* root_gwindow
,
428 gfx::Point
* point
) OVERRIDE
{
431 virtual void SetBounds(aura::Window
* window
,
432 const gfx::Rect
& bounds
,
433 const gfx::Display
& display
) OVERRIDE
{
434 window
->SetBounds(bounds
);
438 DISALLOW_COPY_AND_ASSIGN(TestScreenPositionClient
);
443 class TooltipControllerCaptureTest
: public TooltipControllerTest
{
445 TooltipControllerCaptureTest() {}
446 virtual ~TooltipControllerCaptureTest() {}
448 virtual void SetUp() OVERRIDE
{
449 TooltipControllerTest::SetUp();
450 aura::client::SetScreenPositionClient(GetRootWindow(),
451 &screen_position_client_
);
452 #if !defined(OS_CHROMEOS)
453 desktop_screen_
.reset(CreateDesktopScreen());
454 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE
,
455 desktop_screen_
.get());
459 virtual void TearDown() OVERRIDE
{
460 #if !defined(OS_CHROMEOS)
461 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE
, test_screen());
462 desktop_screen_
.reset();
464 aura::client::SetScreenPositionClient(GetRootWindow(), NULL
);
465 TooltipControllerTest::TearDown();
469 TestScreenPositionClient screen_position_client_
;
470 scoped_ptr
<gfx::Screen
> desktop_screen_
;
472 DISALLOW_COPY_AND_ASSIGN(TooltipControllerCaptureTest
);
475 // Verifies when capture is released the TooltipController resets state.
476 // Flaky on all builders. http://crbug.com/388268
477 TEST_F(TooltipControllerCaptureTest
, DISABLED_CloseOnCaptureLost
) {
478 view_
->GetWidget()->SetCapture(view_
);
479 RunAllPendingInMessageLoop();
480 view_
->set_tooltip_text(ASCIIToUTF16("Tooltip Text"));
481 generator_
->MoveMouseToCenterOf(GetWindow());
482 base::string16 expected_tooltip
= ASCIIToUTF16("Tooltip Text");
483 EXPECT_EQ(expected_tooltip
, aura::client::GetTooltipText(GetWindow()));
484 EXPECT_EQ(base::string16(), helper_
->GetTooltipText());
485 EXPECT_EQ(GetWindow(), helper_
->GetTooltipWindow());
487 // Fire tooltip timer so tooltip becomes visible.
488 helper_
->FireTooltipTimer();
490 EXPECT_TRUE(helper_
->IsTooltipVisible());
491 view_
->GetWidget()->ReleaseCapture();
492 EXPECT_FALSE(helper_
->IsTooltipVisible());
493 EXPECT_TRUE(helper_
->GetTooltipWindow() == NULL
);
496 // Disabled on linux as DesktopScreenX11::GetWindowAtScreenPoint() doesn't
498 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
499 #define MAYBE_Capture DISABLED_Capture
501 #define MAYBE_Capture Capture
503 // Verifies the correct window is found for tooltips when there is a capture.
504 TEST_F(TooltipControllerCaptureTest
, MAYBE_Capture
) {
505 const base::string16
tooltip_text(ASCIIToUTF16("1"));
506 const base::string16
tooltip_text2(ASCIIToUTF16("2"));
508 widget_
->SetBounds(gfx::Rect(0, 0, 200, 200));
509 view_
->set_tooltip_text(tooltip_text
);
511 scoped_ptr
<views::Widget
> widget2(CreateWidget(root_window()));
512 widget2
->SetContentsView(new View
);
513 TooltipTestView
* view2
= new TooltipTestView
;
514 widget2
->GetContentsView()->AddChildView(view2
);
515 view2
->set_tooltip_text(tooltip_text2
);
516 widget2
->SetBounds(gfx::Rect(0, 0, 200, 200));
517 view2
->SetBoundsRect(widget2
->GetContentsView()->GetLocalBounds());
519 widget_
->SetCapture(view_
);
520 EXPECT_TRUE(widget_
->HasCapture());
522 EXPECT_GE(IndexInParent(widget2
->GetNativeWindow()),
523 IndexInParent(widget_
->GetNativeWindow()));
525 generator_
->MoveMouseRelativeTo(widget_
->GetNativeWindow(),
526 view_
->bounds().CenterPoint());
528 EXPECT_TRUE(helper_
->IsTooltipTimerRunning());
529 helper_
->FireTooltipTimer();
530 // Even though the mouse is over a window with a tooltip it shouldn't be
531 // picked up because the windows don't have the same value for
532 // |TooltipManager::kGroupingPropertyKey|.
533 EXPECT_TRUE(helper_
->GetTooltipText().empty());
535 // Now make both the windows have same transient value for
536 // kGroupingPropertyKey. In this case the tooltip should be picked up from
537 // |widget2| (because the mouse is over it).
538 const int grouping_key
= 1;
539 widget_
->SetNativeWindowProperty(TooltipManager::kGroupingPropertyKey
,
540 reinterpret_cast<void*>(grouping_key
));
541 widget2
->SetNativeWindowProperty(TooltipManager::kGroupingPropertyKey
,
542 reinterpret_cast<void*>(grouping_key
));
543 generator_
->MoveMouseBy(1, 10);
544 EXPECT_TRUE(helper_
->IsTooltipTimerRunning());
545 helper_
->FireTooltipTimer();
546 EXPECT_EQ(tooltip_text2
, helper_
->GetTooltipText());
553 class TestTooltip
: public Tooltip
{
555 TestTooltip() : is_visible_(false) {}
556 virtual ~TestTooltip() {}
558 const base::string16
& tooltip_text() const { return tooltip_text_
; }
561 virtual void SetText(aura::Window
* window
,
562 const base::string16
& tooltip_text
,
563 const gfx::Point
& location
) OVERRIDE
{
564 tooltip_text_
= tooltip_text
;
565 location_
= location
;
567 virtual void Show() OVERRIDE
{
570 virtual void Hide() OVERRIDE
{
573 virtual bool IsVisible() OVERRIDE
{
576 const gfx::Point
& location() { return location_
; }
580 base::string16 tooltip_text_
;
581 gfx::Point location_
;
583 DISALLOW_COPY_AND_ASSIGN(TestTooltip
);
588 // Use for tests that don't depend upon views.
589 class TooltipControllerTest2
: public aura::test::AuraTestBase
{
591 TooltipControllerTest2() : test_tooltip_(new TestTooltip
) {}
592 virtual ~TooltipControllerTest2() {}
594 virtual void SetUp() OVERRIDE
{
595 wm_state_
.reset(new wm::WMState
);
596 aura::test::AuraTestBase::SetUp();
597 new wm::DefaultActivationClient(root_window());
598 controller_
.reset(new TooltipController(
599 scoped_ptr
<corewm::Tooltip
>(test_tooltip_
)));
600 root_window()->AddPreTargetHandler(controller_
.get());
601 SetTooltipClient(root_window(), controller_
.get());
602 helper_
.reset(new TooltipControllerTestHelper(controller_
.get()));
603 generator_
.reset(new aura::test::EventGenerator(root_window()));
606 virtual void TearDown() OVERRIDE
{
607 root_window()->RemovePreTargetHandler(controller_
.get());
608 aura::client::SetTooltipClient(root_window(), NULL
);
612 aura::test::AuraTestBase::TearDown();
617 // Owned by |controller_|.
618 TestTooltip
* test_tooltip_
;
619 scoped_ptr
<TooltipControllerTestHelper
> helper_
;
620 scoped_ptr
<aura::test::EventGenerator
> generator_
;
623 scoped_ptr
<TooltipController
> controller_
;
624 scoped_ptr
<wm::WMState
> wm_state_
;
626 DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest2
);
629 TEST_F(TooltipControllerTest2
, VerifyLeadingTrailingWhitespaceStripped
) {
630 aura::test::TestWindowDelegate test_delegate
;
631 scoped_ptr
<aura::Window
> window(
632 CreateNormalWindow(100, root_window(), &test_delegate
));
633 window
->SetBounds(gfx::Rect(0, 0, 300, 300));
634 base::string16
tooltip_text(ASCIIToUTF16(" \nx "));
635 aura::client::SetTooltipText(window
.get(), &tooltip_text
);
636 generator_
->MoveMouseToCenterOf(window
.get());
637 helper_
->FireTooltipTimer();
638 EXPECT_EQ(ASCIIToUTF16("x"), test_tooltip_
->tooltip_text());
641 // Verifies that tooltip is hidden and tooltip window closed upon cancel mode.
642 TEST_F(TooltipControllerTest2
, CloseOnCancelMode
) {
643 aura::test::TestWindowDelegate test_delegate
;
644 scoped_ptr
<aura::Window
> window(
645 CreateNormalWindow(100, root_window(), &test_delegate
));
646 window
->SetBounds(gfx::Rect(0, 0, 300, 300));
647 base::string16
tooltip_text(ASCIIToUTF16("Tooltip Text"));
648 aura::client::SetTooltipText(window
.get(), &tooltip_text
);
649 generator_
->MoveMouseToCenterOf(window
.get());
651 // Fire tooltip timer so tooltip becomes visible.
652 helper_
->FireTooltipTimer();
653 EXPECT_TRUE(helper_
->IsTooltipVisible());
655 // Send OnCancelMode event and verify that tooltip becomes invisible and
656 // the tooltip window is closed.
657 ui::CancelModeEvent event
;
658 helper_
->controller()->OnCancelMode(&event
);
659 EXPECT_FALSE(helper_
->IsTooltipVisible());
660 EXPECT_TRUE(helper_
->GetTooltipWindow() == NULL
);
663 // Use for tests that need both views and a TestTooltip.
664 class TooltipControllerTest3
: public aura::test::AuraTestBase
{
666 TooltipControllerTest3() : test_tooltip_(new TestTooltip
) {}
667 virtual ~TooltipControllerTest3() {}
669 virtual void SetUp() OVERRIDE
{
670 wm_state_
.reset(new wm::WMState
);
671 aura::test::AuraTestBase::SetUp();
672 new wm::DefaultActivationClient(root_window());
674 widget_
.reset(CreateWidget(root_window()));
675 widget_
->SetContentsView(new View
);
676 view_
= new TooltipTestView
;
677 widget_
->GetContentsView()->AddChildView(view_
);
678 view_
->SetBoundsRect(widget_
->GetContentsView()->GetLocalBounds());
680 generator_
.reset(new aura::test::EventGenerator(GetRootWindow()));
681 controller_
.reset(new TooltipController(
682 scoped_ptr
<views::corewm::Tooltip
>(test_tooltip_
)));
683 GetRootWindow()->RemovePreTargetHandler(
684 static_cast<TooltipController
*>(aura::client::GetTooltipClient(
685 widget_
->GetNativeWindow()->GetRootWindow())));
686 GetRootWindow()->AddPreTargetHandler(controller_
.get());
687 helper_
.reset(new TooltipControllerTestHelper(controller_
.get()));
688 SetTooltipClient(GetRootWindow(), controller_
.get());
691 virtual void TearDown() OVERRIDE
{
692 GetRootWindow()->RemovePreTargetHandler(controller_
.get());
693 aura::client::SetTooltipClient(GetRootWindow(), NULL
);
699 aura::test::AuraTestBase::TearDown();
703 aura::Window
* GetWindow() { return widget_
->GetNativeWindow(); }
706 // Owned by |controller_|.
707 TestTooltip
* test_tooltip_
;
708 scoped_ptr
<TooltipControllerTestHelper
> helper_
;
709 scoped_ptr
<aura::test::EventGenerator
> generator_
;
710 scoped_ptr
<views::Widget
> widget_
;
711 TooltipTestView
* view_
;
714 scoped_ptr
<TooltipController
> controller_
;
715 scoped_ptr
<wm::WMState
> wm_state_
;
718 ui::ScopedOleInitializer ole_initializer_
;
721 aura::Window
* GetRootWindow() { return GetWindow()->GetRootWindow(); }
723 DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest3
);
726 TEST_F(TooltipControllerTest3
, TooltipPositionChangesOnTwoViewsWithSameLabel
) {
728 // These two views have the same tooltip text
729 TooltipTestView
* v1
= new TooltipTestView
;
730 TooltipTestView
* v2
= new TooltipTestView
;
731 // v1_1 is a view inside v1 that has an identical tooltip text to that of v1
733 TooltipTestView
* v1_1
= new TooltipTestView
;
734 // v2_1 is a view inside v2 that has an identical tooltip text to that of v1
736 TooltipTestView
* v2_1
= new TooltipTestView
;
737 // v2_2 is a view inside v2 with the tooltip text different from all the
739 TooltipTestView
* v2_2
= new TooltipTestView
;
741 // Setup all the views' relations
742 view_
->AddChildView(v1
);
743 view_
->AddChildView(v2
);
744 v1
->AddChildView(v1_1
);
745 v2
->AddChildView(v2_1
);
746 v2
->AddChildView(v2_2
);
747 const base::string16
reference_string(
748 base::ASCIIToUTF16("Identical Tooltip Text"));
749 const base::string16
alternative_string(
750 base::ASCIIToUTF16("Another Shrubbery"));
751 v1
->set_tooltip_text(reference_string
);
752 v2
->set_tooltip_text(reference_string
);
753 v1_1
->set_tooltip_text(reference_string
);
754 v2_1
->set_tooltip_text(reference_string
);
755 v2_2
->set_tooltip_text(alternative_string
);
758 gfx::Rect
view_bounds(view_
->GetLocalBounds());
759 view_bounds
.set_height(view_bounds
.height() / 2);
760 v1
->SetBoundsRect(view_bounds
);
761 v1_1
->SetBounds(0, 0, 3, 3);
762 view_bounds
.set_y(view_bounds
.height());
763 v2
->SetBoundsRect(view_bounds
);
764 v2_2
->SetBounds(view_bounds
.width() - 3, view_bounds
.height() - 3, 3, 3);
765 v2_1
->SetBounds(0, 0, 3, 3);
767 // Test whether a toolbar appears on v1
768 gfx::Point center
= v1
->bounds().CenterPoint();
769 generator_
->MoveMouseRelativeTo(GetWindow(), center
);
770 helper_
->FireTooltipTimer();
771 EXPECT_TRUE(helper_
->IsTooltipVisible());
772 EXPECT_EQ(reference_string
, helper_
->GetTooltipText());
773 gfx::Point tooltip_bounds1
= test_tooltip_
->location();
775 // Test whether the toolbar changes position on mouse over v2
776 center
= v2
->bounds().CenterPoint();
777 generator_
->MoveMouseRelativeTo(GetWindow(), center
);
778 helper_
->FireTooltipTimer();
779 EXPECT_TRUE(helper_
->IsTooltipVisible());
780 EXPECT_EQ(reference_string
, helper_
->GetTooltipText());
781 gfx::Point tooltip_bounds2
= test_tooltip_
->location();
783 EXPECT_NE(tooltip_bounds1
, gfx::Point());
784 EXPECT_NE(tooltip_bounds2
, gfx::Point());
785 EXPECT_NE(tooltip_bounds1
, tooltip_bounds2
);
787 // Test if the toolbar does not change position on encountering a contained
788 // view with the same tooltip text
789 center
= v2_1
->GetLocalBounds().CenterPoint();
790 views::View::ConvertPointToTarget(v2_1
, view_
, ¢er
);
791 generator_
->MoveMouseRelativeTo(GetWindow(), center
);
792 helper_
->FireTooltipTimer();
793 gfx::Point tooltip_bounds2_1
= test_tooltip_
->location();
795 EXPECT_NE(tooltip_bounds2
, tooltip_bounds2_1
);
796 EXPECT_TRUE(helper_
->IsTooltipVisible());
797 EXPECT_EQ(reference_string
, helper_
->GetTooltipText());
799 // Test if the toolbar changes position on encountering a contained
800 // view with a different tooltip text
801 center
= v2_2
->GetLocalBounds().CenterPoint();
802 views::View::ConvertPointToTarget(v2_2
, view_
, ¢er
);
803 generator_
->MoveMouseRelativeTo(GetWindow(), center
);
804 helper_
->FireTooltipTimer();
805 gfx::Point tooltip_bounds2_2
= test_tooltip_
->location();
807 EXPECT_NE(tooltip_bounds2_1
, tooltip_bounds2_2
);
808 EXPECT_TRUE(helper_
->IsTooltipVisible());
809 EXPECT_EQ(alternative_string
, helper_
->GetTooltipText());
811 // Test if moving from a view that is contained by a larger view, both with
812 // the same tooltip text, does not change tooltip's position.
813 center
= v1_1
->GetLocalBounds().CenterPoint();
814 views::View::ConvertPointToTarget(v1_1
, view_
, ¢er
);
815 generator_
->MoveMouseRelativeTo(GetWindow(), center
);
816 helper_
->FireTooltipTimer();
817 gfx::Point tooltip_bounds1_1
= test_tooltip_
->location();
819 EXPECT_TRUE(helper_
->IsTooltipVisible());
820 EXPECT_EQ(reference_string
, helper_
->GetTooltipText());
822 center
= v1
->bounds().CenterPoint();
823 generator_
->MoveMouseRelativeTo(GetWindow(), center
);
824 helper_
->FireTooltipTimer();
825 tooltip_bounds1
= test_tooltip_
->location();
827 EXPECT_NE(tooltip_bounds1_1
, tooltip_bounds1
);
828 EXPECT_EQ(reference_string
, helper_
->GetTooltipText());
832 } // namespace corewm