Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ui / views / widget / root_view_unittest.cc
1 // Copyright 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/widget/root_view.h"
6
7 #include "ui/views/context_menu_controller.h"
8 #include "ui/views/test/views_test_base.h"
9 #include "ui/views/view_targeter.h"
10 #include "ui/views/widget/root_view.h"
11
12 namespace views {
13 namespace test {
14
15 typedef ViewsTestBase RootViewTest;
16
17 class DeleteOnKeyEventView : public View {
18  public:
19   explicit DeleteOnKeyEventView(bool* set_on_key) : set_on_key_(set_on_key) {}
20   virtual ~DeleteOnKeyEventView() {}
21
22   virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE {
23     *set_on_key_ = true;
24     delete this;
25     return true;
26   }
27
28  private:
29   // Set to true in OnKeyPressed().
30   bool* set_on_key_;
31
32   DISALLOW_COPY_AND_ASSIGN(DeleteOnKeyEventView);
33 };
34
35 // Verifies deleting a View in OnKeyPressed() doesn't crash and that the
36 // target is marked as destroyed in the returned EventDispatchDetails.
37 TEST_F(RootViewTest, DeleteViewDuringKeyEventDispatch) {
38   Widget widget;
39   Widget::InitParams init_params =
40       CreateParams(Widget::InitParams::TYPE_POPUP);
41   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
42   widget.Init(init_params);
43
44   bool got_key_event = false;
45
46   View* content = new View;
47   widget.SetContentsView(content);
48
49   View* child = new DeleteOnKeyEventView(&got_key_event);
50   content->AddChildView(child);
51
52   // Give focus to |child| so that it will be the target of the key event.
53   child->SetFocusable(true);
54   child->RequestFocus();
55
56   internal::RootView* root_view =
57       static_cast<internal::RootView*>(widget.GetRootView());
58   ViewTargeter* view_targeter = new ViewTargeter(root_view);
59   root_view->SetEventTargeter(make_scoped_ptr(view_targeter));
60
61   ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, ui::EF_NONE);
62   ui::EventDispatchDetails details = root_view->OnEventFromSource(&key_event);
63   EXPECT_TRUE(details.target_destroyed);
64   EXPECT_FALSE(details.dispatcher_destroyed);
65   EXPECT_TRUE(got_key_event);
66 }
67
68 // Tracks whether a context menu is shown.
69 class TestContextMenuController : public ContextMenuController {
70  public:
71   TestContextMenuController()
72       : show_context_menu_calls_(0),
73         menu_source_view_(NULL),
74         menu_source_type_(ui::MENU_SOURCE_NONE) {
75   }
76   virtual ~TestContextMenuController() {}
77
78   int show_context_menu_calls() const { return show_context_menu_calls_; }
79   View* menu_source_view() const { return menu_source_view_; }
80   ui::MenuSourceType menu_source_type() const { return menu_source_type_; }
81
82   void Reset() {
83     show_context_menu_calls_ = 0;
84     menu_source_view_ = NULL;
85     menu_source_type_ = ui::MENU_SOURCE_NONE;
86   }
87
88   // ContextMenuController:
89   virtual void ShowContextMenuForView(
90       View* source,
91       const gfx::Point& point,
92       ui::MenuSourceType source_type) OVERRIDE {
93     show_context_menu_calls_++;
94     menu_source_view_ = source;
95     menu_source_type_ = source_type;
96   }
97
98  private:
99   int show_context_menu_calls_;
100   View* menu_source_view_;
101   ui::MenuSourceType menu_source_type_;
102
103   DISALLOW_COPY_AND_ASSIGN(TestContextMenuController);
104 };
105
106 // Tests that context menus are shown for certain key events (Shift+F10
107 // and VKEY_APPS) by the pre-target handler installed on RootView.
108 TEST_F(RootViewTest, ContextMenuFromKeyEvent) {
109   Widget widget;
110   Widget::InitParams init_params =
111       CreateParams(Widget::InitParams::TYPE_POPUP);
112   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
113   widget.Init(init_params);
114   internal::RootView* root_view =
115       static_cast<internal::RootView*>(widget.GetRootView());
116
117   TestContextMenuController controller;
118   View* focused_view = new View;
119   focused_view->set_context_menu_controller(&controller);
120   widget.SetContentsView(focused_view);
121   focused_view->SetFocusable(true);
122   focused_view->RequestFocus();
123
124   // No context menu should be shown for a keypress of 'A'.
125   ui::KeyEvent nomenu_key_event('a', ui::VKEY_A, ui::EF_NONE);
126   ui::EventDispatchDetails details =
127       root_view->OnEventFromSource(&nomenu_key_event);
128   EXPECT_FALSE(details.target_destroyed);
129   EXPECT_FALSE(details.dispatcher_destroyed);
130   EXPECT_EQ(0, controller.show_context_menu_calls());
131   EXPECT_EQ(NULL, controller.menu_source_view());
132   EXPECT_EQ(ui::MENU_SOURCE_NONE, controller.menu_source_type());
133   controller.Reset();
134
135   // A context menu should be shown for a keypress of Shift+F10.
136   ui::KeyEvent menu_key_event(
137       ui::ET_KEY_PRESSED, ui::VKEY_F10, ui::EF_SHIFT_DOWN);
138   details = root_view->OnEventFromSource(&menu_key_event);
139   EXPECT_FALSE(details.target_destroyed);
140   EXPECT_FALSE(details.dispatcher_destroyed);
141   EXPECT_EQ(1, controller.show_context_menu_calls());
142   EXPECT_EQ(focused_view, controller.menu_source_view());
143   EXPECT_EQ(ui::MENU_SOURCE_KEYBOARD, controller.menu_source_type());
144   controller.Reset();
145
146   // A context menu should be shown for a keypress of VKEY_APPS.
147   ui::KeyEvent menu_key_event2(ui::ET_KEY_PRESSED, ui::VKEY_APPS, ui::EF_NONE);
148   details = root_view->OnEventFromSource(&menu_key_event2);
149   EXPECT_FALSE(details.target_destroyed);
150   EXPECT_FALSE(details.dispatcher_destroyed);
151   EXPECT_EQ(1, controller.show_context_menu_calls());
152   EXPECT_EQ(focused_view, controller.menu_source_view());
153   EXPECT_EQ(ui::MENU_SOURCE_KEYBOARD, controller.menu_source_type());
154   controller.Reset();
155 }
156
157 // View which handles all gesture events.
158 class GestureHandlingView : public View {
159  public:
160   GestureHandlingView() {
161   }
162
163   virtual ~GestureHandlingView() {
164   }
165
166   virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
167     event->SetHandled();
168   }
169
170  private:
171   DISALLOW_COPY_AND_ASSIGN(GestureHandlingView);
172 };
173
174 // Tests that context menus are shown for long press by the post-target handler
175 // installed on the RootView only if the event is targetted at a view which can
176 // show a context menu.
177 TEST_F(RootViewTest, ContextMenuFromLongPress) {
178   Widget widget;
179   Widget::InitParams init_params =
180       CreateParams(Widget::InitParams::TYPE_POPUP);
181   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
182   init_params.bounds = gfx::Rect(100, 100);
183   widget.Init(init_params);
184   internal::RootView* root_view =
185       static_cast<internal::RootView*>(widget.GetRootView());
186
187   // Create a view capable of showing the context menu with two children one of
188   // which handles all gesture events (e.g. a button).
189   TestContextMenuController controller;
190   View* parent_view = new View;
191   parent_view->set_context_menu_controller(&controller);
192   widget.SetContentsView(parent_view);
193
194   View* gesture_handling_child_view = new GestureHandlingView;
195   gesture_handling_child_view->SetBoundsRect(gfx::Rect(10, 10));
196   parent_view->AddChildView(gesture_handling_child_view);
197
198   View* other_child_view = new View;
199   other_child_view->SetBoundsRect(gfx::Rect(20, 0, 10, 10));
200   parent_view->AddChildView(other_child_view);
201
202   // |parent_view| should not show a context menu as a result of a long press on
203   // |gesture_handling_child_view|.
204   ui::GestureEvent long_press1(
205       5,
206       5,
207       0,
208       base::TimeDelta(),
209       ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
210   ui::EventDispatchDetails details = root_view->OnEventFromSource(&long_press1);
211
212   ui::GestureEvent end1(
213       5, 5, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_END));
214   details = root_view->OnEventFromSource(&end1);
215
216   EXPECT_FALSE(details.target_destroyed);
217   EXPECT_FALSE(details.dispatcher_destroyed);
218   EXPECT_EQ(0, controller.show_context_menu_calls());
219   controller.Reset();
220
221   // |parent_view| should show a context menu as a result of a long press on
222   // |other_child_view|.
223   ui::GestureEvent long_press2(
224       25,
225       5,
226       0,
227       base::TimeDelta(),
228       ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
229   details = root_view->OnEventFromSource(&long_press2);
230
231   ui::GestureEvent end2(
232       25, 5, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_END));
233   details = root_view->OnEventFromSource(&end2);
234
235   EXPECT_FALSE(details.target_destroyed);
236   EXPECT_FALSE(details.dispatcher_destroyed);
237   EXPECT_EQ(1, controller.show_context_menu_calls());
238   controller.Reset();
239
240   // |parent_view| should show a context menu as a result of a long press on
241   // itself.
242   ui::GestureEvent long_press3(
243       50,
244       50,
245       0,
246       base::TimeDelta(),
247       ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
248   details = root_view->OnEventFromSource(&long_press3);
249
250   ui::GestureEvent end3(
251       25, 5, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_END));
252   details = root_view->OnEventFromSource(&end3);
253
254   EXPECT_FALSE(details.target_destroyed);
255   EXPECT_FALSE(details.dispatcher_destroyed);
256   EXPECT_EQ(1, controller.show_context_menu_calls());
257 }
258
259 // Tests that context menus are not shown for disabled views on a long press.
260 TEST_F(RootViewTest, ContextMenuFromLongPressOnDisabledView) {
261   Widget widget;
262   Widget::InitParams init_params =
263       CreateParams(Widget::InitParams::TYPE_POPUP);
264   init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
265   init_params.bounds = gfx::Rect(100, 100);
266   widget.Init(init_params);
267   internal::RootView* root_view =
268       static_cast<internal::RootView*>(widget.GetRootView());
269
270   // Create a view capable of showing the context menu with two children one of
271   // which handles all gesture events (e.g. a button). Also mark this view
272   // as disabled.
273   TestContextMenuController controller;
274   View* parent_view = new View;
275   parent_view->set_context_menu_controller(&controller);
276   parent_view->SetEnabled(false);
277   widget.SetContentsView(parent_view);
278
279   View* gesture_handling_child_view = new GestureHandlingView;
280   gesture_handling_child_view->SetBoundsRect(gfx::Rect(10, 10));
281   parent_view->AddChildView(gesture_handling_child_view);
282
283   View* other_child_view = new View;
284   other_child_view->SetBoundsRect(gfx::Rect(20, 0, 10, 10));
285   parent_view->AddChildView(other_child_view);
286
287   // |parent_view| should not show a context menu as a result of a long press on
288   // |gesture_handling_child_view|.
289   ui::GestureEvent long_press1(
290       5,
291       5,
292       0,
293       base::TimeDelta(),
294       ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
295   ui::EventDispatchDetails details = root_view->OnEventFromSource(&long_press1);
296
297   ui::GestureEvent end1(
298       5, 5, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_END));
299   details = root_view->OnEventFromSource(&end1);
300
301   EXPECT_FALSE(details.target_destroyed);
302   EXPECT_FALSE(details.dispatcher_destroyed);
303   EXPECT_EQ(0, controller.show_context_menu_calls());
304   controller.Reset();
305
306   // |parent_view| should not show a context menu as a result of a long press on
307   // |other_child_view|.
308   ui::GestureEvent long_press2(
309       25,
310       5,
311       0,
312       base::TimeDelta(),
313       ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
314   details = root_view->OnEventFromSource(&long_press2);
315
316   ui::GestureEvent end2(
317       25, 5, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_END));
318   details = root_view->OnEventFromSource(&end2);
319
320   EXPECT_FALSE(details.target_destroyed);
321   EXPECT_FALSE(details.dispatcher_destroyed);
322   EXPECT_EQ(0, controller.show_context_menu_calls());
323   controller.Reset();
324
325   // |parent_view| should not show a context menu as a result of a long press on
326   // itself.
327   ui::GestureEvent long_press3(
328       50,
329       50,
330       0,
331       base::TimeDelta(),
332       ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
333   details = root_view->OnEventFromSource(&long_press3);
334
335   ui::GestureEvent end3(
336       25, 5, 0, base::TimeDelta(), ui::GestureEventDetails(ui::ET_GESTURE_END));
337   details = root_view->OnEventFromSource(&end3);
338
339   EXPECT_FALSE(details.target_destroyed);
340   EXPECT_FALSE(details.dispatcher_destroyed);
341   EXPECT_EQ(0, controller.show_context_menu_calls());
342 }
343
344 }  // namespace test
345 }  // namespace views