Home | History | Annotate | Download | only in bubble
      1 // Copyright (c) 2012 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/base/hit_test.h"
      6 #include "ui/views/bubble/bubble_delegate.h"
      7 #include "ui/views/bubble/bubble_frame_view.h"
      8 #include "ui/views/test/test_widget_observer.h"
      9 #include "ui/views/test/views_test_base.h"
     10 #include "ui/views/widget/widget.h"
     11 #include "ui/views/widget/widget_observer.h"
     12 
     13 namespace views {
     14 
     15 namespace {
     16 
     17 class TestBubbleDelegateView : public BubbleDelegateView {
     18  public:
     19   TestBubbleDelegateView(View* anchor_view)
     20       : BubbleDelegateView(anchor_view, BubbleBorder::TOP_LEFT),
     21         view_(new View()) {
     22     view_->SetFocusable(true);
     23     AddChildView(view_);
     24   }
     25   virtual ~TestBubbleDelegateView() {}
     26 
     27   void SetAnchorRectForTest(gfx::Rect rect) {
     28     SetAnchorRect(rect);
     29   }
     30 
     31   void SetAnchorViewForTest(View* view) {
     32     SetAnchorView(view);
     33   }
     34 
     35   // BubbleDelegateView overrides:
     36   virtual View* GetInitiallyFocusedView() OVERRIDE { return view_; }
     37   virtual gfx::Size GetPreferredSize() const OVERRIDE {
     38     return gfx::Size(200, 200);
     39   }
     40 
     41  private:
     42   View* view_;
     43 
     44   DISALLOW_COPY_AND_ASSIGN(TestBubbleDelegateView);
     45 };
     46 
     47 class BubbleDelegateTest : public ViewsTestBase {
     48  public:
     49   BubbleDelegateTest() {}
     50   virtual ~BubbleDelegateTest() {}
     51 
     52   // Creates a test widget that owns its native widget.
     53   Widget* CreateTestWidget() {
     54     Widget* widget = new Widget();
     55     Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
     56     params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
     57     widget->Init(params);
     58     return widget;
     59   }
     60 
     61  private:
     62   DISALLOW_COPY_AND_ASSIGN(BubbleDelegateTest);
     63 };
     64 
     65 }  // namespace
     66 
     67 TEST_F(BubbleDelegateTest, CreateDelegate) {
     68   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
     69   BubbleDelegateView* bubble_delegate = new BubbleDelegateView(
     70       anchor_widget->GetContentsView(), BubbleBorder::NONE);
     71   bubble_delegate->set_color(SK_ColorGREEN);
     72   Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate);
     73   EXPECT_EQ(bubble_delegate, bubble_widget->widget_delegate());
     74   EXPECT_EQ(bubble_widget, bubble_delegate->GetWidget());
     75   test::TestWidgetObserver bubble_observer(bubble_widget);
     76   bubble_widget->Show();
     77 
     78   BubbleBorder* border = bubble_delegate->GetBubbleFrameView()->bubble_border();
     79   EXPECT_EQ(bubble_delegate->arrow(), border->arrow());
     80   EXPECT_EQ(bubble_delegate->color(), border->background_color());
     81 
     82   EXPECT_FALSE(bubble_observer.widget_closed());
     83   bubble_widget->CloseNow();
     84   EXPECT_TRUE(bubble_observer.widget_closed());
     85 }
     86 
     87 TEST_F(BubbleDelegateTest, CloseAnchorWidget) {
     88   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
     89   BubbleDelegateView* bubble_delegate = new BubbleDelegateView(
     90       anchor_widget->GetContentsView(), BubbleBorder::NONE);
     91   // Preventing close on deactivate should not prevent closing with the anchor.
     92   bubble_delegate->set_close_on_deactivate(false);
     93   Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate);
     94   EXPECT_EQ(bubble_delegate, bubble_widget->widget_delegate());
     95   EXPECT_EQ(bubble_widget, bubble_delegate->GetWidget());
     96   EXPECT_EQ(anchor_widget, bubble_delegate->anchor_widget());
     97   test::TestWidgetObserver bubble_observer(bubble_widget);
     98   EXPECT_FALSE(bubble_observer.widget_closed());
     99 
    100   bubble_widget->Show();
    101   EXPECT_EQ(anchor_widget, bubble_delegate->anchor_widget());
    102   EXPECT_FALSE(bubble_observer.widget_closed());
    103 
    104   // TODO(msw): Remove activation hack to prevent bookkeeping errors in:
    105   //            aura::test::TestActivationClient::OnWindowDestroyed().
    106   scoped_ptr<Widget> smoke_and_mirrors_widget(CreateTestWidget());
    107   EXPECT_FALSE(bubble_observer.widget_closed());
    108 
    109   // Ensure that closing the anchor widget also closes the bubble itself.
    110   anchor_widget->CloseNow();
    111   EXPECT_TRUE(bubble_observer.widget_closed());
    112 }
    113 
    114 // This test checks that the bubble delegate is capable to handle an early
    115 // destruction of the used anchor view. (Animations and delayed closure of the
    116 // bubble will call upon the anchor view to get its location).
    117 TEST_F(BubbleDelegateTest, CloseAnchorViewTest) {
    118   // Create an anchor widget and add a view to be used as an anchor view.
    119   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
    120   scoped_ptr<View> anchor_view(new View());
    121   anchor_widget->GetContentsView()->AddChildView(anchor_view.get());
    122   TestBubbleDelegateView* bubble_delegate = new TestBubbleDelegateView(
    123       anchor_view.get());
    124   // Prevent flakes by avoiding closing on activation changes.
    125   bubble_delegate->set_close_on_deactivate(false);
    126   Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate);
    127 
    128   // Check that the anchor view is correct and set up an anchor view rect.
    129   // Make sure that this rect will get ignored (as long as the anchor view is
    130   // attached).
    131   EXPECT_EQ(anchor_view, bubble_delegate->GetAnchorView());
    132   const gfx::Rect set_anchor_rect = gfx::Rect(10, 10, 100, 100);
    133   bubble_delegate->SetAnchorRectForTest(set_anchor_rect);
    134   const gfx::Rect view_rect = bubble_delegate->GetAnchorRect();
    135   EXPECT_NE(view_rect.ToString(), set_anchor_rect.ToString());
    136 
    137   // Create the bubble.
    138   bubble_widget->Show();
    139   EXPECT_EQ(anchor_widget, bubble_delegate->anchor_widget());
    140 
    141   // Remove now the anchor view and make sure that the original found rect
    142   // is still kept, so that the bubble does not jump when the view gets deleted.
    143   anchor_widget->GetContentsView()->RemoveChildView(anchor_view.get());
    144   anchor_view.reset();
    145   EXPECT_EQ(NULL, bubble_delegate->GetAnchorView());
    146   EXPECT_EQ(view_rect.ToString(), bubble_delegate->GetAnchorRect().ToString());
    147 }
    148 
    149 // Testing that a move of the anchor view will lead to new bubble locations.
    150 TEST_F(BubbleDelegateTest, TestAnchorRectMovesWithViewTest) {
    151   // Create an anchor widget and add a view to be used as anchor view.
    152   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
    153   TestBubbleDelegateView* bubble_delegate = new TestBubbleDelegateView(
    154       anchor_widget->GetContentsView());
    155   BubbleDelegateView::CreateBubble(bubble_delegate);
    156 
    157   anchor_widget->GetContentsView()->SetBounds(10, 10, 100, 100);
    158   const gfx::Rect view_rect = bubble_delegate->GetAnchorRect();
    159 
    160   anchor_widget->GetContentsView()->SetBounds(20, 10, 100, 100);
    161   const gfx::Rect view_rect_2 = bubble_delegate->GetAnchorRect();
    162   EXPECT_NE(view_rect.ToString(), view_rect_2.ToString());
    163 }
    164 
    165 TEST_F(BubbleDelegateTest, ResetAnchorWidget) {
    166   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
    167   BubbleDelegateView* bubble_delegate = new BubbleDelegateView(
    168       anchor_widget->GetContentsView(), BubbleBorder::NONE);
    169 
    170   // Make sure the bubble widget is parented to a widget other than the anchor
    171   // widget so that closing the anchor widget does not close the bubble widget.
    172   scoped_ptr<Widget> parent_widget(CreateTestWidget());
    173   bubble_delegate->set_parent_window(parent_widget->GetNativeView());
    174   // Preventing close on deactivate should not prevent closing with the parent.
    175   bubble_delegate->set_close_on_deactivate(false);
    176   Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate);
    177   EXPECT_EQ(bubble_delegate, bubble_widget->widget_delegate());
    178   EXPECT_EQ(bubble_widget, bubble_delegate->GetWidget());
    179   EXPECT_EQ(anchor_widget, bubble_delegate->anchor_widget());
    180   test::TestWidgetObserver bubble_observer(bubble_widget);
    181   EXPECT_FALSE(bubble_observer.widget_closed());
    182 
    183   // Showing and hiding the bubble widget should have no effect on its anchor.
    184   bubble_widget->Show();
    185   EXPECT_EQ(anchor_widget, bubble_delegate->anchor_widget());
    186   bubble_widget->Hide();
    187   EXPECT_EQ(anchor_widget, bubble_delegate->anchor_widget());
    188 
    189   // Ensure that closing the anchor widget clears the bubble's reference to that
    190   // anchor widget, but the bubble itself does not close.
    191   anchor_widget->CloseNow();
    192   EXPECT_NE(anchor_widget, bubble_delegate->anchor_widget());
    193   EXPECT_FALSE(bubble_observer.widget_closed());
    194 
    195   // TODO(msw): Remove activation hack to prevent bookkeeping errors in:
    196   //            aura::test::TestActivationClient::OnWindowDestroyed().
    197   scoped_ptr<Widget> smoke_and_mirrors_widget(CreateTestWidget());
    198   EXPECT_FALSE(bubble_observer.widget_closed());
    199 
    200   // Ensure that closing the parent widget also closes the bubble itself.
    201   parent_widget->CloseNow();
    202   EXPECT_TRUE(bubble_observer.widget_closed());
    203 }
    204 
    205 TEST_F(BubbleDelegateTest, InitiallyFocusedView) {
    206   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
    207   BubbleDelegateView* bubble_delegate = new BubbleDelegateView(
    208       anchor_widget->GetContentsView(), BubbleBorder::NONE);
    209   Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate);
    210   EXPECT_EQ(bubble_delegate->GetInitiallyFocusedView(),
    211             bubble_widget->GetFocusManager()->GetFocusedView());
    212   bubble_widget->CloseNow();
    213 }
    214 
    215 TEST_F(BubbleDelegateTest, NonClientHitTest) {
    216   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
    217   TestBubbleDelegateView* bubble_delegate =
    218       new TestBubbleDelegateView(anchor_widget->GetContentsView());
    219   BubbleDelegateView::CreateBubble(bubble_delegate);
    220   BubbleFrameView* frame = bubble_delegate->GetBubbleFrameView();
    221   const int border = frame->bubble_border()->GetBorderThickness();
    222 
    223   struct {
    224     const int point;
    225     const int hit;
    226   } cases[] = {
    227     { border,      HTNOWHERE },
    228     { border + 50, HTCLIENT  },
    229     { 1000,        HTNOWHERE },
    230   };
    231 
    232   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
    233     gfx::Point point(cases[i].point, cases[i].point);
    234     EXPECT_EQ(cases[i].hit, frame->NonClientHitTest(point))
    235         << " with border: " << border << ", at point " << cases[i].point;
    236   }
    237 }
    238 
    239 TEST_F(BubbleDelegateTest, VisibleWhenAnchorWidgetBoundsChanged) {
    240   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
    241   BubbleDelegateView* bubble_delegate = new BubbleDelegateView(
    242       anchor_widget->GetContentsView(), BubbleBorder::NONE);
    243   Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate);
    244   test::TestWidgetObserver bubble_observer(bubble_widget);
    245   EXPECT_FALSE(bubble_observer.widget_closed());
    246 
    247   bubble_widget->Show();
    248   EXPECT_TRUE(bubble_widget->IsVisible());
    249   anchor_widget->SetBounds(gfx::Rect(10, 10, 100, 100));
    250   EXPECT_TRUE(bubble_widget->IsVisible());
    251 }
    252 
    253 // Test that setting WidgetDelegate::set_can_activate() to false makes the
    254 // widget created via BubbleDelegateView::CreateBubble() not activatable.
    255 TEST_F(BubbleDelegateTest, NotActivatable) {
    256   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
    257   BubbleDelegateView* bubble_delegate = new BubbleDelegateView(
    258       anchor_widget->GetContentsView(), BubbleBorder::NONE);
    259   bubble_delegate->set_can_activate(false);
    260   Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate);
    261   bubble_widget->Show();
    262   EXPECT_FALSE(bubble_widget->CanActivate());
    263 }
    264 
    265 }  // namespace views
    266