| OLD | NEW |
| (Empty) |
| 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 "ui/views/corewm/tooltip_controller.h" | |
| 6 | |
| 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" | |
| 33 | |
| 34 #if defined(OS_WIN) | |
| 35 #include "ui/base/win/scoped_ole_initializer.h" | |
| 36 #endif | |
| 37 | |
| 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" | |
| 41 #endif | |
| 42 | |
| 43 using base::ASCIIToUTF16; | |
| 44 | |
| 45 namespace views { | |
| 46 namespace corewm { | |
| 47 namespace test { | |
| 48 namespace { | |
| 49 | |
| 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) | |
| 57 params.parent = root; | |
| 58 #else | |
| 59 params.native_widget = new DesktopNativeWidgetAura(widget); | |
| 60 #endif | |
| 61 params.bounds = gfx::Rect(0, 0, 200, 100); | |
| 62 widget->Init(params); | |
| 63 widget->Show(); | |
| 64 return widget; | |
| 65 } | |
| 66 | |
| 67 TooltipController* GetController(Widget* widget) { | |
| 68 return static_cast<TooltipController*>( | |
| 69 aura::client::GetTooltipClient( | |
| 70 widget->GetNativeWindow()->GetRootWindow())); | |
| 71 } | |
| 72 | |
| 73 } // namespace | |
| 74 | |
| 75 class TooltipControllerTest : public aura::test::AuraTestBase { | |
| 76 public: | |
| 77 TooltipControllerTest() : view_(NULL) {} | |
| 78 virtual ~TooltipControllerTest() {} | |
| 79 | |
| 80 virtual void SetUp() override { | |
| 81 #if defined(OS_CHROMEOS) | |
| 82 views_delegate_.reset(new TestViewsDelegate); | |
| 83 #else | |
| 84 views_delegate_.reset(new DesktopTestViewsDelegate); | |
| 85 #endif | |
| 86 | |
| 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()); | |
| 95 #endif | |
| 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())); | |
| 104 } | |
| 105 | |
| 106 virtual void TearDown() override { | |
| 107 #if defined(OS_CHROMEOS) | |
| 108 root_window()->RemovePreTargetHandler(controller_.get()); | |
| 109 aura::client::SetTooltipClient(root_window(), NULL); | |
| 110 controller_.reset(); | |
| 111 #endif | |
| 112 generator_.reset(); | |
| 113 helper_.reset(); | |
| 114 widget_.reset(); | |
| 115 aura::test::AuraTestBase::TearDown(); | |
| 116 views_delegate_.reset(); | |
| 117 } | |
| 118 | |
| 119 protected: | |
| 120 aura::Window* GetWindow() { | |
| 121 return widget_->GetNativeWindow(); | |
| 122 } | |
| 123 | |
| 124 aura::Window* GetRootWindow() { | |
| 125 return GetWindow()->GetRootWindow(); | |
| 126 } | |
| 127 | |
| 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); | |
| 133 return view2; | |
| 134 } | |
| 135 | |
| 136 scoped_ptr<views::Widget> widget_; | |
| 137 TooltipTestView* view_; | |
| 138 scoped_ptr<TooltipControllerTestHelper> helper_; | |
| 139 scoped_ptr<ui::test::EventGenerator> generator_; | |
| 140 | |
| 141 private: | |
| 142 scoped_ptr<TooltipController> controller_; | |
| 143 | |
| 144 scoped_ptr<views::TestViewsDelegate> views_delegate_; | |
| 145 | |
| 146 #if defined(OS_WIN) | |
| 147 ui::ScopedOleInitializer ole_initializer_; | |
| 148 #endif | |
| 149 | |
| 150 DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest); | |
| 151 }; | |
| 152 | |
| 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()); | |
| 158 | |
| 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()); | |
| 165 | |
| 166 // Fire tooltip timer so tooltip becomes visible. | |
| 167 helper_->FireTooltipTimer(); | |
| 168 | |
| 169 EXPECT_TRUE(helper_->IsTooltipVisible()); | |
| 170 generator_->MoveMouseBy(1, 0); | |
| 171 | |
| 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()); | |
| 176 } | |
| 177 | |
| 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()); | |
| 182 | |
| 183 PrepareSecondView(); | |
| 184 aura::Window* window = GetWindow(); | |
| 185 aura::Window* root_window = GetRootWindow(); | |
| 186 | |
| 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()); | |
| 200 } | |
| 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()); | |
| 210 } | |
| 211 } | |
| 212 | |
| 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()); | |
| 217 | |
| 218 generator_->MoveMouseRelativeTo(GetWindow(), view_->bounds().CenterPoint()); | |
| 219 base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text"); | |
| 220 | |
| 221 // Fire tooltip timer so tooltip becomes visible. | |
| 222 helper_->FireTooltipTimer(); | |
| 223 EXPECT_TRUE(helper_->IsTooltipVisible()); | |
| 224 | |
| 225 // Disable tooltips and check again. | |
| 226 helper_->controller()->SetTooltipsEnabled(false); | |
| 227 EXPECT_FALSE(helper_->IsTooltipVisible()); | |
| 228 helper_->FireTooltipTimer(); | |
| 229 EXPECT_FALSE(helper_->IsTooltipVisible()); | |
| 230 | |
| 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()); | |
| 236 } | |
| 237 | |
| 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()); | |
| 243 | |
| 244 generator_->MoveMouseRelativeTo(GetWindow(), view_->bounds().CenterPoint()); | |
| 245 | |
| 246 helper_->FireTooltipTimer(); | |
| 247 EXPECT_FALSE(helper_->IsTooltipVisible()); | |
| 248 } | |
| 249 | |
| 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()); | |
| 254 | |
| 255 TooltipTestView* view2 = PrepareSecondView(); | |
| 256 view2->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 2")); | |
| 257 | |
| 258 aura::Window* window = GetWindow(); | |
| 259 | |
| 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()); | |
| 265 | |
| 266 generator_->PressKey(ui::VKEY_1, 0); | |
| 267 EXPECT_FALSE(helper_->IsTooltipVisible()); | |
| 268 EXPECT_FALSE(helper_->IsTooltipTimerRunning()); | |
| 269 EXPECT_FALSE(helper_->IsTooltipShownTimerRunning()); | |
| 270 | |
| 271 // Moving the mouse inside |view1| should not change the state of the tooltip | |
| 272 // or the timers. | |
| 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()); | |
| 278 EXPECT_EQ(window, | |
| 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()); | |
| 285 } | |
| 286 | |
| 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()); | |
| 297 } | |
| 298 | |
| 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()); | |
| 303 | |
| 304 TooltipTestView* view2 = PrepareSecondView(); | |
| 305 view2->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 2")); | |
| 306 | |
| 307 aura::Window* window = GetWindow(); | |
| 308 | |
| 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()); | |
| 314 | |
| 315 helper_->FireTooltipShownTimer(); | |
| 316 EXPECT_FALSE(helper_->IsTooltipVisible()); | |
| 317 EXPECT_FALSE(helper_->IsTooltipTimerRunning()); | |
| 318 EXPECT_FALSE(helper_->IsTooltipShownTimerRunning()); | |
| 319 | |
| 320 // Moving the mouse inside |view1| should not change the state of the tooltip | |
| 321 // or the timers. | |
| 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()); | |
| 333 } | |
| 334 | |
| 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()); | |
| 345 } | |
| 346 | |
| 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()); | |
| 355 | |
| 356 // Fire tooltip timer so tooltip becomes visible. | |
| 357 helper_->FireTooltipTimer(); | |
| 358 | |
| 359 EXPECT_TRUE(helper_->IsTooltipVisible()); | |
| 360 generator_->SendMouseExit(); | |
| 361 EXPECT_FALSE(helper_->IsTooltipVisible()); | |
| 362 } | |
| 363 | |
| 364 TEST_F(TooltipControllerTest, ReshowOnClickAfterEnterExit) { | |
| 365 // Owned by |view_|. | |
| 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); | |
| 379 | |
| 380 gfx::Point v1_point(1, 1); | |
| 381 View::ConvertPointToWidget(v1, &v1_point); | |
| 382 generator_->MoveMouseRelativeTo(GetWindow(), v1_point); | |
| 383 | |
| 384 // Fire tooltip timer so tooltip becomes visible. | |
| 385 helper_->FireTooltipTimer(); | |
| 386 EXPECT_TRUE(helper_->IsTooltipVisible()); | |
| 387 EXPECT_EQ(v1_tt, helper_->GetTooltipText()); | |
| 388 | |
| 389 // Press the mouse, move to v2 and back to v1. | |
| 390 generator_->ClickLeftButton(); | |
| 391 | |
| 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); | |
| 396 | |
| 397 helper_->FireTooltipTimer(); | |
| 398 EXPECT_TRUE(helper_->IsTooltipVisible()); | |
| 399 EXPECT_EQ(v1_tt, helper_->GetTooltipText()); | |
| 400 } | |
| 401 | |
| 402 namespace { | |
| 403 | |
| 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(), | |
| 409 window); | |
| 410 return i == window->parent()->children().end() ? -1 : | |
| 411 static_cast<int>(i - window->parent()->children().begin()); | |
| 412 } | |
| 413 | |
| 414 class TestScreenPositionClient : public aura::client::ScreenPositionClient { | |
| 415 public: | |
| 416 TestScreenPositionClient() {} | |
| 417 virtual ~TestScreenPositionClient() {} | |
| 418 | |
| 419 // ScreenPositionClient overrides: | |
| 420 virtual void ConvertPointToScreen(const aura::Window* window, | |
| 421 gfx::Point* point) override { | |
| 422 } | |
| 423 virtual void ConvertPointFromScreen(const aura::Window* window, | |
| 424 gfx::Point* point) override { | |
| 425 } | |
| 426 virtual void ConvertHostPointToScreen(aura::Window* root_gwindow, | |
| 427 gfx::Point* point) override { | |
| 428 NOTREACHED(); | |
| 429 } | |
| 430 virtual void SetBounds(aura::Window* window, | |
| 431 const gfx::Rect& bounds, | |
| 432 const gfx::Display& display) override { | |
| 433 window->SetBounds(bounds); | |
| 434 } | |
| 435 | |
| 436 private: | |
| 437 DISALLOW_COPY_AND_ASSIGN(TestScreenPositionClient); | |
| 438 }; | |
| 439 | |
| 440 } // namespace | |
| 441 | |
| 442 class TooltipControllerCaptureTest : public TooltipControllerTest { | |
| 443 public: | |
| 444 TooltipControllerCaptureTest() {} | |
| 445 virtual ~TooltipControllerCaptureTest() {} | |
| 446 | |
| 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()); | |
| 455 #endif | |
| 456 } | |
| 457 | |
| 458 virtual void TearDown() override { | |
| 459 #if !defined(OS_CHROMEOS) | |
| 460 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen()); | |
| 461 desktop_screen_.reset(); | |
| 462 #endif | |
| 463 aura::client::SetScreenPositionClient(GetRootWindow(), NULL); | |
| 464 TooltipControllerTest::TearDown(); | |
| 465 } | |
| 466 | |
| 467 private: | |
| 468 TestScreenPositionClient screen_position_client_; | |
| 469 scoped_ptr<gfx::Screen> desktop_screen_; | |
| 470 | |
| 471 DISALLOW_COPY_AND_ASSIGN(TooltipControllerCaptureTest); | |
| 472 }; | |
| 473 | |
| 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()); | |
| 485 | |
| 486 // Fire tooltip timer so tooltip becomes visible. | |
| 487 helper_->FireTooltipTimer(); | |
| 488 | |
| 489 EXPECT_TRUE(helper_->IsTooltipVisible()); | |
| 490 view_->GetWidget()->ReleaseCapture(); | |
| 491 EXPECT_FALSE(helper_->IsTooltipVisible()); | |
| 492 EXPECT_TRUE(helper_->GetTooltipWindow() == NULL); | |
| 493 } | |
| 494 | |
| 495 // Disabled on linux as DesktopScreenX11::GetWindowAtScreenPoint() doesn't | |
| 496 // consider z-order. | |
| 497 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) | |
| 498 #define MAYBE_Capture DISABLED_Capture | |
| 499 #else | |
| 500 #define MAYBE_Capture Capture | |
| 501 #endif | |
| 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")); | |
| 506 | |
| 507 widget_->SetBounds(gfx::Rect(0, 0, 200, 200)); | |
| 508 view_->set_tooltip_text(tooltip_text); | |
| 509 | |
| 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()); | |
| 517 | |
| 518 widget_->SetCapture(view_); | |
| 519 EXPECT_TRUE(widget_->HasCapture()); | |
| 520 widget2->Show(); | |
| 521 EXPECT_GE(IndexInParent(widget2->GetNativeWindow()), | |
| 522 IndexInParent(widget_->GetNativeWindow())); | |
| 523 | |
| 524 generator_->MoveMouseRelativeTo(widget_->GetNativeWindow(), | |
| 525 view_->bounds().CenterPoint()); | |
| 526 | |
| 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()); | |
| 533 | |
| 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()); | |
| 546 | |
| 547 widget2.reset(); | |
| 548 } | |
| 549 | |
| 550 namespace { | |
| 551 | |
| 552 class TestTooltip : public Tooltip { | |
| 553 public: | |
| 554 TestTooltip() : is_visible_(false) {} | |
| 555 virtual ~TestTooltip() {} | |
| 556 | |
| 557 const base::string16& tooltip_text() const { return tooltip_text_; } | |
| 558 | |
| 559 // Tooltip: | |
| 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; | |
| 565 } | |
| 566 virtual void Show() override { | |
| 567 is_visible_ = true; | |
| 568 } | |
| 569 virtual void Hide() override { | |
| 570 is_visible_ = false; | |
| 571 } | |
| 572 virtual bool IsVisible() override { | |
| 573 return is_visible_; | |
| 574 } | |
| 575 const gfx::Point& location() { return location_; } | |
| 576 | |
| 577 private: | |
| 578 bool is_visible_; | |
| 579 base::string16 tooltip_text_; | |
| 580 gfx::Point location_; | |
| 581 | |
| 582 DISALLOW_COPY_AND_ASSIGN(TestTooltip); | |
| 583 }; | |
| 584 | |
| 585 } // namespace | |
| 586 | |
| 587 // Use for tests that don't depend upon views. | |
| 588 class TooltipControllerTest2 : public aura::test::AuraTestBase { | |
| 589 public: | |
| 590 TooltipControllerTest2() : test_tooltip_(new TestTooltip) {} | |
| 591 virtual ~TooltipControllerTest2() {} | |
| 592 | |
| 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())); | |
| 603 } | |
| 604 | |
| 605 virtual void TearDown() override { | |
| 606 root_window()->RemovePreTargetHandler(controller_.get()); | |
| 607 aura::client::SetTooltipClient(root_window(), NULL); | |
| 608 controller_.reset(); | |
| 609 generator_.reset(); | |
| 610 helper_.reset(); | |
| 611 aura::test::AuraTestBase::TearDown(); | |
| 612 wm_state_.reset(); | |
| 613 } | |
| 614 | |
| 615 protected: | |
| 616 // Owned by |controller_|. | |
| 617 TestTooltip* test_tooltip_; | |
| 618 scoped_ptr<TooltipControllerTestHelper> helper_; | |
| 619 scoped_ptr<ui::test::EventGenerator> generator_; | |
| 620 | |
| 621 private: | |
| 622 scoped_ptr<TooltipController> controller_; | |
| 623 scoped_ptr<wm::WMState> wm_state_; | |
| 624 | |
| 625 DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest2); | |
| 626 }; | |
| 627 | |
| 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()); | |
| 638 } | |
| 639 | |
| 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()); | |
| 649 | |
| 650 // Fire tooltip timer so tooltip becomes visible. | |
| 651 helper_->FireTooltipTimer(); | |
| 652 EXPECT_TRUE(helper_->IsTooltipVisible()); | |
| 653 | |
| 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); | |
| 660 } | |
| 661 | |
| 662 // Use for tests that need both views and a TestTooltip. | |
| 663 class TooltipControllerTest3 : public aura::test::AuraTestBase { | |
| 664 public: | |
| 665 TooltipControllerTest3() : test_tooltip_(new TestTooltip) {} | |
| 666 virtual ~TooltipControllerTest3() {} | |
| 667 | |
| 668 virtual void SetUp() override { | |
| 669 wm_state_.reset(new wm::WMState); | |
| 670 aura::test::AuraTestBase::SetUp(); | |
| 671 new wm::DefaultActivationClient(root_window()); | |
| 672 | |
| 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()); | |
| 678 | |
| 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()); | |
| 688 } | |
| 689 | |
| 690 virtual void TearDown() override { | |
| 691 GetRootWindow()->RemovePreTargetHandler(controller_.get()); | |
| 692 aura::client::SetTooltipClient(GetRootWindow(), NULL); | |
| 693 | |
| 694 controller_.reset(); | |
| 695 generator_.reset(); | |
| 696 helper_.reset(); | |
| 697 widget_.reset(); | |
| 698 aura::test::AuraTestBase::TearDown(); | |
| 699 wm_state_.reset(); | |
| 700 } | |
| 701 | |
| 702 aura::Window* GetWindow() { return widget_->GetNativeWindow(); } | |
| 703 | |
| 704 protected: | |
| 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_; | |
| 711 | |
| 712 private: | |
| 713 scoped_ptr<TooltipController> controller_; | |
| 714 scoped_ptr<wm::WMState> wm_state_; | |
| 715 | |
| 716 #if defined(OS_WIN) | |
| 717 ui::ScopedOleInitializer ole_initializer_; | |
| 718 #endif | |
| 719 | |
| 720 aura::Window* GetRootWindow() { return GetWindow()->GetRootWindow(); } | |
| 721 | |
| 722 DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest3); | |
| 723 }; | |
| 724 | |
| 725 TEST_F(TooltipControllerTest3, TooltipPositionChangesOnTwoViewsWithSameLabel) { | |
| 726 // Owned by |view_|. | |
| 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 | |
| 731 // and v2 | |
| 732 TooltipTestView* v1_1 = new TooltipTestView; | |
| 733 // v2_1 is a view inside v2 that has an identical tooltip text to that of v1 | |
| 734 // and v2 | |
| 735 TooltipTestView* v2_1 = new TooltipTestView; | |
| 736 // v2_2 is a view inside v2 with the tooltip text different from all the | |
| 737 // others | |
| 738 TooltipTestView* v2_2 = new TooltipTestView; | |
| 739 | |
| 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); | |
| 755 | |
| 756 // Set views' bounds | |
| 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); | |
| 765 | |
| 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(); | |
| 773 | |
| 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(); | |
| 781 | |
| 782 EXPECT_NE(tooltip_bounds1, gfx::Point()); | |
| 783 EXPECT_NE(tooltip_bounds2, gfx::Point()); | |
| 784 EXPECT_NE(tooltip_bounds1, tooltip_bounds2); | |
| 785 | |
| 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(); | |
| 793 | |
| 794 EXPECT_NE(tooltip_bounds2, tooltip_bounds2_1); | |
| 795 EXPECT_TRUE(helper_->IsTooltipVisible()); | |
| 796 EXPECT_EQ(reference_string, helper_->GetTooltipText()); | |
| 797 | |
| 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(); | |
| 805 | |
| 806 EXPECT_NE(tooltip_bounds2_1, tooltip_bounds2_2); | |
| 807 EXPECT_TRUE(helper_->IsTooltipVisible()); | |
| 808 EXPECT_EQ(alternative_string, helper_->GetTooltipText()); | |
| 809 | |
| 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(); | |
| 817 | |
| 818 EXPECT_TRUE(helper_->IsTooltipVisible()); | |
| 819 EXPECT_EQ(reference_string, helper_->GetTooltipText()); | |
| 820 | |
| 821 center = v1->bounds().CenterPoint(); | |
| 822 generator_->MoveMouseRelativeTo(GetWindow(), center); | |
| 823 helper_->FireTooltipTimer(); | |
| 824 tooltip_bounds1 = test_tooltip_->location(); | |
| 825 | |
| 826 EXPECT_NE(tooltip_bounds1_1, tooltip_bounds1); | |
| 827 EXPECT_EQ(reference_string, helper_->GetTooltipText()); | |
| 828 } | |
| 829 | |
| 830 } // namespace test | |
| 831 } // namespace corewm | |
| 832 } // namespace views | |
| OLD | NEW |