Home | History | Annotate | Download | only in corewm
      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_, &center);
    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_, &center);
    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_, &center);
    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
    833