OLD | NEW |
---|---|
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2015 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 #include "base/strings/sys_string_conversions.h" | |
5 #include "chrome/browser/ui/autofill/card_unmask_prompt_controller.h" | 6 #include "chrome/browser/ui/autofill/card_unmask_prompt_controller.h" |
6 #include "chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h" | 7 #include "chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h" |
8 #import "chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.h" | |
7 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h" | 9 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h" |
8 #include "chrome/browser/ui/chrome_style.h" | 10 #include "chrome/browser/ui/chrome_style.h" |
11 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_control_u tils.h" | |
9 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sh eet.h" | 12 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sh eet.h" |
10 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_wi ndow.h" | 13 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_wi ndow.h" |
11 #import "chrome/browser/ui/cocoa/key_equivalent_constants.h" | 14 #import "chrome/browser/ui/cocoa/key_equivalent_constants.h" |
12 #include "grit/generated_resources.h" | 15 #include "grit/generated_resources.h" |
13 #include "ui/base/cocoa/window_size_constants.h" | 16 #include "ui/base/cocoa/window_size_constants.h" |
14 #include "ui/base/l10n/l10n_util.h" | 17 #include "ui/base/l10n/l10n_util.h" |
15 | 18 |
16 namespace { | 19 namespace { |
20 | |
17 const CGFloat kButtonGap = 6.0f; | 21 const CGFloat kButtonGap = 6.0f; |
22 const CGFloat kDialogMinWidth = 250.0f; | |
23 const CGFloat kCvcInputWidth = 64.0f; | |
24 | |
18 } // namespace | 25 } // namespace |
19 | 26 |
20 namespace autofill { | 27 namespace autofill { |
21 | 28 |
22 // static | 29 // static |
23 CardUnmaskPromptView* CardUnmaskPromptView::CreateAndShow( | 30 CardUnmaskPromptView* CardUnmaskPromptView::CreateAndShow( |
24 CardUnmaskPromptController* controller) { | 31 CardUnmaskPromptController* controller) { |
25 return new CardUnmaskPromptViewBridge(controller); | 32 return new CardUnmaskPromptViewBridge(controller); |
26 } | 33 } |
27 | 34 |
28 #pragma mark CardUnmaskPromptViewBridge | 35 #pragma mark CardUnmaskPromptViewBridge |
29 | 36 |
30 CardUnmaskPromptViewBridge::CardUnmaskPromptViewBridge( | 37 CardUnmaskPromptViewBridge::CardUnmaskPromptViewBridge( |
31 CardUnmaskPromptController* controller) | 38 CardUnmaskPromptController* controller) |
32 : controller_(controller) { | 39 : controller_(controller) { |
33 sheet_controller_.reset([[CardUnmaskPromptViewCocoa alloc] | 40 view_controller_.reset([[CardUnmaskPromptViewCocoa alloc] |
34 initWithWebContents:controller_->GetWebContents() | 41 initWithWebContents:controller_->GetWebContents() |
35 bridge:this]); | 42 bridge:this]); |
43 | |
44 // Setup the constrained window that will show the view. | |
45 base::scoped_nsobject<NSWindow> window([[ConstrainedWindowCustomWindow alloc] | |
46 initWithContentRect:[[view_controller_ view] bounds]]); | |
47 [window setContentView:[view_controller_ view]]; | |
36 base::scoped_nsobject<CustomConstrainedWindowSheet> sheet( | 48 base::scoped_nsobject<CustomConstrainedWindowSheet> sheet( |
37 [[CustomConstrainedWindowSheet alloc] | 49 [[CustomConstrainedWindowSheet alloc] initWithCustomWindow:window]); |
38 initWithCustomWindow:[sheet_controller_ window]]); | |
39 constrained_window_.reset( | 50 constrained_window_.reset( |
40 new ConstrainedWindowMac(this, controller_->GetWebContents(), sheet)); | 51 new ConstrainedWindowMac(this, controller_->GetWebContents(), sheet)); |
41 } | 52 } |
42 | 53 |
43 CardUnmaskPromptViewBridge::~CardUnmaskPromptViewBridge() { | 54 CardUnmaskPromptViewBridge::~CardUnmaskPromptViewBridge() { |
44 } | 55 } |
45 | 56 |
46 void CardUnmaskPromptViewBridge::ControllerGone() { | 57 void CardUnmaskPromptViewBridge::ControllerGone() { |
58 controller_ = nullptr; | |
59 PerformClose(); | |
47 } | 60 } |
48 | 61 |
49 void CardUnmaskPromptViewBridge::DisableAndWaitForVerification() { | 62 void CardUnmaskPromptViewBridge::DisableAndWaitForVerification() { |
50 } | 63 } |
51 | 64 |
52 void CardUnmaskPromptViewBridge::GotVerificationResult(bool success) { | 65 void CardUnmaskPromptViewBridge::GotVerificationResult(bool success) { |
53 } | 66 } |
54 | 67 |
55 void CardUnmaskPromptViewBridge::OnConstrainedWindowClosed( | 68 void CardUnmaskPromptViewBridge::OnConstrainedWindowClosed( |
56 ConstrainedWindowMac* window) { | 69 ConstrainedWindowMac* window) { |
57 constrained_window_.reset(); | 70 constrained_window_.reset(); |
58 controller_->OnUnmaskDialogClosed(); | 71 if (controller_) |
72 controller_->OnUnmaskDialogClosed(); | |
73 } | |
74 | |
75 CardUnmaskPromptController* CardUnmaskPromptViewBridge::GetController() { | |
76 return controller_; | |
59 } | 77 } |
60 | 78 |
61 void CardUnmaskPromptViewBridge::PerformClose() { | 79 void CardUnmaskPromptViewBridge::PerformClose() { |
62 constrained_window_->CloseWebContentsModalDialog(); | 80 constrained_window_->CloseWebContentsModalDialog(); |
63 } | 81 } |
64 | 82 |
65 } // autofill | 83 } // autofill |
66 | 84 |
67 #pragma mark CardUnmaskPromptViewCocoa | 85 #pragma mark CardUnmaskPromptViewCocoa |
68 | 86 |
69 @implementation CardUnmaskPromptViewCocoa | 87 @implementation CardUnmaskPromptViewCocoa |
70 | 88 |
89 + (AutofillPopUpButton*)buildDatePopupWithModel:(ui::ComboboxModel&)model { | |
90 AutofillPopUpButton* popup = | |
91 [[AutofillPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO]; | |
92 | |
93 for (int i = 0; i < model.GetItemCount(); ++i) { | |
94 [popup addItemWithTitle:base::SysUTF16ToNSString(model.GetItemAt(i))]; | |
95 } | |
96 [popup setDefaultValue:base::SysUTF16ToNSString( | |
97 model.GetItemAt(model.GetDefaultIndex()))]; | |
98 [popup sizeToFit]; | |
99 return popup; | |
100 } | |
101 | |
102 + (void)setDatePopup:(AutofillPopUpButton*)popup | |
103 originX:(CGFloat)originX | |
104 originY:(CGFloat)originY | |
105 height:(CGFloat)height { | |
106 [popup setFrameOrigin:NSMakePoint(originX, originY)]; | |
107 [popup setFrameSize:NSMakeSize(NSWidth([popup frame]), height)]; | |
bondd
2015/03/02 23:04:04
After combining setFrameOrigin + setFrameSize -> s
| |
108 } | |
109 | |
71 - (id)initWithWebContents:(content::WebContents*)webContents | 110 - (id)initWithWebContents:(content::WebContents*)webContents |
72 bridge:(autofill::CardUnmaskPromptViewBridge*)bridge { | 111 bridge:(autofill::CardUnmaskPromptViewBridge*)bridge { |
73 DCHECK(webContents); | 112 DCHECK(webContents); |
74 DCHECK(bridge); | 113 DCHECK(bridge); |
75 | 114 |
76 NSRect frame = NSMakeRect(0, 0, 550, 600); | 115 if ((self = [super initWithNibName:nil bundle:nil])) { |
77 base::scoped_nsobject<ConstrainedWindowCustomWindow> window( | |
78 [[ConstrainedWindowCustomWindow alloc] initWithContentRect:frame]); | |
79 if ((self = [super initWithWindow:window])) { | |
80 webContents_ = webContents; | 116 webContents_ = webContents; |
81 bridge_ = bridge; | 117 bridge_ = bridge; |
82 | |
83 [self buildWindowButtons]; | |
84 } | 118 } |
85 return self; | 119 return self; |
86 } | 120 } |
87 | 121 |
88 - (IBAction)closeSheet:(id)sender { | 122 - (IBAction)closeSheet:(id)sender { |
89 bridge_->PerformClose(); | 123 bridge_->PerformClose(); |
90 } | 124 } |
91 | 125 |
92 - (void)buildWindowButtons { | 126 - (void)loadView { |
93 base::scoped_nsobject<NSView> buttonContainer( | 127 autofill::CardUnmaskPromptController* controller = bridge_->GetController(); |
128 DCHECK(controller); | |
129 | |
130 base::scoped_nsobject<NSView> mainView( | |
94 [[NSView alloc] initWithFrame:NSZeroRect]); | 131 [[NSView alloc] initWithFrame:NSZeroRect]); |
95 | 132 |
96 base::scoped_nsobject<NSButton> button( | 133 // Title label. |
134 NSTextField* title = constrained_window::CreateLabel(); | |
135 NSAttributedString* titleString = | |
136 constrained_window::GetAttributedLabelString( | |
137 SysUTF16ToNSString(controller->GetWindowTitle()), | |
138 chrome_style::kTitleFontStyle, NSNaturalTextAlignment, | |
139 NSLineBreakByWordWrapping); | |
140 [title setAttributedStringValue:titleString]; | |
141 [title sizeToFit]; | |
142 [mainView addSubview:title]; | |
143 | |
144 // Instructions label. | |
145 NSTextField* instructions = constrained_window::CreateLabel(); | |
146 NSAttributedString* instructionsString = | |
147 constrained_window::GetAttributedLabelString( | |
148 SysUTF16ToNSString(controller->GetInstructionsMessage()), | |
149 chrome_style::kTextFontStyle, NSNaturalTextAlignment, | |
150 NSLineBreakByWordWrapping); | |
151 [instructions setAttributedStringValue:instructionsString]; | |
152 // No need to call sizeToFit here. Size is calculated later. | |
groby-ooo-7-16
2015/02/28 00:49:17
Feel free to kill this comment :)
bondd
2015/03/02 23:04:04
Done.
| |
153 [mainView addSubview:instructions]; | |
154 | |
155 // Expiration date. | |
156 base::scoped_nsobject<AutofillPopUpButton> monthPopup; | |
157 base::scoped_nsobject<AutofillPopUpButton> yearPopup; | |
158 NSSize expirationDateSize = NSZeroSize; | |
159 if (controller->ShouldRequestExpirationDate()) { | |
160 // Month. | |
161 autofill::MonthComboboxModel monthModel; | |
162 monthPopup.reset( | |
163 [CardUnmaskPromptViewCocoa buildDatePopupWithModel:monthModel]); | |
164 [mainView addSubview:monthPopup]; | |
165 | |
166 // Year. | |
167 autofill::YearComboboxModel yearModel; | |
168 yearPopup.reset( | |
169 [CardUnmaskPromptViewCocoa buildDatePopupWithModel:yearModel]); | |
170 [mainView addSubview:yearPopup]; | |
171 | |
172 // Dimensions. | |
173 expirationDateSize.width = NSWidth([monthPopup frame]) + | |
174 NSWidth([yearPopup frame]) + kButtonGap * 2; | |
175 expirationDateSize.height = | |
176 std::max(NSHeight([monthPopup frame]), NSHeight([yearPopup frame])); | |
177 } | |
178 | |
179 // CVC text input. | |
180 base::scoped_nsobject<NSTextField> cvcInput( | |
181 [[NSTextField alloc] initWithFrame:NSZeroRect]); | |
182 [[cvcInput cell] | |
183 setPlaceholderString:l10n_util::GetNSString( | |
184 IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC)]; | |
185 [[cvcInput cell] setScrollable:YES]; | |
186 [cvcInput sizeToFit]; | |
187 [mainView addSubview:cvcInput]; | |
188 | |
189 // CVC image. | |
190 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
191 NSImage* cvcImage = | |
192 rb.GetNativeImageNamed(controller->GetCvcImageRid()).ToNSImage(); | |
193 base::scoped_nsobject<NSImageView> cvcImageView( | |
194 [[NSImageView alloc] initWithFrame:NSZeroRect]); | |
195 [cvcImageView setImage:cvcImage]; | |
196 [mainView addSubview:cvcImageView]; | |
197 | |
198 // Cancel button. | |
199 base::scoped_nsobject<NSButton> cancelButton( | |
97 [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]); | 200 [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]); |
98 [button setTitle:l10n_util::GetNSStringWithFixup(IDS_CANCEL)]; | 201 [cancelButton setTitle:l10n_util::GetNSStringWithFixup(IDS_CANCEL)]; |
99 [button setKeyEquivalent:kKeyEquivalentEscape]; | 202 [cancelButton setKeyEquivalent:kKeyEquivalentEscape]; |
100 [button setTarget:self]; | 203 [cancelButton setTarget:self]; |
101 [button setAction:@selector(closeSheet:)]; | 204 [cancelButton setAction:@selector(closeSheet:)]; |
102 [button sizeToFit]; | 205 [cancelButton sizeToFit]; |
103 [buttonContainer addSubview:button]; | 206 [mainView addSubview:cancelButton]; |
104 | 207 |
105 CGFloat nextX = NSMaxX([button frame]) + kButtonGap; | 208 // Verify button. |
106 button.reset([[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]); | 209 base::scoped_nsobject<NSButton> verifyButton( |
107 [button setFrameOrigin:NSMakePoint(nextX, 0)]; | 210 [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]); |
108 [button setTitle:l10n_util::GetNSStringWithFixup( | 211 // TODO(bondd): use l10n string. |
109 IDS_AUTOFILL_DIALOG_SUBMIT_BUTTON)]; | 212 [verifyButton setTitle:@"Verify"]; |
110 [button setKeyEquivalent:kKeyEquivalentReturn]; | 213 [verifyButton setKeyEquivalent:kKeyEquivalentReturn]; |
111 [button setTarget:self]; | 214 [verifyButton setTarget:self]; |
112 [button setAction:@selector(closeSheet:)]; | 215 [verifyButton setAction:@selector(closeSheet:)]; |
113 [button sizeToFit]; | 216 [verifyButton sizeToFit]; |
114 [buttonContainer addSubview:button]; | 217 [mainView addSubview:verifyButton]; |
115 | 218 |
116 const CGFloat dialogOffset = NSWidth([[self window] frame]) - | 219 // Calculate input row dimensions. |
117 chrome_style::kHorizontalPadding - | 220 NSSize inputRowSize; |
118 NSMaxX([button frame]); | 221 inputRowSize.width = kCvcInputWidth + kButtonGap + [cvcImage size].width + |
119 [buttonContainer | 222 expirationDateSize.width; |
120 setFrame:NSMakeRect(dialogOffset, chrome_style::kClientBottomPadding, | 223 CGFloat maxCvcHeight = |
121 NSMaxX([button frame]), NSMaxY([button frame]))]; | 224 std::max(NSHeight([cvcInput frame]), [cvcImage size].height); |
225 inputRowSize.height = std::max(maxCvcHeight, expirationDateSize.height); | |
122 | 226 |
123 [[[self window] contentView] addSubview:buttonContainer]; | 227 // Calculate dialog width. |
228 CGFloat dialogWidth = std::max(NSWidth([title frame]), inputRowSize.width) + | |
229 chrome_style::kHorizontalPadding * 2; | |
groby-ooo-7-16
2015/02/28 00:49:17
If you want to save yourself a whole lot of paddin
bondd
2015/03/02 23:04:04
Done. Now I use NSBox contentViewMargins for horiz
| |
230 dialogWidth = std::max(dialogWidth, kDialogMinWidth); | |
231 | |
232 // Layout the elements, starting at the bottom and moving up. | |
groby-ooo-7-16
2015/02/28 00:49:17
"Starting at the bottom" is pretty much implied in
bondd
2015/03/02 23:04:04
Acknowledged. I saw it in profile_signin_confirmat
| |
233 | |
234 CGFloat curX = dialogWidth - chrome_style::kHorizontalPadding; | |
groby-ooo-7-16
2015/02/28 00:49:17
Since you keep converting this to a point anyways
bondd
2015/03/02 23:04:04
Done.
| |
235 CGFloat curY = chrome_style::kClientBottomPadding; | |
236 | |
237 // Verify and Cancel buttons. | |
238 curX -= NSWidth([verifyButton frame]); | |
239 [verifyButton setFrameOrigin:NSMakePoint(curX, curY)]; | |
240 curX -= kButtonGap + NSWidth([cancelButton frame]); | |
241 [cancelButton setFrameOrigin:NSMakePoint(curX, curY)]; | |
242 curY += NSHeight([cancelButton frame]); | |
243 | |
244 // Get start position of input row. | |
245 curX = chrome_style::kHorizontalPadding; | |
246 curY += chrome_style::kRowPadding; | |
247 | |
248 // Expiration date. | |
249 if (controller->ShouldRequestExpirationDate()) { | |
250 [CardUnmaskPromptViewCocoa setDatePopup:monthPopup | |
251 originX:curX | |
252 originY:curY | |
253 height:inputRowSize.height]; | |
254 curX += NSWidth([monthPopup frame]) + kButtonGap; | |
255 | |
256 [CardUnmaskPromptViewCocoa setDatePopup:yearPopup | |
257 originX:curX | |
258 originY:curY | |
259 height:inputRowSize.height]; | |
260 curX += NSWidth([yearPopup frame]) + kButtonGap; | |
261 } | |
262 | |
263 // Center cvcInput vertically in the input row. | |
groby-ooo-7-16
2015/02/28 00:49:17
Does that ensure centering of popups as well?
bondd
2015/03/02 23:04:04
Yes, popups will be centered vertically. Popups ge
| |
264 CGFloat cvcInputY = | |
265 curY + round((inputRowSize.height - NSHeight([cvcInput frame])) * 0.5); | |
groby-ooo-7-16
2015/02/28 00:49:17
Why round, instead of ceil?
bondd
2015/03/02 23:04:04
Done.
| |
266 [cvcInput setFrameOrigin:NSMakePoint(curX, cvcInputY)]; | |
groby-ooo-7-16
2015/02/28 00:49:17
setFrame:NSMakeRect(...
bondd
2015/03/02 23:04:04
Done.
| |
267 [cvcInput | |
268 setFrameSize:NSMakeSize(kCvcInputWidth, NSHeight([cvcInput frame]))]; | |
269 curX += NSWidth([cvcInput frame]) + kButtonGap; | |
270 | |
271 // CVC image. | |
272 [cvcImageView setFrameOrigin:NSMakePoint(curX, curY)]; | |
273 [cvcImageView | |
274 setFrameSize:NSMakeSize([cvcImage size].width, inputRowSize.height)]; | |
groby-ooo-7-16
2015/02/28 00:49:17
setFrame:NSMakeRect(...
bondd
2015/03/02 23:04:04
Done.
| |
275 curX += NSWidth([cvcImageView frame]); | |
276 | |
277 // Instruction label. | |
278 curX = chrome_style::kHorizontalPadding; | |
279 curY += inputRowSize.height + chrome_style::kRowPadding; | |
280 [instructions setFrameOrigin:NSMakePoint(curX, curY)]; | |
281 CGFloat maxTextWidth = dialogWidth - chrome_style::kHorizontalPadding * 2; | |
282 NSSize instructionsSize = [[instructions cell] | |
283 cellSizeForBounds:NSMakeRect(0.0, 0.0, maxTextWidth, CGFLOAT_MAX)]; | |
284 [instructions setFrameSize:instructionsSize]; | |
285 | |
286 // Title label. | |
287 curY += instructionsSize.height + chrome_style::kRowPadding; | |
288 [title setFrameOrigin:NSMakePoint(curX, curY)]; | |
289 | |
290 // Dialog size. | |
291 CGFloat dialogHeight = | |
292 curY + NSHeight([title frame]) + chrome_style::kTitleTopPadding; | |
groby-ooo-7-16
2015/02/28 00:49:17
That's NSMaxY([title frame]) + chrome_style::kTitl
bondd
2015/03/02 23:04:04
Done.
| |
293 | |
294 [mainView setFrame:NSMakeRect(0, 0, dialogWidth, dialogHeight)]; | |
groby-ooo-7-16
2015/02/28 00:49:17
You can probably just to -setFrameSize
Ther orig
bondd
2015/03/02 23:04:04
Done.
| |
295 [self setView:mainView]; | |
124 } | 296 } |
125 | 297 |
126 @end | 298 @end |
OLD | NEW |