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 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h"
7 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
8 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
9 #import "testing/gtest_mac.h"
13 const int kSystemSheetReturnCode = 77;
17 @interface ConstrainedWindowSystemSheetTest
18 : NSObject <ConstrainedWindowSheet> {
20 NSAlert* alert_; // weak
23 @property(nonatomic, readonly) int returnCode;
24 @property(nonatomic, assign) NSAlert* alert;
28 @implementation ConstrainedWindowSystemSheetTest
30 @synthesize returnCode = returnCode_;
31 @synthesize alert = alert_;
33 - (void)showSheetForWindow:(NSWindow*)window {
34 [alert_ beginSheetModalForWindow:window
36 didEndSelector:@selector(alertDidEnd:returnCode:ctxInfo:)
40 - (void)closeSheetWithAnimation:(BOOL)withAnimation {
41 [NSApp endSheet:[alert_ window] returnCode:kSystemSheetReturnCode];
53 - (void)makeSheetKeyAndOrderFront {
56 - (void)updateSheetPosition {
59 - (void)alertDidEnd:(NSAlert *)alert
60 returnCode:(NSInteger)returnCode
61 ctxInfo:(void *)contextInfo {
62 returnCode_ = returnCode;
67 class ConstrainedWindowSheetControllerTest : public CocoaTest {
69 virtual ~ConstrainedWindowSheetControllerTest() {
72 virtual void SetUp() OVERRIDE {
75 // Center the window so that the sheet doesn't go offscreen.
76 [test_window() center];
78 // Create two dummy tabs and make the first one active.
79 NSRect dummyRect = NSMakeRect(0, 0, 50, 50);
80 tab_views_.reset([[NSMutableArray alloc] init]);
81 for (int i = 0; i < 2; ++i) {
82 base::scoped_nsobject<NSView> view(
83 [[NSView alloc] initWithFrame:dummyRect]);
84 [tab_views_ addObject:view];
86 tab0_.reset([[tab_views_ objectAtIndex:0] retain]);
87 tab1_.reset([[tab_views_ objectAtIndex:1] retain]);
88 ActivateTabView(tab0_);
90 // Create a test sheet.
91 sheet_window_.reset([[NSWindow alloc]
92 initWithContentRect:dummyRect
93 styleMask:NSTitledWindowMask
94 backing:NSBackingStoreBuffered
96 [sheet_window_ setReleasedWhenClosed:NO];
97 sheet_.reset([[CustomConstrainedWindowSheet alloc]
98 initWithCustomWindow:sheet_window_]);
100 controller_.reset([[ConstrainedWindowSheetController
101 controllerForParentWindow:test_window()] retain]);
102 EXPECT_TRUE(controller_);
103 EXPECT_FALSE([ConstrainedWindowSheetController controllerForSheet:sheet_]);
106 virtual void TearDown() OVERRIDE {
108 sheet_window_.reset();
109 CocoaTest::TearDown();
112 void ActivateTabView(NSView* tab_view) {
113 for (NSView* view in tab_views_.get()) {
114 [view removeFromSuperview];
116 [[test_window() contentView] addSubview:tab_view];
117 active_tab_view_.reset([tab_view retain]);
119 ConstrainedWindowSheetController* controller =
120 [ConstrainedWindowSheetController
121 controllerForParentWindow:test_window()];
122 EXPECT_TRUE(controller);
123 [controller parentViewDidBecomeActive:active_tab_view_];
126 NSRect GetViewFrameInScreenCoordinates(NSView* view) {
127 NSRect rect = [view convertRect:[view bounds] toView:nil];
128 rect.origin = [[view window] convertBaseToScreen:rect.origin];
132 void VerifySheetXPosition(NSRect sheet_frame, NSView* parent_view) {
133 NSRect parent_frame = GetViewFrameInScreenCoordinates(parent_view);
134 CGFloat expected_x = NSMinX(parent_frame) +
135 (NSWidth(parent_frame) - NSWidth(sheet_frame)) / 2.0;
136 EXPECT_EQ(expected_x, NSMinX(sheet_frame));
139 base::scoped_nsobject<NSWindow> sheet_window_;
140 base::scoped_nsobject<CustomConstrainedWindowSheet> sheet_;
141 base::scoped_nsobject<ConstrainedWindowSheetController> controller_;
142 base::scoped_nsobject<NSMutableArray> tab_views_;
143 base::scoped_nsobject<NSView> active_tab_view_;
144 base::scoped_nsobject<NSView> tab0_;
145 base::scoped_nsobject<NSView> tab1_;
148 // Test showing then hiding the sheet.
149 TEST_F(ConstrainedWindowSheetControllerTest, ShowHide) {
150 EXPECT_FALSE([sheet_window_ isVisible]);
151 [controller_ showSheet:sheet_ forParentView:active_tab_view_];
152 EXPECT_TRUE([ConstrainedWindowSheetController controllerForSheet:sheet_]);
153 EXPECT_TRUE([sheet_window_ isVisible]);
155 [controller_ closeSheet:sheet_];
156 EXPECT_FALSE([ConstrainedWindowSheetController controllerForSheet:sheet_]);
157 EXPECT_FALSE([sheet_window_ isVisible]);
160 // Test that switching tabs correctly hides the inactive tab's sheet.
161 TEST_F(ConstrainedWindowSheetControllerTest, SwitchTabs) {
162 [controller_ showSheet:sheet_ forParentView:active_tab_view_];
164 EXPECT_TRUE([sheet_window_ isVisible]);
165 EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
166 ActivateTabView([tab_views_ objectAtIndex:1]);
167 EXPECT_TRUE([sheet_window_ isVisible]);
168 EXPECT_EQ(0.0, [sheet_window_ alphaValue]);
169 ActivateTabView([tab_views_ objectAtIndex:0]);
170 EXPECT_TRUE([sheet_window_ isVisible]);
171 EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
174 // Test that adding a sheet to an inactive view doesn't show it.
175 TEST_F(ConstrainedWindowSheetControllerTest, AddToInactiveTab) {
176 ActivateTabView(tab0_);
177 [controller_ showSheet:sheet_ forParentView:tab1_];
178 EXPECT_EQ(0.0, [sheet_window_ alphaValue]);
180 ActivateTabView(tab1_);
181 EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
182 VerifySheetXPosition([sheet_window_ frame], tab1_);
185 // Test that two parent windows with two sheet controllers don't conflict.
186 TEST_F(ConstrainedWindowSheetControllerTest, TwoParentWindows) {
187 base::scoped_nsobject<NSWindow> parent_window2(
188 [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 30, 30)
189 styleMask:NSTitledWindowMask
190 backing:NSBackingStoreBuffered
192 [parent_window2 setReleasedWhenClosed:NO];
194 ConstrainedWindowSheetController* controller2 =
195 [ConstrainedWindowSheetController
196 controllerForParentWindow:parent_window2];
197 EXPECT_TRUE(controller2);
198 EXPECT_NSNE(controller_, controller2);
200 [controller2 showSheet:sheet_ forParentView:[parent_window2 contentView]];
201 EXPECT_NSEQ(controller2,
202 [ConstrainedWindowSheetController controllerForSheet:sheet_]);
204 [parent_window2 close];
207 // Test that using a top level parent view works.
208 TEST_F(ConstrainedWindowSheetControllerTest, TopLevelView) {
209 NSView* parentView = [[test_window() contentView] superview];
210 [controller_ parentViewDidBecomeActive:parentView];
212 EXPECT_FALSE([sheet_window_ isVisible]);
213 [controller_ showSheet:sheet_ forParentView:parentView];
214 EXPECT_TRUE([ConstrainedWindowSheetController controllerForSheet:sheet_]);
215 EXPECT_TRUE([sheet_window_ isVisible]);
216 VerifySheetXPosition([sheet_window_ frame], parentView);
219 // Test that resizing sheet works.
220 TEST_F(ConstrainedWindowSheetControllerTest, Resize) {
221 [controller_ showSheet:sheet_ forParentView:active_tab_view_];
223 NSRect old_frame = [sheet_window_ frame];
226 sheet_frame.size = NSMakeSize(NSWidth(old_frame) + 100,
227 NSHeight(old_frame) + 50);
228 sheet_frame.origin = [controller_ originForSheet:sheet_
229 withWindowSize:sheet_frame.size];
231 // Y pos should not have changed.
232 EXPECT_EQ(NSMaxY(sheet_frame), NSMaxY(old_frame));
234 // X pos should be centered on parent view.
235 VerifySheetXPosition(sheet_frame, active_tab_view_);
238 // Test that resizing a hidden sheet works.
239 TEST_F(ConstrainedWindowSheetControllerTest, ResizeHiddenSheet) {
240 [controller_ showSheet:sheet_ forParentView:tab0_];
241 EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
242 ActivateTabView(tab1_);
243 EXPECT_EQ(0.0, [sheet_window_ alphaValue]);
245 NSRect old_frame = [sheet_window_ frame];
246 NSRect new_inactive_frame = NSInsetRect(old_frame, -30, -40);
247 [sheet_window_ setFrame:new_inactive_frame display:YES];
249 ActivateTabView(tab0_);
250 EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
252 NSRect new_active_frame = [sheet_window_ frame];
253 EXPECT_EQ(NSWidth(new_inactive_frame), NSWidth(new_active_frame));
254 EXPECT_EQ(NSHeight(new_inactive_frame), NSHeight(new_active_frame));
257 // Test system sheets.
258 TEST_F(ConstrainedWindowSheetControllerTest, SystemSheet) {
259 base::scoped_nsobject<ConstrainedWindowSystemSheetTest> system_sheet(
260 [[ConstrainedWindowSystemSheetTest alloc] init]);
261 base::scoped_nsobject<NSAlert> alert([[NSAlert alloc] init]);
262 [system_sheet setAlert:alert];
264 EXPECT_FALSE([[alert window] isVisible]);
265 [controller_ showSheet:system_sheet
266 forParentView:active_tab_view_];
267 EXPECT_TRUE([[alert window] isVisible]);
269 [controller_ closeSheet:system_sheet];
270 EXPECT_FALSE([[alert window] isVisible]);
271 EXPECT_EQ(kSystemSheetReturnCode, [system_sheet returnCode]);
274 // Test showing a system sheet on an inactive tab.
275 TEST_F(ConstrainedWindowSheetControllerTest, SystemSheetAddToInactiveTab) {
276 base::scoped_nsobject<ConstrainedWindowSystemSheetTest> system_sheet(
277 [[ConstrainedWindowSystemSheetTest alloc] init]);
278 base::scoped_nsobject<NSAlert> alert([[NSAlert alloc] init]);
279 [system_sheet setAlert:alert];
281 EXPECT_FALSE([[alert window] isVisible]);
282 [controller_ showSheet:system_sheet
283 forParentView:tab1_];
284 EXPECT_FALSE([[alert window] isVisible]);
286 ActivateTabView(tab1_);
287 EXPECT_TRUE([[alert window] isVisible]);
288 EXPECT_EQ(1.0, [[alert window] alphaValue]);
290 [controller_ closeSheet:system_sheet];