| 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 "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(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 | |
| OLD | NEW |