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