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/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"
     34 
     35 #if defined(OS_WIN)
     36 #include "ui/base/win/scoped_ole_initializer.h"
     37 #endif
     38 
     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"
     42 #endif
     43 
     44 using base::ASCIIToUTF16;
     45 
     46 namespace views {
     47 namespace corewm {
     48 namespace test {
     49 namespace {
     50 
     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)
     58   params.parent = root;
     59 #else
     60   params.native_widget = new DesktopNativeWidgetAura(widget);
     61 #endif
     62   params.bounds = gfx::Rect(0, 0, 200, 100);
     63   widget->Init(params);
     64   widget->Show();
     65   return widget;
     66 }
     67 
     68 TooltipController* GetController(Widget* widget) {
     69   return static_cast<TooltipController*>(
     70       aura::client::GetTooltipClient(
     71           widget->GetNativeWindow()->GetRootWindow()));
     72 }
     73 
     74 }  // namespace
     75 
     76 class TooltipControllerTest : public aura::test::AuraTestBase {
     77  public:
     78   TooltipControllerTest() : view_(NULL) {}
     79   virtual ~TooltipControllerTest() {}
     80 
     81   virtual void SetUp() OVERRIDE {
     82 #if defined(OS_CHROMEOS)
     83     views_delegate_.reset(new TestViewsDelegate);
     84 #else
     85     views_delegate_.reset(new DesktopTestViewsDelegate);
     86 #endif
     87 
     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());
     96 #endif
     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()));
    105   }
    106 
    107   virtual void TearDown() OVERRIDE {
    108 #if defined(OS_CHROMEOS)
    109     root_window()->RemovePreTargetHandler(controller_.get());
    110     aura::client::SetTooltipClient(root_window(), NULL);
    111     controller_.reset();
    112 #endif
    113     generator_.reset();
    114     helper_.reset();
    115     widget_.reset();
    116     aura::test::AuraTestBase::TearDown();
    117     views_delegate_.reset();
    118   }
    119 
    120  protected:
    121   aura::Window* GetWindow() {
    122     return widget_->GetNativeWindow();
    123   }
    124 
    125   aura::Window* GetRootWindow() {
    126     return GetWindow()->GetRootWindow();
    127   }
    128 
    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);
    134     return view2;
    135   }
    136 
    137   scoped_ptr<views::Widget> widget_;
    138   TooltipTestView* view_;
    139   scoped_ptr<TooltipControllerTestHelper> helper_;
    140   scoped_ptr<aura::test::EventGenerator> generator_;
    141 
    142  private:
    143   scoped_ptr<TooltipController> controller_;
    144 
    145   scoped_ptr<views::TestViewsDelegate> views_delegate_;
    146 
    147 #if defined(OS_WIN)
    148   ui::ScopedOleInitializer ole_initializer_;
    149 #endif
    150 
    151   DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest);
    152 };
    153 
    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());
    159 
    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());
    166 
    167   // Fire tooltip timer so tooltip becomes visible.
    168   helper_->FireTooltipTimer();
    169 
    170   EXPECT_TRUE(helper_->IsTooltipVisible());
    171   generator_->MoveMouseBy(1, 0);
    172 
    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());
    177 }
    178 
    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());
    183 
    184   PrepareSecondView();
    185   aura::Window* window = GetWindow();
    186   aura::Window* root_window = GetRootWindow();
    187 
    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());
    201   }
    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());
    211   }
    212 }
    213 
    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());
    218 
    219   generator_->MoveMouseRelativeTo(GetWindow(), view_->bounds().CenterPoint());
    220   base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text");
    221 
    222   // Fire tooltip timer so tooltip becomes visible.
    223   helper_->FireTooltipTimer();
    224   EXPECT_TRUE(helper_->IsTooltipVisible());
    225 
    226   // Disable tooltips and check again.
    227   helper_->controller()->SetTooltipsEnabled(false);
    228   EXPECT_FALSE(helper_->IsTooltipVisible());
    229   helper_->FireTooltipTimer();
    230   EXPECT_FALSE(helper_->IsTooltipVisible());
    231 
    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());
    237 }
    238 
    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());
    244 
    245   generator_->MoveMouseRelativeTo(GetWindow(), view_->bounds().CenterPoint());
    246 
    247   helper_->FireTooltipTimer();
    248   EXPECT_FALSE(helper_->IsTooltipVisible());
    249 }
    250 
    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());
    255 
    256   TooltipTestView* view2 = PrepareSecondView();
    257   view2->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 2"));
    258 
    259   aura::Window* window = GetWindow();
    260 
    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());
    266 
    267   generator_->PressKey(ui::VKEY_1, 0);
    268   EXPECT_FALSE(helper_->IsTooltipVisible());
    269   EXPECT_FALSE(helper_->IsTooltipTimerRunning());
    270   EXPECT_FALSE(helper_->IsTooltipShownTimerRunning());
    271 
    272   // Moving the mouse inside |view1| should not change the state of the tooltip
    273   // or the timers.
    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());
    279     EXPECT_EQ(window,
    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());
    286   }
    287 
    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());
    298 }
    299 
    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());
    304 
    305   TooltipTestView* view2 = PrepareSecondView();
    306   view2->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 2"));
    307 
    308   aura::Window* window = GetWindow();
    309 
    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());
    315 
    316   helper_->FireTooltipShownTimer();
    317   EXPECT_FALSE(helper_->IsTooltipVisible());
    318   EXPECT_FALSE(helper_->IsTooltipTimerRunning());
    319   EXPECT_FALSE(helper_->IsTooltipShownTimerRunning());
    320 
    321   // Moving the mouse inside |view1| should not change the state of the tooltip
    322   // or the timers.
    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());
    334   }
    335 
    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());
    346 }
    347 
    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());
    356 
    357   // Fire tooltip timer so tooltip becomes visible.
    358   helper_->FireTooltipTimer();
    359 
    360   EXPECT_TRUE(helper_->IsTooltipVisible());
    361   generator_->SendMouseExit();
    362   EXPECT_FALSE(helper_->IsTooltipVisible());
    363 }
    364 
    365 TEST_F(TooltipControllerTest, ReshowOnClickAfterEnterExit) {
    366   // Owned by |view_|.
    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);
    380 
    381   gfx::Point v1_point(1, 1);
    382   View::ConvertPointToWidget(v1, &v1_point);
    383   generator_->MoveMouseRelativeTo(GetWindow(), v1_point);
    384 
    385   // Fire tooltip timer so tooltip becomes visible.
    386   helper_->FireTooltipTimer();
    387   EXPECT_TRUE(helper_->IsTooltipVisible());
    388   EXPECT_EQ(v1_tt, helper_->GetTooltipText());
    389 
    390   // Press the mouse, move to v2 and back to v1.
    391   generator_->ClickLeftButton();
    392 
    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);
    397 
    398   helper_->FireTooltipTimer();
    399   EXPECT_TRUE(helper_->IsTooltipVisible());
    400   EXPECT_EQ(v1_tt, helper_->GetTooltipText());
    401 }
    402 
    403 namespace {
    404 
    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(),
    410                 window);
    411   return i == window->parent()->children().end() ? -1 :
    412       static_cast<int>(i - window->parent()->children().begin());
    413 }
    414 
    415 class TestScreenPositionClient : public aura::client::ScreenPositionClient {
    416  public:
    417   TestScreenPositionClient() {}
    418   virtual ~TestScreenPositionClient() {}
    419 
    420   // ScreenPositionClient overrides:
    421   virtual void ConvertPointToScreen(const aura::Window* window,
    422                                     gfx::Point* point) OVERRIDE {
    423   }
    424   virtual void ConvertPointFromScreen(const aura::Window* window,
    425                                       gfx::Point* point) OVERRIDE {
    426   }
    427   virtual void ConvertHostPointToScreen(aura::Window* root_gwindow,
    428                                         gfx::Point* point) OVERRIDE {
    429     NOTREACHED();
    430   }
    431   virtual void SetBounds(aura::Window* window,
    432                          const gfx::Rect& bounds,
    433                          const gfx::Display& display) OVERRIDE {
    434     window->SetBounds(bounds);
    435   }
    436 
    437  private:
    438   DISALLOW_COPY_AND_ASSIGN(TestScreenPositionClient);
    439 };
    440 
    441 }  // namespace
    442 
    443 class TooltipControllerCaptureTest : public TooltipControllerTest {
    444  public:
    445   TooltipControllerCaptureTest() {}
    446   virtual ~TooltipControllerCaptureTest() {}
    447 
    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());
    456 #endif
    457   }
    458 
    459   virtual void TearDown() OVERRIDE {
    460 #if !defined(OS_CHROMEOS)
    461     gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen());
    462     desktop_screen_.reset();
    463 #endif
    464     aura::client::SetScreenPositionClient(GetRootWindow(), NULL);
    465     TooltipControllerTest::TearDown();
    466   }
    467 
    468  private:
    469   TestScreenPositionClient screen_position_client_;
    470   scoped_ptr<gfx::Screen> desktop_screen_;
    471 
    472   DISALLOW_COPY_AND_ASSIGN(TooltipControllerCaptureTest);
    473 };
    474 
    475 // Verifies when capture is released the TooltipController resets state.
    476 TEST_F(TooltipControllerCaptureTest, 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 aura::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<aura::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 aura::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<aura::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