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 #import "ui/base/cocoa/menu_controller.h" | |
12 #include "ui/base/models/simple_menu_model.h" | 13 #include "ui/base/models/simple_menu_model.h" |
13 #include "ui/events/event_utils.h" | 14 #include "ui/events/event_utils.h" |
14 #include "ui/views/test/views_test_base.h" | 15 #include "ui/views/test/views_test_base.h" |
15 | 16 |
17 // A helper class to handle menu open notifications. | |
18 @interface MenuOpenWatcher : NSObject { | |
19 dispatch_block_t openCallback_; | |
tapted
2016/03/24 02:10:36
nit: @private
| |
20 } | |
21 | |
22 // Method to handle menu open notification. | |
23 - (void)menuWillOpen:(NSNotification*)notification; | |
24 | |
25 // Block to be invoked on menu open notification. Weak. Clients must ensure that | |
26 // it remains in a valid state. | |
27 @property(nonatomic, assign) dispatch_block_t openCallback; | |
28 | |
29 @end | |
30 | |
31 @implementation MenuOpenWatcher | |
32 | |
33 @synthesize openCallback = openCallback_; | |
34 | |
35 - (id)init { | |
36 if (self = [super init]) { | |
tapted
2016/03/24 02:10:36
nit: extra parens around assignment used as condit
| |
37 [[NSNotificationCenter defaultCenter] | |
38 addObserver:self | |
39 selector:@selector(menuWillOpen:) | |
40 name:kMenuControllerMenuWillOpenNotification | |
41 object:nil]; | |
42 } | |
43 return self; | |
44 } | |
45 | |
46 - (void)dealloc { | |
47 [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
48 [super dealloc]; | |
49 } | |
50 | |
51 - (void)menuWillOpen:(NSNotification*)notification { | |
52 if (openCallback_) | |
53 openCallback_(); | |
54 } | |
55 | |
56 @end | |
57 | |
16 namespace views { | 58 namespace views { |
17 namespace test { | 59 namespace test { |
18 namespace { | 60 namespace { |
19 | 61 |
20 class TestModel : public ui::SimpleMenuModel { | 62 class TestModel : public ui::SimpleMenuModel { |
tapted
2016/03/24 02:10:36
Can we override MenuModel::MenuWillShow? Here, or
karandeepb
2016/04/06 05:52:48
Done. Though the code looks slightly uglier now si
| |
21 public: | 63 public: |
22 TestModel() : ui::SimpleMenuModel(&delegate_), delegate_(this) {} | 64 TestModel() : ui::SimpleMenuModel(&delegate_), delegate_(this) {} |
23 | 65 |
24 void set_checked_command(int command) { checked_command_ = command; } | 66 void set_checked_command(int command) { checked_command_ = command; } |
25 | 67 |
26 private: | 68 private: |
27 class Delegate : public ui::SimpleMenuModel::Delegate { | 69 class Delegate : public ui::SimpleMenuModel::Delegate { |
28 public: | 70 public: |
29 explicit Delegate(TestModel* model) : model_(model) {} | 71 explicit Delegate(TestModel* model) : model_(model) {} |
30 bool IsCommandIdChecked(int command_id) const override { | 72 bool IsCommandIdChecked(int command_id) const override { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
70 menu_->AddCheckItem(0, base::ASCIIToUTF16("Menu Item")); | 112 menu_->AddCheckItem(0, base::ASCIIToUTF16("Menu Item")); |
71 | 113 |
72 parent_ = new views::Widget(); | 114 parent_ = new views::Widget(); |
73 parent_->Init(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS)); | 115 parent_->Init(CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS)); |
74 parent_->SetBounds( | 116 parent_->SetBounds( |
75 gfx::Rect(kWindowOffset, kWindowOffset, kWindowWidth, kWindowHeight)); | 117 gfx::Rect(kWindowOffset, kWindowOffset, kWindowWidth, kWindowHeight)); |
76 parent_->Show(); | 118 parent_->Show(); |
77 | 119 |
78 runner_ = new internal::MenuRunnerImplCocoa(menu_.get()); | 120 runner_ = new internal::MenuRunnerImplCocoa(menu_.get()); |
79 EXPECT_FALSE(runner_->IsRunning()); | 121 EXPECT_FALSE(runner_->IsRunning()); |
122 menu_watcher_.reset([[MenuOpenWatcher alloc] init]); | |
80 } | 123 } |
81 | 124 |
82 void TearDown() override { | 125 void TearDown() override { |
83 if (runner_) { | 126 if (runner_) { |
84 runner_->Release(); | 127 runner_->Release(); |
85 runner_ = NULL; | 128 runner_ = NULL; |
86 } | 129 } |
87 | 130 |
88 parent_->CloseNow(); | 131 parent_->CloseNow(); |
89 ViewsTestBase::TearDown(); | 132 ViewsTestBase::TearDown(); |
90 } | 133 } |
91 | 134 |
92 // Runs the menu after scheduling |block| on the run loop. | 135 // Runs the menu after scheduling |block| on the run loop. |
93 MenuRunner::RunResult RunMenu(dispatch_block_t block) { | 136 MenuRunner::RunResult RunMenu(dispatch_block_t block) { |
94 CFRunLoopPerformBlock(CFRunLoopGetCurrent(), kCFRunLoopCommonModes, ^{ | 137 [menu_watcher_ setOpenCallback:^{ |
95 EXPECT_TRUE(runner_->IsRunning()); | 138 EXPECT_TRUE(runner_->IsRunning()); |
96 block(); | 139 block(); |
97 }); | 140 }]; |
98 return runner_->RunMenuAt(parent_, NULL, gfx::Rect(), MENU_ANCHOR_TOPLEFT, | 141 MenuRunner::RunResult result = |
99 MenuRunner::CONTEXT_MENU); | 142 runner_->RunMenuAt(parent_, NULL, gfx::Rect(), MENU_ANCHOR_TOPLEFT, |
tapted
2016/03/24 02:10:36
nit (while you're here) NULL -> nullptr
karandeepb
2016/04/06 05:52:48
Done.
| |
143 MenuRunner::CONTEXT_MENU); | |
144 [menu_watcher_ setOpenCallback:nil]; | |
145 return result; | |
100 } | 146 } |
101 | 147 |
102 // Runs then cancels a combobox menu and captures the frame of the anchoring | 148 // Runs then cancels a combobox menu and captures the frame of the anchoring |
103 // view. | 149 // view. |
104 MenuRunner::RunResult RunMenuAt(const gfx::Rect& anchor) { | 150 MenuRunner::RunResult RunMenuAt(const gfx::Rect& anchor) { |
105 last_anchor_frame_ = NSZeroRect; | 151 last_anchor_frame_ = NSZeroRect; |
106 | 152 |
107 // Should be one child (the compositor layer) before showing, and it should | 153 // 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. | 154 // go up by one (the anchor view) while the menu is shown. |
109 EXPECT_EQ(1u, [[parent_->GetNativeView() subviews] count]); | 155 EXPECT_EQ(1u, [[parent_->GetNativeView() subviews] count]); |
110 CFRunLoopPerformBlock(CFRunLoopGetCurrent(), kCFRunLoopCommonModes, ^{ | 156 |
157 [menu_watcher_ setOpenCallback:^{ | |
111 NSArray* subviews = [parent_->GetNativeView() subviews]; | 158 NSArray* subviews = [parent_->GetNativeView() subviews]; |
112 EXPECT_EQ(2u, [subviews count]); | 159 EXPECT_EQ(2u, [subviews count]); |
113 last_anchor_frame_ = [[subviews objectAtIndex:1] frame]; | 160 last_anchor_frame_ = [[subviews objectAtIndex:1] frame]; |
114 runner_->Cancel(); | 161 runner_->Cancel(); |
115 }); | 162 }]; |
163 | |
116 MenuRunner::RunResult result = runner_->RunMenuAt( | 164 MenuRunner::RunResult result = runner_->RunMenuAt( |
117 parent_, nullptr, anchor, MENU_ANCHOR_TOPLEFT, MenuRunner::COMBOBOX); | 165 parent_, nullptr, anchor, MENU_ANCHOR_TOPLEFT, MenuRunner::COMBOBOX); |
118 | 166 |
119 // Ensure the anchor view is removed. | 167 // Ensure the anchor view is removed. |
120 EXPECT_EQ(1u, [[parent_->GetNativeView() subviews] count]); | 168 EXPECT_EQ(1u, [[parent_->GetNativeView() subviews] count]); |
169 [menu_watcher_ setOpenCallback:nil]; | |
121 return result; | 170 return result; |
122 } | 171 } |
123 | 172 |
124 protected: | 173 protected: |
125 scoped_ptr<TestModel> menu_; | 174 scoped_ptr<TestModel> menu_; |
175 base::scoped_nsobject<MenuOpenWatcher> menu_watcher_; | |
126 internal::MenuRunnerImplCocoa* runner_ = nullptr; | 176 internal::MenuRunnerImplCocoa* runner_ = nullptr; |
127 views::Widget* parent_ = nullptr; | 177 views::Widget* parent_ = nullptr; |
128 NSRect last_anchor_frame_ = NSZeroRect; | 178 NSRect last_anchor_frame_ = NSZeroRect; |
129 | 179 |
130 private: | 180 private: |
131 DISALLOW_COPY_AND_ASSIGN(MenuRunnerCocoaTest); | 181 DISALLOW_COPY_AND_ASSIGN(MenuRunnerCocoaTest); |
132 }; | 182 }; |
133 | 183 |
134 TEST_F(MenuRunnerCocoaTest, RunMenuAndCancel) { | 184 TEST_F(MenuRunnerCocoaTest, RunMenuAndCancel) { |
135 base::TimeDelta min_time = ui::EventTimeForNow(); | 185 base::TimeDelta min_time = ui::EventTimeForNow(); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
217 // In RTL, Cocoa messes up the positioning unless the anchor rectangle is | 267 // 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 | 268 // offset to the right of the view. The offset for the checkmark is also |
219 // skipped, to give a better match to native behavior. | 269 // skipped, to give a better match to native behavior. |
220 base::i18n::SetICUDefaultLocale("he"); | 270 base::i18n::SetICUDefaultLocale("he"); |
221 RunMenuAt(anchor_rect); | 271 RunMenuAt(anchor_rect); |
222 EXPECT_EQ(combobox_rect.right(), last_anchor_frame_.origin.x); | 272 EXPECT_EQ(combobox_rect.right(), last_anchor_frame_.origin.x); |
223 } | 273 } |
224 | 274 |
225 } // namespace test | 275 } // namespace test |
226 } // namespace views | 276 } // namespace views |
OLD | NEW |