Infobar material design refresh: layout
[chromium-blink-merge.git] / chrome / browser / ui / views / menu_model_adapter_test.cc
blobd32c90871c5d1cda9b09d3e2ba012a22ec02d545
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 "base/callback.h"
6 #include "base/location.h"
7 #include "base/single_thread_task_runner.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "chrome/test/base/interactive_test_utils.h"
11 #include "chrome/test/base/ui_test_utils.h"
12 #include "chrome/test/base/view_event_test_base.h"
13 #include "ui/base/models/menu_model.h"
14 #include "ui/base/test/ui_controls.h"
15 #include "ui/views/controls/button/menu_button.h"
16 #include "ui/views/controls/button/menu_button_listener.h"
17 #include "ui/views/controls/menu/menu_controller.h"
18 #include "ui/views/controls/menu/menu_item_view.h"
19 #include "ui/views/controls/menu/menu_model_adapter.h"
20 #include "ui/views/controls/menu/menu_runner.h"
21 #include "ui/views/controls/menu/submenu_view.h"
22 #include "ui/views/widget/root_view.h"
23 #include "ui/views/widget/widget.h"
25 namespace {
27 const int kTopMenuBaseId = 100;
28 const int kSubMenuBaseId = 200;
30 // Implement most of the ui::MenuModel pure virtual methods for subclasses
32 // Exceptions:
33 // virtual int GetItemCount() const = 0;
34 // virtual ItemType GetTypeAt(int index) const = 0;
35 // virtual int GetCommandIdAt(int index) const = 0;
36 // virtual base::string16 GetLabelAt(int index) const = 0;
37 class CommonMenuModel : public ui::MenuModel {
38 public:
39 CommonMenuModel() {
42 ~CommonMenuModel() override {}
44 protected:
45 // ui::MenuModel implementation.
46 bool HasIcons() const override { return false; }
48 bool IsItemDynamicAt(int index) const override { return false; }
50 bool GetAcceleratorAt(int index,
51 ui::Accelerator* accelerator) const override {
52 return false;
55 ui::MenuSeparatorType GetSeparatorTypeAt(int index) const override {
56 return ui::NORMAL_SEPARATOR;
59 bool IsItemCheckedAt(int index) const override { return false; }
61 int GetGroupIdAt(int index) const override { return 0; }
63 bool GetIconAt(int index, gfx::Image* icon) override { return false; }
65 ui::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const override {
66 return NULL;
69 bool IsEnabledAt(int index) const override { return true; }
71 ui::MenuModel* GetSubmenuModelAt(int index) const override { return NULL; }
73 void HighlightChangedTo(int index) override {}
75 void ActivatedAt(int index) override {}
77 void SetMenuModelDelegate(ui::MenuModelDelegate* delegate) override {}
79 ui::MenuModelDelegate* GetMenuModelDelegate() const override { return NULL; }
81 private:
82 DISALLOW_COPY_AND_ASSIGN(CommonMenuModel);
85 class SubMenuModel : public CommonMenuModel {
86 public:
87 SubMenuModel()
88 : showing_(false) {
91 ~SubMenuModel() override {}
93 bool showing() const {
94 return showing_;
97 private:
98 // ui::MenuModel implementation.
99 int GetItemCount() const override { return 1; }
101 ItemType GetTypeAt(int index) const override { return TYPE_COMMAND; }
103 int GetCommandIdAt(int index) const override {
104 return index + kSubMenuBaseId;
107 base::string16 GetLabelAt(int index) const override {
108 return base::ASCIIToUTF16("Item");
111 void MenuWillShow() override { showing_ = true; }
113 // Called when the menu has been closed.
114 void MenuClosed() override { showing_ = false; }
116 bool showing_;
118 DISALLOW_COPY_AND_ASSIGN(SubMenuModel);
121 class TopMenuModel : public CommonMenuModel {
122 public:
123 TopMenuModel() {
126 ~TopMenuModel() override {}
128 bool IsSubmenuShowing() {
129 return sub_menu_model_.showing();
132 private:
133 // ui::MenuModel implementation.
134 int GetItemCount() const override { return 1; }
136 ItemType GetTypeAt(int index) const override { return TYPE_SUBMENU; }
138 int GetCommandIdAt(int index) const override {
139 return index + kTopMenuBaseId;
142 base::string16 GetLabelAt(int index) const override {
143 return base::ASCIIToUTF16("submenu");
146 MenuModel* GetSubmenuModelAt(int index) const override {
147 return &sub_menu_model_;
150 mutable SubMenuModel sub_menu_model_;
152 DISALLOW_COPY_AND_ASSIGN(TopMenuModel);
155 } // namespace
157 class MenuModelAdapterTest : public ViewEventTestBase,
158 public views::MenuButtonListener {
159 public:
160 MenuModelAdapterTest()
161 : ViewEventTestBase(),
162 button_(NULL),
163 menu_model_adapter_(&top_menu_model_),
164 menu_(NULL) {
167 ~MenuModelAdapterTest() override {}
169 // ViewEventTestBase implementation.
171 void SetUp() override {
172 button_ = new views::MenuButton(
173 NULL, base::ASCIIToUTF16("Menu Adapter Test"), this, true);
175 menu_ = menu_model_adapter_.CreateMenu();
176 menu_runner_.reset(
177 new views::MenuRunner(menu_, views::MenuRunner::HAS_MNEMONICS));
179 ViewEventTestBase::SetUp();
182 void TearDown() override {
183 menu_runner_.reset(NULL);
184 menu_ = NULL;
185 ViewEventTestBase::TearDown();
188 views::View* CreateContentsView() override { return button_; }
190 gfx::Size GetPreferredSize() const override {
191 return button_->GetPreferredSize();
194 // views::MenuButtonListener implementation.
195 void OnMenuButtonClicked(views::View* source,
196 const gfx::Point& point) override {
197 gfx::Point screen_location;
198 views::View::ConvertPointToScreen(source, &screen_location);
199 gfx::Rect bounds(screen_location, source->size());
200 ignore_result(menu_runner_->RunMenuAt(source->GetWidget(),
201 button_,
202 bounds,
203 views::MENU_ANCHOR_TOPLEFT,
204 ui::MENU_SOURCE_NONE));
207 // ViewEventTestBase implementation
208 void DoTestOnMessageLoop() override {
209 Click(button_, CreateEventTask(this, &MenuModelAdapterTest::Step1));
212 // Open the submenu.
213 void Step1() {
214 views::SubmenuView* topmenu = menu_->GetSubmenu();
215 ASSERT_TRUE(topmenu);
216 ASSERT_TRUE(topmenu->IsShowing());
217 ASSERT_FALSE(top_menu_model_.IsSubmenuShowing());
219 // Click the first item to open the submenu.
220 views::MenuItemView* item = topmenu->GetMenuItemAt(0);
221 ASSERT_TRUE(item);
222 Click(item, CreateEventTask(this, &MenuModelAdapterTest::Step2));
225 // Rebuild the menu which should close the submenu.
226 void Step2() {
227 views::SubmenuView* topmenu = menu_->GetSubmenu();
228 ASSERT_TRUE(topmenu);
229 ASSERT_TRUE(topmenu->IsShowing());
230 ASSERT_TRUE(top_menu_model_.IsSubmenuShowing());
232 menu_model_adapter_.BuildMenu(menu_);
234 base::MessageLoopForUI::current()->task_runner()->PostTask(
235 FROM_HERE, CreateEventTask(this, &MenuModelAdapterTest::Step3));
238 // Verify that the submenu MenuModel received the close callback
239 // and close the menu.
240 void Step3() {
241 views::SubmenuView* topmenu = menu_->GetSubmenu();
242 ASSERT_TRUE(topmenu);
243 ASSERT_TRUE(topmenu->IsShowing());
244 ASSERT_FALSE(top_menu_model_.IsSubmenuShowing());
246 // Click the button to exit the menu.
247 Click(button_, CreateEventTask(this, &MenuModelAdapterTest::Step4));
250 // All done.
251 void Step4() {
252 views::SubmenuView* topmenu = menu_->GetSubmenu();
253 ASSERT_TRUE(topmenu);
254 ASSERT_FALSE(topmenu->IsShowing());
255 ASSERT_FALSE(top_menu_model_.IsSubmenuShowing());
257 Done();
260 private:
261 // Generate a mouse click on the specified view and post a new task.
262 virtual void Click(views::View* view, const base::Closure& next) {
263 ui_test_utils::MoveMouseToCenterAndPress(
264 view,
265 ui_controls::LEFT,
266 ui_controls::DOWN | ui_controls::UP,
267 next);
270 views::MenuButton* button_;
271 TopMenuModel top_menu_model_;
272 views::MenuModelAdapter menu_model_adapter_;
273 views::MenuItemView* menu_;
274 scoped_ptr<views::MenuRunner> menu_runner_;
277 #if defined(OS_WIN)
278 // flaky on Windows - http://crbug.com/523255
279 #define MAYBE_RebuildMenu DISABLED_RebuildMenu
280 #else
281 #define MAYBE_RebuildMenu RebuildMenu
282 #endif
283 VIEW_TEST(MenuModelAdapterTest, MAYBE_RebuildMenu)