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.
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"
17 class TestBubbleDelegateView
: public BubbleDelegateView
{
19 TestBubbleDelegateView(View
* anchor_view
)
20 : BubbleDelegateView(anchor_view
, BubbleBorder::TOP_LEFT
),
22 view_
->SetFocusable(true);
25 ~TestBubbleDelegateView() override
{}
27 void SetAnchorRectForTest(gfx::Rect rect
) {
31 void SetAnchorViewForTest(View
* view
) {
35 // BubbleDelegateView overrides:
36 View
* GetInitiallyFocusedView() override
{ return view_
; }
37 gfx::Size
GetPreferredSize() const override
{ return gfx::Size(200, 200); }
42 DISALLOW_COPY_AND_ASSIGN(TestBubbleDelegateView
);
45 class BubbleDelegateTest
: public ViewsTestBase
{
47 BubbleDelegateTest() {}
48 ~BubbleDelegateTest() override
{}
50 // Creates a test widget that owns its native widget.
51 Widget
* CreateTestWidget() {
52 Widget
* widget
= new Widget();
53 Widget::InitParams params
= CreateParams(Widget::InitParams::TYPE_WINDOW
);
54 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
60 DISALLOW_COPY_AND_ASSIGN(BubbleDelegateTest
);
65 TEST_F(BubbleDelegateTest
, CreateDelegate
) {
66 scoped_ptr
<Widget
> anchor_widget(CreateTestWidget());
67 BubbleDelegateView
* bubble_delegate
= new BubbleDelegateView(
68 anchor_widget
->GetContentsView(), BubbleBorder::NONE
);
69 bubble_delegate
->set_color(SK_ColorGREEN
);
70 Widget
* bubble_widget
= BubbleDelegateView::CreateBubble(bubble_delegate
);
71 EXPECT_EQ(bubble_delegate
, bubble_widget
->widget_delegate());
72 EXPECT_EQ(bubble_widget
, bubble_delegate
->GetWidget());
73 test::TestWidgetObserver
bubble_observer(bubble_widget
);
74 bubble_widget
->Show();
76 BubbleBorder
* border
= bubble_delegate
->GetBubbleFrameView()->bubble_border();
77 EXPECT_EQ(bubble_delegate
->arrow(), border
->arrow());
78 EXPECT_EQ(bubble_delegate
->color(), border
->background_color());
80 EXPECT_FALSE(bubble_observer
.widget_closed());
81 bubble_widget
->CloseNow();
82 EXPECT_TRUE(bubble_observer
.widget_closed());
85 TEST_F(BubbleDelegateTest
, CloseAnchorWidget
) {
86 scoped_ptr
<Widget
> anchor_widget(CreateTestWidget());
87 BubbleDelegateView
* bubble_delegate
= new BubbleDelegateView(
88 anchor_widget
->GetContentsView(), BubbleBorder::NONE
);
89 // Preventing close on deactivate should not prevent closing with the anchor.
90 bubble_delegate
->set_close_on_deactivate(false);
91 Widget
* bubble_widget
= BubbleDelegateView::CreateBubble(bubble_delegate
);
92 EXPECT_EQ(bubble_delegate
, bubble_widget
->widget_delegate());
93 EXPECT_EQ(bubble_widget
, bubble_delegate
->GetWidget());
94 EXPECT_EQ(anchor_widget
, bubble_delegate
->anchor_widget());
95 test::TestWidgetObserver
bubble_observer(bubble_widget
);
96 EXPECT_FALSE(bubble_observer
.widget_closed());
98 bubble_widget
->Show();
99 EXPECT_EQ(anchor_widget
, bubble_delegate
->anchor_widget());
100 EXPECT_FALSE(bubble_observer
.widget_closed());
102 // TODO(msw): Remove activation hack to prevent bookkeeping errors in:
103 // aura::test::TestActivationClient::OnWindowDestroyed().
104 scoped_ptr
<Widget
> smoke_and_mirrors_widget(CreateTestWidget());
105 EXPECT_FALSE(bubble_observer
.widget_closed());
107 // Ensure that closing the anchor widget also closes the bubble itself.
108 anchor_widget
->CloseNow();
109 EXPECT_TRUE(bubble_observer
.widget_closed());
112 // This test checks that the bubble delegate is capable to handle an early
113 // destruction of the used anchor view. (Animations and delayed closure of the
114 // bubble will call upon the anchor view to get its location).
115 TEST_F(BubbleDelegateTest
, CloseAnchorViewTest
) {
116 // Create an anchor widget and add a view to be used as an anchor view.
117 scoped_ptr
<Widget
> anchor_widget(CreateTestWidget());
118 scoped_ptr
<View
> anchor_view(new View());
119 anchor_widget
->GetContentsView()->AddChildView(anchor_view
.get());
120 TestBubbleDelegateView
* bubble_delegate
= new TestBubbleDelegateView(
122 // Prevent flakes by avoiding closing on activation changes.
123 bubble_delegate
->set_close_on_deactivate(false);
124 Widget
* bubble_widget
= BubbleDelegateView::CreateBubble(bubble_delegate
);
126 // Check that the anchor view is correct and set up an anchor view rect.
127 // Make sure that this rect will get ignored (as long as the anchor view is
129 EXPECT_EQ(anchor_view
, bubble_delegate
->GetAnchorView());
130 const gfx::Rect set_anchor_rect
= gfx::Rect(10, 10, 100, 100);
131 bubble_delegate
->SetAnchorRectForTest(set_anchor_rect
);
132 const gfx::Rect view_rect
= bubble_delegate
->GetAnchorRect();
133 EXPECT_NE(view_rect
.ToString(), set_anchor_rect
.ToString());
135 // Create the bubble.
136 bubble_widget
->Show();
137 EXPECT_EQ(anchor_widget
, bubble_delegate
->anchor_widget());
139 // Remove now the anchor view and make sure that the original found rect
140 // is still kept, so that the bubble does not jump when the view gets deleted.
141 anchor_widget
->GetContentsView()->RemoveChildView(anchor_view
.get());
143 EXPECT_EQ(NULL
, bubble_delegate
->GetAnchorView());
144 EXPECT_EQ(view_rect
.ToString(), bubble_delegate
->GetAnchorRect().ToString());
147 // Testing that a move of the anchor view will lead to new bubble locations.
148 TEST_F(BubbleDelegateTest
, TestAnchorRectMovesWithViewTest
) {
149 // Create an anchor widget and add a view to be used as anchor view.
150 scoped_ptr
<Widget
> anchor_widget(CreateTestWidget());
151 TestBubbleDelegateView
* bubble_delegate
= new TestBubbleDelegateView(
152 anchor_widget
->GetContentsView());
153 BubbleDelegateView::CreateBubble(bubble_delegate
);
155 anchor_widget
->GetContentsView()->SetBounds(10, 10, 100, 100);
156 const gfx::Rect view_rect
= bubble_delegate
->GetAnchorRect();
158 anchor_widget
->GetContentsView()->SetBounds(20, 10, 100, 100);
159 const gfx::Rect view_rect_2
= bubble_delegate
->GetAnchorRect();
160 EXPECT_NE(view_rect
.ToString(), view_rect_2
.ToString());
163 TEST_F(BubbleDelegateTest
, ResetAnchorWidget
) {
164 scoped_ptr
<Widget
> anchor_widget(CreateTestWidget());
165 BubbleDelegateView
* bubble_delegate
= new BubbleDelegateView(
166 anchor_widget
->GetContentsView(), BubbleBorder::NONE
);
168 // Make sure the bubble widget is parented to a widget other than the anchor
169 // widget so that closing the anchor widget does not close the bubble widget.
170 scoped_ptr
<Widget
> parent_widget(CreateTestWidget());
171 bubble_delegate
->set_parent_window(parent_widget
->GetNativeView());
172 // Preventing close on deactivate should not prevent closing with the parent.
173 bubble_delegate
->set_close_on_deactivate(false);
174 Widget
* bubble_widget
= BubbleDelegateView::CreateBubble(bubble_delegate
);
175 EXPECT_EQ(bubble_delegate
, bubble_widget
->widget_delegate());
176 EXPECT_EQ(bubble_widget
, bubble_delegate
->GetWidget());
177 EXPECT_EQ(anchor_widget
, bubble_delegate
->anchor_widget());
178 test::TestWidgetObserver
bubble_observer(bubble_widget
);
179 EXPECT_FALSE(bubble_observer
.widget_closed());
181 // Showing and hiding the bubble widget should have no effect on its anchor.
182 bubble_widget
->Show();
183 EXPECT_EQ(anchor_widget
, bubble_delegate
->anchor_widget());
184 bubble_widget
->Hide();
185 EXPECT_EQ(anchor_widget
, bubble_delegate
->anchor_widget());
187 // Ensure that closing the anchor widget clears the bubble's reference to that
188 // anchor widget, but the bubble itself does not close.
189 anchor_widget
->CloseNow();
190 EXPECT_NE(anchor_widget
, bubble_delegate
->anchor_widget());
191 EXPECT_FALSE(bubble_observer
.widget_closed());
193 // TODO(msw): Remove activation hack to prevent bookkeeping errors in:
194 // aura::test::TestActivationClient::OnWindowDestroyed().
195 scoped_ptr
<Widget
> smoke_and_mirrors_widget(CreateTestWidget());
196 EXPECT_FALSE(bubble_observer
.widget_closed());
198 // Ensure that closing the parent widget also closes the bubble itself.
199 parent_widget
->CloseNow();
200 EXPECT_TRUE(bubble_observer
.widget_closed());
203 TEST_F(BubbleDelegateTest
, InitiallyFocusedView
) {
204 scoped_ptr
<Widget
> anchor_widget(CreateTestWidget());
205 BubbleDelegateView
* bubble_delegate
= new BubbleDelegateView(
206 anchor_widget
->GetContentsView(), BubbleBorder::NONE
);
207 Widget
* bubble_widget
= BubbleDelegateView::CreateBubble(bubble_delegate
);
208 EXPECT_EQ(bubble_delegate
->GetInitiallyFocusedView(),
209 bubble_widget
->GetFocusManager()->GetFocusedView());
210 bubble_widget
->CloseNow();
213 TEST_F(BubbleDelegateTest
, NonClientHitTest
) {
214 scoped_ptr
<Widget
> anchor_widget(CreateTestWidget());
215 TestBubbleDelegateView
* bubble_delegate
=
216 new TestBubbleDelegateView(anchor_widget
->GetContentsView());
217 BubbleDelegateView::CreateBubble(bubble_delegate
);
218 BubbleFrameView
* frame
= bubble_delegate
->GetBubbleFrameView();
219 const int border
= frame
->bubble_border()->GetBorderThickness();
225 { border
, HTNOWHERE
},
226 { border
+ 50, HTCLIENT
},
230 for (size_t i
= 0; i
< arraysize(cases
); ++i
) {
231 gfx::Point
point(cases
[i
].point
, cases
[i
].point
);
232 EXPECT_EQ(cases
[i
].hit
, frame
->NonClientHitTest(point
))
233 << " with border: " << border
<< ", at point " << cases
[i
].point
;
237 TEST_F(BubbleDelegateTest
, VisibleWhenAnchorWidgetBoundsChanged
) {
238 scoped_ptr
<Widget
> anchor_widget(CreateTestWidget());
239 BubbleDelegateView
* bubble_delegate
= new BubbleDelegateView(
240 anchor_widget
->GetContentsView(), BubbleBorder::NONE
);
241 Widget
* bubble_widget
= BubbleDelegateView::CreateBubble(bubble_delegate
);
242 test::TestWidgetObserver
bubble_observer(bubble_widget
);
243 EXPECT_FALSE(bubble_observer
.widget_closed());
245 bubble_widget
->Show();
246 EXPECT_TRUE(bubble_widget
->IsVisible());
247 anchor_widget
->SetBounds(gfx::Rect(10, 10, 100, 100));
248 EXPECT_TRUE(bubble_widget
->IsVisible());
251 // Test that setting WidgetDelegate::set_can_activate() to false makes the
252 // widget created via BubbleDelegateView::CreateBubble() not activatable.
253 TEST_F(BubbleDelegateTest
, NotActivatable
) {
254 scoped_ptr
<Widget
> anchor_widget(CreateTestWidget());
255 BubbleDelegateView
* bubble_delegate
= new BubbleDelegateView(
256 anchor_widget
->GetContentsView(), BubbleBorder::NONE
);
257 bubble_delegate
->set_can_activate(false);
258 Widget
* bubble_widget
= BubbleDelegateView::CreateBubble(bubble_delegate
);
259 bubble_widget
->Show();
260 EXPECT_FALSE(bubble_widget
->CanActivate());