OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "chrome/browser/ui/cocoa/base_bubble_controller.h" | 5 #import "chrome/browser/ui/cocoa/base_bubble_controller.h" |
6 | 6 |
7 #include "base/mac/mac_util.h" | 7 #include "base/mac/mac_util.h" |
8 #import "base/mac/scoped_nsobject.h" | 8 #import "base/mac/scoped_nsobject.h" |
9 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" | 9 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" |
10 #import "chrome/browser/ui/cocoa/info_bubble_view.h" | 10 #import "chrome/browser/ui/cocoa/info_bubble_view.h" |
11 #import "chrome/browser/ui/cocoa/run_loop_testing.h" | |
12 #import "ui/events/test/cocoa_test_event_utils.h" | 11 #import "ui/events/test/cocoa_test_event_utils.h" |
13 | 12 |
14 namespace { | 13 namespace { |
15 const CGFloat kBubbleWindowWidth = 100; | 14 const CGFloat kBubbleWindowWidth = 100; |
16 const CGFloat kBubbleWindowHeight = 50; | 15 const CGFloat kBubbleWindowHeight = 50; |
17 const CGFloat kAnchorPointX = 400; | 16 const CGFloat kAnchorPointX = 400; |
18 const CGFloat kAnchorPointY = 300; | 17 const CGFloat kAnchorPointY = 300; |
19 } // namespace | 18 } // namespace |
20 | 19 |
| 20 @interface ContextMenuController : NSObject<NSMenuDelegate> { |
| 21 @private |
| 22 NSMenu* menu_; |
| 23 NSWindow* window_; |
| 24 BOOL isMenuOpen_; |
| 25 BOOL didOpen_; |
| 26 } |
| 27 |
| 28 - (id)initWithMenu:(NSMenu*)menu andWindow:(NSWindow*)window; |
| 29 |
| 30 - (BOOL)isMenuOpen; |
| 31 - (BOOL)didOpen; |
| 32 - (BOOL)isWindowVisible; |
| 33 |
| 34 // NSMenuDelegate methods |
| 35 - (void)menuWillOpen:(NSMenu*)menu; |
| 36 - (void)menuDidClose:(NSMenu*)menu; |
| 37 |
| 38 @end |
| 39 |
| 40 @implementation ContextMenuController |
| 41 |
| 42 - (id)initWithMenu:(NSMenu*)menu andWindow:(NSWindow*)window { |
| 43 if (self = [super init]) { |
| 44 menu_ = menu; |
| 45 window_ = window; |
| 46 isMenuOpen_ = NO; |
| 47 didOpen_ = NO; |
| 48 [menu_ setDelegate:self]; |
| 49 } |
| 50 return self; |
| 51 } |
| 52 |
| 53 - (BOOL)isMenuOpen { |
| 54 return isMenuOpen_; |
| 55 } |
| 56 |
| 57 - (BOOL)didOpen { |
| 58 return didOpen_; |
| 59 } |
| 60 |
| 61 - (BOOL)isWindowVisible { |
| 62 if (window_) { |
| 63 return [window_ isVisible]; |
| 64 } |
| 65 return NO; |
| 66 } |
| 67 |
| 68 - (void)menuWillOpen:(NSMenu*)menu { |
| 69 isMenuOpen_ = YES; |
| 70 didOpen_ = NO; |
| 71 |
| 72 NSArray* modes = @[NSEventTrackingRunLoopMode, NSDefaultRunLoopMode]; |
| 73 [menu_ performSelector:@selector(cancelTracking) |
| 74 withObject:nil |
| 75 afterDelay:0.1 |
| 76 inModes:modes]; |
| 77 } |
| 78 |
| 79 - (void)menuDidClose:(NSMenu*)menu { |
| 80 isMenuOpen_ = NO; |
| 81 didOpen_ = YES; |
| 82 } |
| 83 |
| 84 @end |
| 85 |
21 class BaseBubbleControllerTest : public CocoaTest { | 86 class BaseBubbleControllerTest : public CocoaTest { |
22 public: | 87 public: |
23 virtual void SetUp() OVERRIDE { | 88 virtual void SetUp() OVERRIDE { |
24 bubbleWindow_.reset([[NSWindow alloc] | 89 bubbleWindow_.reset([[NSWindow alloc] |
25 initWithContentRect:NSMakeRect(0, 0, kBubbleWindowWidth, | 90 initWithContentRect:NSMakeRect(0, 0, kBubbleWindowWidth, |
26 kBubbleWindowHeight) | 91 kBubbleWindowHeight) |
27 styleMask:NSBorderlessWindowMask | 92 styleMask:NSBorderlessWindowMask |
28 backing:NSBackingStoreBuffered | 93 backing:NSBackingStoreBuffered |
29 defer:YES]); | 94 defer:YES]); |
30 | 95 |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
167 else | 232 else |
168 [controller_ windowDidResignKey:notif]; | 233 [controller_ windowDidResignKey:notif]; |
169 | 234 |
170 | 235 |
171 EXPECT_FALSE([bubble_window isVisible]); | 236 EXPECT_FALSE([bubble_window isVisible]); |
172 EXPECT_TRUE([other_window isVisible]); | 237 EXPECT_TRUE([other_window isVisible]); |
173 } | 238 } |
174 | 239 |
175 // Test that clicking outside the window causes the bubble to close if | 240 // Test that clicking outside the window causes the bubble to close if |
176 // shouldCloseOnResignKey is YES. | 241 // shouldCloseOnResignKey is YES. |
177 TEST_F(BaseBubbleControllerTest, LionClickOutsideCloses) { | 242 TEST_F(BaseBubbleControllerTest, LionClickOutsideClosesWithoutContextMenu) { |
178 // The event tap is only installed on 10.7+. | 243 // The event tap is only installed on 10.7+. |
179 if (!base::mac::IsOSLionOrLater()) | 244 if (!base::mac::IsOSLionOrLater()) |
180 return; | 245 return; |
181 | 246 |
182 // Closing the bubble will autorelease the controller. | 247 // Closing the bubble will autorelease the controller. |
183 base::scoped_nsobject<BaseBubbleController> keep_alive([controller_ retain]); | 248 base::scoped_nsobject<BaseBubbleController> keep_alive([controller_ retain]); |
184 NSWindow* window = [controller_ window]; | 249 NSWindow* window = [controller_ window]; |
185 | 250 |
186 EXPECT_TRUE([controller_ shouldCloseOnResignKey]); // Verify default value. | 251 EXPECT_TRUE([controller_ shouldCloseOnResignKey]); // Verify default value. |
187 EXPECT_FALSE([window isVisible]); | 252 EXPECT_FALSE([window isVisible]); |
188 | 253 |
189 [controller_ showWindow:nil]; | 254 [controller_ showWindow:nil]; |
190 | 255 |
191 EXPECT_TRUE([window isVisible]); | 256 EXPECT_TRUE([window isVisible]); |
192 | 257 |
193 [controller_ setShouldCloseOnResignKey:NO]; | 258 [controller_ setShouldCloseOnResignKey:NO]; |
194 NSEvent* event = cocoa_test_event_utils::LeftMouseDownAtPointInWindow( | 259 NSEvent* event = cocoa_test_event_utils::LeftMouseDownAtPointInWindow( |
195 NSMakePoint(10, 10), test_window()); | 260 NSMakePoint(10, 10), test_window()); |
196 [NSApp sendEvent:event]; | 261 [NSApp sendEvent:event]; |
197 chrome::testing::NSRunLoopRunAllPending(); | |
198 | 262 |
199 EXPECT_TRUE([window isVisible]); | 263 EXPECT_TRUE([window isVisible]); |
200 | 264 |
| 265 event = cocoa_test_event_utils::RightMouseDownAtPointInWindow( |
| 266 NSMakePoint(10, 10), test_window()); |
| 267 [NSApp sendEvent:event]; |
| 268 |
| 269 EXPECT_TRUE([window isVisible]); |
| 270 |
201 [controller_ setShouldCloseOnResignKey:YES]; | 271 [controller_ setShouldCloseOnResignKey:YES]; |
202 event = cocoa_test_event_utils::LeftMouseDownAtPointInWindow( | 272 event = cocoa_test_event_utils::LeftMouseDownAtPointInWindow( |
203 NSMakePoint(10, 10), test_window()); | 273 NSMakePoint(10, 10), test_window()); |
204 [NSApp sendEvent:event]; | 274 [NSApp sendEvent:event]; |
205 chrome::testing::NSRunLoopRunAllPending(); | 275 |
| 276 EXPECT_FALSE([window isVisible]); |
| 277 |
| 278 [controller_ showWindow:nil]; // Show it again |
| 279 EXPECT_TRUE([window isVisible]); |
| 280 EXPECT_TRUE([controller_ shouldCloseOnResignKey]); // Verify. |
| 281 |
| 282 event = cocoa_test_event_utils::RightMouseDownAtPointInWindow( |
| 283 NSMakePoint(10, 10), test_window()); |
| 284 [NSApp sendEvent:event]; |
206 | 285 |
207 EXPECT_FALSE([window isVisible]); | 286 EXPECT_FALSE([window isVisible]); |
208 } | 287 } |
| 288 |
| 289 // Test that right-clicking the window with displaying a context menu causes |
| 290 // the bubble to close. |
| 291 TEST_F(BaseBubbleControllerTest, LionRightClickOutsideClosesWithContextMenu) { |
| 292 // The event tap is only installed on 10.7+. |
| 293 if (!base::mac::IsOSLionOrLater()) |
| 294 return; |
| 295 |
| 296 // Closing the bubble will autorelease the controller. |
| 297 base::scoped_nsobject<BaseBubbleController> keep_alive([controller_ retain]); |
| 298 NSWindow* window = [controller_ window]; |
| 299 |
| 300 EXPECT_TRUE([controller_ shouldCloseOnResignKey]); // Verify default value. |
| 301 EXPECT_FALSE([window isVisible]); |
| 302 |
| 303 [controller_ showWindow:nil]; |
| 304 |
| 305 EXPECT_TRUE([window isVisible]); |
| 306 |
| 307 base::scoped_nsobject<NSMenu> context_menu( |
| 308 [[NSMenu alloc] initWithTitle:@""]); |
| 309 [context_menu addItemWithTitle:@"ContextMenuTest" |
| 310 action:nil |
| 311 keyEquivalent:@""]; |
| 312 base::scoped_nsobject<ContextMenuController> menu_controller( |
| 313 [[ContextMenuController alloc] initWithMenu:context_menu |
| 314 andWindow:window]); |
| 315 |
| 316 // Set the menu as the contextual menu of contentView of test_window(). |
| 317 [[test_window() contentView] setMenu:context_menu]; |
| 318 |
| 319 // RightMouseDown in test_window() would close the bubble window and then |
| 320 // dispaly the contextual menu. |
| 321 NSEvent* event = cocoa_test_event_utils::RightMouseDownAtPointInWindow( |
| 322 NSMakePoint(10, 10), test_window()); |
| 323 // Verify bubble's window is closed when contextual menu is open. |
| 324 CFRunLoopPerformBlock(CFRunLoopGetCurrent(), NSEventTrackingRunLoopMode, ^{ |
| 325 EXPECT_TRUE([menu_controller isMenuOpen]); |
| 326 EXPECT_FALSE([menu_controller isWindowVisible]); |
| 327 }); |
| 328 |
| 329 EXPECT_FALSE([menu_controller isMenuOpen]); |
| 330 EXPECT_FALSE([menu_controller didOpen]); |
| 331 |
| 332 [NSApp sendEvent:event]; |
| 333 |
| 334 // When we got here, menu has already run its RunLoop. |
| 335 // See -[ContextualMenuController menuWillOpen:]. |
| 336 EXPECT_FALSE([window isVisible]); |
| 337 |
| 338 EXPECT_FALSE([menu_controller isMenuOpen]); |
| 339 EXPECT_TRUE([menu_controller didOpen]); |
| 340 } |
| 341 |
OLD | NEW |