• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/callback.h"
6 #include "base/strings/utf_string_conversions.h"
7 #include "chrome/test/base/interactive_test_utils.h"
8 #include "chrome/test/base/ui_test_utils.h"
9 #include "chrome/test/base/view_event_test_base.h"
10 #include "ui/base/models/menu_model.h"
11 #include "ui/base/test/ui_controls.h"
12 #include "ui/views/controls/button/menu_button.h"
13 #include "ui/views/controls/button/menu_button_listener.h"
14 #include "ui/views/controls/menu/menu_controller.h"
15 #include "ui/views/controls/menu/menu_item_view.h"
16 #include "ui/views/controls/menu/menu_model_adapter.h"
17 #include "ui/views/controls/menu/menu_runner.h"
18 #include "ui/views/controls/menu/submenu_view.h"
19 #include "ui/views/widget/root_view.h"
20 #include "ui/views/widget/widget.h"
21 
22 namespace {
23 
24 const int kTopMenuBaseId = 100;
25 const int kSubMenuBaseId = 200;
26 
27 // Implement most of the ui::MenuModel pure virtual methods for subclasses
28 //
29 // Exceptions:
30 //  virtual int GetItemCount() const = 0;
31 //  virtual ItemType GetTypeAt(int index) const = 0;
32 //  virtual int GetCommandIdAt(int index) const = 0;
33 //  virtual base::string16 GetLabelAt(int index) const = 0;
34 class CommonMenuModel : public ui::MenuModel {
35  public:
CommonMenuModel()36   CommonMenuModel() {
37   }
38 
~CommonMenuModel()39   virtual ~CommonMenuModel() {
40   }
41 
42  protected:
43   // ui::MenuModel implementation.
HasIcons() const44   virtual bool HasIcons() const OVERRIDE {
45     return false;
46   }
47 
IsItemDynamicAt(int index) const48   virtual bool IsItemDynamicAt(int index) const OVERRIDE {
49     return false;
50   }
51 
GetAcceleratorAt(int index,ui::Accelerator * accelerator) const52   virtual bool GetAcceleratorAt(int index,
53                                 ui::Accelerator* accelerator) const OVERRIDE {
54     return false;
55   }
56 
GetSeparatorTypeAt(int index) const57   virtual ui::MenuSeparatorType GetSeparatorTypeAt(int index) const OVERRIDE {
58     return ui::NORMAL_SEPARATOR;
59   }
60 
IsItemCheckedAt(int index) const61   virtual bool IsItemCheckedAt(int index) const OVERRIDE {
62     return false;
63   }
64 
GetGroupIdAt(int index) const65   virtual int GetGroupIdAt(int index) const OVERRIDE {
66     return 0;
67   }
68 
GetIconAt(int index,gfx::Image * icon)69   virtual bool GetIconAt(int index, gfx::Image* icon) OVERRIDE {
70     return false;
71   }
72 
GetButtonMenuItemAt(int index) const73   virtual ui::ButtonMenuItemModel* GetButtonMenuItemAt(
74       int index) const OVERRIDE {
75     return NULL;
76   }
77 
IsEnabledAt(int index) const78   virtual bool IsEnabledAt(int index) const OVERRIDE {
79     return true;
80   }
81 
GetSubmenuModelAt(int index) const82   virtual ui::MenuModel* GetSubmenuModelAt(int index) const OVERRIDE {
83     return NULL;
84   }
85 
HighlightChangedTo(int index)86   virtual void HighlightChangedTo(int index) OVERRIDE {
87   }
88 
ActivatedAt(int index)89   virtual void ActivatedAt(int index) OVERRIDE {
90   }
91 
SetMenuModelDelegate(ui::MenuModelDelegate * delegate)92   virtual void SetMenuModelDelegate(ui::MenuModelDelegate* delegate) OVERRIDE {
93   }
94 
GetMenuModelDelegate() const95   virtual ui::MenuModelDelegate* GetMenuModelDelegate() const OVERRIDE {
96     return NULL;
97   }
98 
99  private:
100   DISALLOW_COPY_AND_ASSIGN(CommonMenuModel);
101 };
102 
103 class SubMenuModel : public CommonMenuModel {
104  public:
SubMenuModel()105   SubMenuModel()
106       : showing_(false) {
107   }
108 
~SubMenuModel()109   virtual ~SubMenuModel() {
110   }
111 
showing() const112   bool showing() const {
113     return showing_;
114   }
115 
116  private:
117   // ui::MenuModel implementation.
GetItemCount() const118   virtual int GetItemCount() const OVERRIDE {
119     return 1;
120   }
121 
GetTypeAt(int index) const122   virtual ItemType GetTypeAt(int index) const OVERRIDE {
123     return TYPE_COMMAND;
124   }
125 
GetCommandIdAt(int index) const126   virtual int GetCommandIdAt(int index) const OVERRIDE {
127     return index + kSubMenuBaseId;
128   }
129 
GetLabelAt(int index) const130   virtual base::string16 GetLabelAt(int index) const OVERRIDE {
131     return base::ASCIIToUTF16("Item");
132   }
133 
MenuWillShow()134   virtual void MenuWillShow() OVERRIDE {
135     showing_ = true;
136   }
137 
138   // Called when the menu has been closed.
MenuClosed()139   virtual void MenuClosed() OVERRIDE {
140     showing_ = false;
141   }
142 
143   bool showing_;
144 
145   DISALLOW_COPY_AND_ASSIGN(SubMenuModel);
146 };
147 
148 class TopMenuModel : public CommonMenuModel {
149  public:
TopMenuModel()150   TopMenuModel() {
151   }
152 
~TopMenuModel()153   virtual ~TopMenuModel() {
154   }
155 
IsSubmenuShowing()156   bool IsSubmenuShowing() {
157     return sub_menu_model_.showing();
158   }
159 
160  private:
161   // ui::MenuModel implementation.
GetItemCount() const162   virtual int GetItemCount() const OVERRIDE {
163     return 1;
164   }
165 
GetTypeAt(int index) const166   virtual ItemType GetTypeAt(int index) const OVERRIDE {
167     return TYPE_SUBMENU;
168   }
169 
GetCommandIdAt(int index) const170   virtual int GetCommandIdAt(int index) const OVERRIDE {
171     return index + kTopMenuBaseId;
172   }
173 
GetLabelAt(int index) const174   virtual base::string16 GetLabelAt(int index) const OVERRIDE {
175     return base::ASCIIToUTF16("submenu");
176   }
177 
GetSubmenuModelAt(int index) const178   virtual MenuModel* GetSubmenuModelAt(int index) const OVERRIDE {
179     return &sub_menu_model_;
180   }
181 
182   mutable SubMenuModel sub_menu_model_;
183 
184   DISALLOW_COPY_AND_ASSIGN(TopMenuModel);
185 };
186 
187 }  // namespace
188 
189 class MenuModelAdapterTest : public ViewEventTestBase,
190                              public views::MenuButtonListener {
191  public:
MenuModelAdapterTest()192   MenuModelAdapterTest()
193       : ViewEventTestBase(),
194         button_(NULL),
195         menu_model_adapter_(&top_menu_model_),
196         menu_(NULL) {
197   }
198 
~MenuModelAdapterTest()199   virtual ~MenuModelAdapterTest() {
200   }
201 
202   // ViewEventTestBase implementation.
203 
SetUp()204   virtual void SetUp() OVERRIDE {
205     button_ = new views::MenuButton(
206         NULL, base::ASCIIToUTF16("Menu Adapter Test"), this, true);
207 
208     menu_ = menu_model_adapter_.CreateMenu();
209     menu_runner_.reset(new views::MenuRunner(menu_));
210 
211     ViewEventTestBase::SetUp();
212   }
213 
TearDown()214   virtual void TearDown() OVERRIDE {
215     menu_runner_.reset(NULL);
216     menu_ = NULL;
217     ViewEventTestBase::TearDown();
218   }
219 
CreateContentsView()220   virtual views::View* CreateContentsView() OVERRIDE {
221     return button_;
222   }
223 
GetPreferredSize() const224   virtual gfx::Size GetPreferredSize() const OVERRIDE {
225     return button_->GetPreferredSize();
226   }
227 
228   // views::MenuButtonListener implementation.
OnMenuButtonClicked(views::View * source,const gfx::Point & point)229   virtual void OnMenuButtonClicked(views::View* source,
230                                    const gfx::Point& point) OVERRIDE {
231     gfx::Point screen_location;
232     views::View::ConvertPointToScreen(source, &screen_location);
233     gfx::Rect bounds(screen_location, source->size());
234     ignore_result(menu_runner_->RunMenuAt(source->GetWidget(),
235                                           button_,
236                                           bounds,
237                                           views::MENU_ANCHOR_TOPLEFT,
238                                           ui::MENU_SOURCE_NONE,
239                                           views::MenuRunner::HAS_MNEMONICS));
240   }
241 
242   // ViewEventTestBase implementation
DoTestOnMessageLoop()243   virtual void DoTestOnMessageLoop() OVERRIDE {
244     Click(button_, CreateEventTask(this, &MenuModelAdapterTest::Step1));
245   }
246 
247   // Open the submenu.
Step1()248   void Step1() {
249     views::SubmenuView* topmenu = menu_->GetSubmenu();
250     ASSERT_TRUE(topmenu);
251     ASSERT_TRUE(topmenu->IsShowing());
252     ASSERT_FALSE(top_menu_model_.IsSubmenuShowing());
253 
254     // Click the first item to open the submenu.
255     views::MenuItemView* item = topmenu->GetMenuItemAt(0);
256     ASSERT_TRUE(item);
257     Click(item, CreateEventTask(this, &MenuModelAdapterTest::Step2));
258   }
259 
260   // Rebuild the menu which should close the submenu.
Step2()261   void Step2() {
262     views::SubmenuView* topmenu = menu_->GetSubmenu();
263     ASSERT_TRUE(topmenu);
264     ASSERT_TRUE(topmenu->IsShowing());
265     ASSERT_TRUE(top_menu_model_.IsSubmenuShowing());
266 
267     menu_model_adapter_.BuildMenu(menu_);
268 
269     base::MessageLoopForUI::current()->PostTask(
270         FROM_HERE, CreateEventTask(this, &MenuModelAdapterTest::Step3));
271   }
272 
273   // Verify that the submenu MenuModel received the close callback
274   // and close the menu.
Step3()275   void Step3() {
276     views::SubmenuView* topmenu = menu_->GetSubmenu();
277     ASSERT_TRUE(topmenu);
278     ASSERT_TRUE(topmenu->IsShowing());
279     ASSERT_FALSE(top_menu_model_.IsSubmenuShowing());
280 
281     // Click the button to exit the menu.
282     Click(button_, CreateEventTask(this, &MenuModelAdapterTest::Step4));
283   }
284 
285   // All done.
Step4()286   void Step4() {
287     views::SubmenuView* topmenu = menu_->GetSubmenu();
288     ASSERT_TRUE(topmenu);
289     ASSERT_FALSE(topmenu->IsShowing());
290     ASSERT_FALSE(top_menu_model_.IsSubmenuShowing());
291 
292     Done();
293   }
294 
295  private:
296   // Generate a mouse click on the specified view and post a new task.
Click(views::View * view,const base::Closure & next)297   virtual void Click(views::View* view, const base::Closure& next) {
298     ui_test_utils::MoveMouseToCenterAndPress(
299         view,
300         ui_controls::LEFT,
301         ui_controls::DOWN | ui_controls::UP,
302         next);
303   }
304 
305   views::MenuButton* button_;
306   TopMenuModel top_menu_model_;
307   views::MenuModelAdapter menu_model_adapter_;
308   views::MenuItemView* menu_;
309   scoped_ptr<views::MenuRunner> menu_runner_;
310 };
311 
312 VIEW_TEST(MenuModelAdapterTest, RebuildMenu)
313