OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "ui/views/controls/menu/menu_runner_impl_cocoa.h" | 5 #import "ui/views/controls/menu/menu_runner_impl_cocoa.h" |
6 | 6 |
7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
8 | 8 |
9 #include "base/macros.h" | 9 #include "base/macros.h" |
10 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
11 #import "testing/gtest_mac.h" | 11 #import "testing/gtest_mac.h" |
12 #include "ui/base/models/simple_menu_model.h" | 12 #include "ui/base/models/simple_menu_model.h" |
13 #include "ui/events/event_utils.h" | 13 #include "ui/events/event_utils.h" |
14 #include "ui/views/test/views_test_base.h" | 14 #include "ui/views/test/views_test_base.h" |
15 | 15 |
16 namespace views { | 16 namespace views { |
17 namespace test { | 17 namespace test { |
18 namespace { | 18 namespace { |
19 | 19 |
20 class TestModel : public ui::SimpleMenuModel { | 20 class TestModel : public ui::SimpleMenuModel { |
21 public: | 21 public: |
22 TestModel() : ui::SimpleMenuModel(&delegate_), delegate_(this) {} | 22 TestModel() : ui::SimpleMenuModel(&delegate_), delegate_(this) {} |
23 | 23 |
24 void set_checked_command(int command) { checked_command_ = command; } | 24 void set_checked_command(int command) { checked_command_ = command; } |
25 | 25 |
| 26 void set_menu_open_callback(const base::Closure& callback) { |
| 27 menu_open_callback_ = callback; |
| 28 } |
| 29 |
26 private: | 30 private: |
27 class Delegate : public ui::SimpleMenuModel::Delegate { | 31 class Delegate : public ui::SimpleMenuModel::Delegate { |
28 public: | 32 public: |
29 explicit Delegate(TestModel* model) : model_(model) {} | 33 explicit Delegate(TestModel* model) : model_(model) {} |
30 bool IsCommandIdChecked(int command_id) const override { | 34 bool IsCommandIdChecked(int command_id) const override { |
31 return command_id == model_->checked_command_; | 35 return command_id == model_->checked_command_; |
32 } | 36 } |
33 bool IsCommandIdEnabled(int command_id) const override { return true; } | 37 bool IsCommandIdEnabled(int command_id) const override { return true; } |
34 bool GetAcceleratorForCommandId(int command_id, | 38 bool GetAcceleratorForCommandId(int command_id, |
35 ui::Accelerator* accelerator) override { | 39 ui::Accelerator* accelerator) override { |
36 return false; | 40 return false; |
37 } | 41 } |
38 void ExecuteCommand(int command_id, int event_flags) override {} | 42 void ExecuteCommand(int command_id, int event_flags) override {} |
39 | 43 |
| 44 void MenuWillShow(SimpleMenuModel* source) override { |
| 45 model_->menu_open_callback_.Run(); |
| 46 } |
| 47 |
40 private: | 48 private: |
41 TestModel* model_; | 49 TestModel* model_; |
42 | 50 |
43 DISALLOW_COPY_AND_ASSIGN(Delegate); | 51 DISALLOW_COPY_AND_ASSIGN(Delegate); |
44 }; | 52 }; |
45 | 53 |
46 private: | 54 private: |
47 int checked_command_ = -1; | 55 int checked_command_ = -1; |
48 Delegate delegate_; | 56 Delegate delegate_; |
| 57 base::Closure menu_open_callback_; |
49 | 58 |
50 DISALLOW_COPY_AND_ASSIGN(TestModel); | 59 DISALLOW_COPY_AND_ASSIGN(TestModel); |
51 }; | 60 }; |
52 | 61 |
53 } // namespace | 62 } // namespace |
54 | 63 |
55 class MenuRunnerCocoaTest : public ViewsTestBase { | 64 class MenuRunnerCocoaTest : public ViewsTestBase { |
56 public: | 65 public: |
57 enum { | 66 enum { |
58 kWindowHeight = 200, | 67 kWindowHeight = 200, |
(...skipping 23 matching lines...) Expand all Loading... |
82 void TearDown() override { | 91 void TearDown() override { |
83 if (runner_) { | 92 if (runner_) { |
84 runner_->Release(); | 93 runner_->Release(); |
85 runner_ = NULL; | 94 runner_ = NULL; |
86 } | 95 } |
87 | 96 |
88 parent_->CloseNow(); | 97 parent_->CloseNow(); |
89 ViewsTestBase::TearDown(); | 98 ViewsTestBase::TearDown(); |
90 } | 99 } |
91 | 100 |
92 // Runs the menu after scheduling |block| on the run loop. | 101 // Runs the menu after registering |callback| as the menu open callback. |
93 MenuRunner::RunResult RunMenu(dispatch_block_t block) { | 102 MenuRunner::RunResult RunMenu(const base::Closure& callback) { |
94 CFRunLoopPerformBlock(CFRunLoopGetCurrent(), kCFRunLoopCommonModes, ^{ | 103 menu_->set_menu_open_callback( |
95 EXPECT_TRUE(runner_->IsRunning()); | 104 base::Bind(&MenuRunnerCocoaTest::RunMenuWrapperCallback, |
96 block(); | 105 base::Unretained(this), callback)); |
97 }); | 106 return runner_->RunMenuAt(parent_, nullptr, gfx::Rect(), |
98 return runner_->RunMenuAt(parent_, NULL, gfx::Rect(), MENU_ANCHOR_TOPLEFT, | 107 MENU_ANCHOR_TOPLEFT, MenuRunner::CONTEXT_MENU); |
99 MenuRunner::CONTEXT_MENU); | |
100 } | 108 } |
101 | 109 |
102 // Runs then cancels a combobox menu and captures the frame of the anchoring | 110 // Runs then cancels a combobox menu and captures the frame of the anchoring |
103 // view. | 111 // view. |
104 MenuRunner::RunResult RunMenuAt(const gfx::Rect& anchor) { | 112 MenuRunner::RunResult RunMenuAt(const gfx::Rect& anchor) { |
105 last_anchor_frame_ = NSZeroRect; | 113 last_anchor_frame_ = NSZeroRect; |
106 | 114 |
107 // Should be one child (the compositor layer) before showing, and it should | 115 // Should be one child (the compositor layer) before showing, and it should |
108 // go up by one (the anchor view) while the menu is shown. | 116 // go up by one (the anchor view) while the menu is shown. |
109 EXPECT_EQ(1u, [[parent_->GetNativeView() subviews] count]); | 117 EXPECT_EQ(1u, [[parent_->GetNativeView() subviews] count]); |
110 CFRunLoopPerformBlock(CFRunLoopGetCurrent(), kCFRunLoopCommonModes, ^{ | 118 |
111 NSArray* subviews = [parent_->GetNativeView() subviews]; | 119 menu_->set_menu_open_callback(base::Bind( |
112 EXPECT_EQ(2u, [subviews count]); | 120 &MenuRunnerCocoaTest::RunMenuAtCallback, base::Unretained(this))); |
113 last_anchor_frame_ = [[subviews objectAtIndex:1] frame]; | 121 |
114 runner_->Cancel(); | |
115 }); | |
116 MenuRunner::RunResult result = runner_->RunMenuAt( | 122 MenuRunner::RunResult result = runner_->RunMenuAt( |
117 parent_, nullptr, anchor, MENU_ANCHOR_TOPLEFT, MenuRunner::COMBOBOX); | 123 parent_, nullptr, anchor, MENU_ANCHOR_TOPLEFT, MenuRunner::COMBOBOX); |
118 | 124 |
119 // Ensure the anchor view is removed. | 125 // Ensure the anchor view is removed. |
120 EXPECT_EQ(1u, [[parent_->GetNativeView() subviews] count]); | 126 EXPECT_EQ(1u, [[parent_->GetNativeView() subviews] count]); |
121 return result; | 127 return result; |
122 } | 128 } |
123 | 129 |
| 130 void MenuCancelCallback() { |
| 131 runner_->Cancel(); |
| 132 EXPECT_FALSE(runner_->IsRunning()); |
| 133 } |
| 134 |
| 135 void MenuDeleteCallback() { |
| 136 runner_->Release(); |
| 137 runner_ = nullptr; |
| 138 } |
| 139 |
124 protected: | 140 protected: |
125 scoped_ptr<TestModel> menu_; | 141 scoped_ptr<TestModel> menu_; |
126 internal::MenuRunnerImplCocoa* runner_ = nullptr; | 142 internal::MenuRunnerImplCocoa* runner_ = nullptr; |
127 views::Widget* parent_ = nullptr; | 143 views::Widget* parent_ = nullptr; |
128 NSRect last_anchor_frame_ = NSZeroRect; | 144 NSRect last_anchor_frame_ = NSZeroRect; |
129 | 145 |
130 private: | 146 private: |
| 147 void RunMenuWrapperCallback(const base::Closure& callback) { |
| 148 EXPECT_TRUE(runner_->IsRunning()); |
| 149 callback.Run(); |
| 150 } |
| 151 |
| 152 void RunMenuAtCallback() { |
| 153 NSArray* subviews = [parent_->GetNativeView() subviews]; |
| 154 EXPECT_EQ(2u, [subviews count]); |
| 155 last_anchor_frame_ = [[subviews objectAtIndex:1] frame]; |
| 156 runner_->Cancel(); |
| 157 } |
| 158 |
131 DISALLOW_COPY_AND_ASSIGN(MenuRunnerCocoaTest); | 159 DISALLOW_COPY_AND_ASSIGN(MenuRunnerCocoaTest); |
132 }; | 160 }; |
133 | 161 |
134 TEST_F(MenuRunnerCocoaTest, RunMenuAndCancel) { | 162 TEST_F(MenuRunnerCocoaTest, RunMenuAndCancel) { |
135 base::TimeDelta min_time = ui::EventTimeForNow(); | 163 base::TimeDelta min_time = ui::EventTimeForNow(); |
136 | 164 |
137 MenuRunner::RunResult result = RunMenu(^{ | 165 MenuRunner::RunResult result = RunMenu(base::Bind( |
138 runner_->Cancel(); | 166 &MenuRunnerCocoaTest::MenuCancelCallback, base::Unretained(this))); |
139 EXPECT_FALSE(runner_->IsRunning()); | |
140 }); | |
141 | 167 |
142 EXPECT_EQ(MenuRunner::NORMAL_EXIT, result); | 168 EXPECT_EQ(MenuRunner::NORMAL_EXIT, result); |
143 EXPECT_FALSE(runner_->IsRunning()); | 169 EXPECT_FALSE(runner_->IsRunning()); |
144 | 170 |
145 EXPECT_GE(runner_->GetClosingEventTime(), min_time); | 171 EXPECT_GE(runner_->GetClosingEventTime(), min_time); |
146 EXPECT_LE(runner_->GetClosingEventTime(), ui::EventTimeForNow()); | 172 EXPECT_LE(runner_->GetClosingEventTime(), ui::EventTimeForNow()); |
147 | 173 |
148 // Cancel again. | 174 // Cancel again. |
149 runner_->Cancel(); | 175 runner_->Cancel(); |
150 EXPECT_FALSE(runner_->IsRunning()); | 176 EXPECT_FALSE(runner_->IsRunning()); |
151 } | 177 } |
152 | 178 |
153 TEST_F(MenuRunnerCocoaTest, RunMenuAndDelete) { | 179 TEST_F(MenuRunnerCocoaTest, RunMenuAndDelete) { |
154 MenuRunner::RunResult result = RunMenu(^{ | 180 MenuRunner::RunResult result = RunMenu(base::Bind( |
155 runner_->Release(); | 181 &MenuRunnerCocoaTest::MenuDeleteCallback, base::Unretained(this))); |
156 runner_ = NULL; | |
157 }); | |
158 | |
159 EXPECT_EQ(MenuRunner::MENU_DELETED, result); | 182 EXPECT_EQ(MenuRunner::MENU_DELETED, result); |
160 } | 183 } |
161 | 184 |
162 TEST_F(MenuRunnerCocoaTest, RunMenuTwice) { | 185 TEST_F(MenuRunnerCocoaTest, RunMenuTwice) { |
163 for (int i = 0; i < 2; ++i) { | 186 for (int i = 0; i < 2; ++i) { |
164 MenuRunner::RunResult result = RunMenu(^{ | 187 MenuRunner::RunResult result = RunMenu(base::Bind( |
165 runner_->Cancel(); | 188 &MenuRunnerCocoaTest::MenuCancelCallback, base::Unretained(this))); |
166 }); | |
167 EXPECT_EQ(MenuRunner::NORMAL_EXIT, result); | 189 EXPECT_EQ(MenuRunner::NORMAL_EXIT, result); |
168 EXPECT_FALSE(runner_->IsRunning()); | 190 EXPECT_FALSE(runner_->IsRunning()); |
169 } | 191 } |
170 } | 192 } |
171 | 193 |
172 TEST_F(MenuRunnerCocoaTest, CancelWithoutRunning) { | 194 TEST_F(MenuRunnerCocoaTest, CancelWithoutRunning) { |
173 runner_->Cancel(); | 195 runner_->Cancel(); |
174 EXPECT_FALSE(runner_->IsRunning()); | 196 EXPECT_FALSE(runner_->IsRunning()); |
175 EXPECT_EQ(base::TimeDelta(), runner_->GetClosingEventTime()); | 197 EXPECT_EQ(base::TimeDelta(), runner_->GetClosingEventTime()); |
176 } | 198 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 // In RTL, Cocoa messes up the positioning unless the anchor rectangle is | 239 // In RTL, Cocoa messes up the positioning unless the anchor rectangle is |
218 // offset to the right of the view. The offset for the checkmark is also | 240 // offset to the right of the view. The offset for the checkmark is also |
219 // skipped, to give a better match to native behavior. | 241 // skipped, to give a better match to native behavior. |
220 base::i18n::SetICUDefaultLocale("he"); | 242 base::i18n::SetICUDefaultLocale("he"); |
221 RunMenuAt(anchor_rect); | 243 RunMenuAt(anchor_rect); |
222 EXPECT_EQ(combobox_rect.right(), last_anchor_frame_.origin.x); | 244 EXPECT_EQ(combobox_rect.right(), last_anchor_frame_.origin.x); |
223 } | 245 } |
224 | 246 |
225 } // namespace test | 247 } // namespace test |
226 } // namespace views | 248 } // namespace views |
OLD | NEW |