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" | |
9 #import "chrome/browser/ui/cocoa/autofill/autofill_textfield.h" | |
7 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h" | 10 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h" |
8 #include "chrome/browser/ui/chrome_style.h" | 11 #include "chrome/browser/ui/chrome_style.h" |
12 #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" | 13 #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" | 14 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_wi ndow.h" |
11 #import "chrome/browser/ui/cocoa/key_equivalent_constants.h" | 15 #import "chrome/browser/ui/cocoa/key_equivalent_constants.h" |
12 #include "grit/generated_resources.h" | 16 #include "grit/generated_resources.h" |
13 #include "ui/base/cocoa/window_size_constants.h" | 17 #include "ui/base/cocoa/window_size_constants.h" |
14 #include "ui/base/l10n/l10n_util.h" | 18 #include "ui/base/l10n/l10n_util.h" |
15 | 19 |
16 namespace { | 20 namespace { |
21 | |
17 const CGFloat kButtonGap = 6.0f; | 22 const CGFloat kButtonGap = 6.0f; |
23 const CGFloat kDialogMinWidth = 250.0f; | |
24 const CGFloat kCvcInputWidth = 64.0f; | |
25 | |
26 AutofillPopUpButton* CreateDatePopup(ui::ComboboxModel& model) { | |
groby-ooo-7-16
2015/02/18 19:01:19
FWIW, we usually have those builder functions as c
bondd
2015/02/26 01:25:08
Done.
| |
27 AutofillPopUpButton* popup = | |
groby-ooo-7-16
2015/02/18 19:01:19
why not use menuFromModel:?
bondd
2015/02/26 01:25:08
Views implementation uses autofill::MonthComboboxM
groby-ooo-7-16
2015/02/28 00:49:17
No, you don't. I naively assumed we had a menuFrom
| |
28 [[AutofillPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO]; | |
29 | |
30 for (int i = 0; i < model.GetItemCount(); ++i) { | |
31 [popup addItemWithTitle:base::SysUTF16ToNSString(model.GetItemAt(i))]; | |
32 } | |
33 [popup setDefaultValue:base::SysUTF16ToNSString( | |
34 model.GetItemAt(model.GetDefaultIndex()))]; | |
35 [popup sizeToFit]; | |
36 return popup; | |
37 } | |
38 | |
18 } // namespace | 39 } // namespace |
19 | 40 |
20 namespace autofill { | 41 namespace autofill { |
21 | 42 |
22 // static | 43 // static |
23 CardUnmaskPromptView* CardUnmaskPromptView::CreateAndShow( | 44 CardUnmaskPromptView* CardUnmaskPromptView::CreateAndShow( |
24 CardUnmaskPromptController* controller) { | 45 CardUnmaskPromptController* controller) { |
25 return new CardUnmaskPromptViewBridge(controller); | 46 return new CardUnmaskPromptViewBridge(controller); |
26 } | 47 } |
27 | 48 |
28 #pragma mark CardUnmaskPromptViewBridge | 49 #pragma mark CardUnmaskPromptViewBridge |
29 | 50 |
30 CardUnmaskPromptViewBridge::CardUnmaskPromptViewBridge( | 51 CardUnmaskPromptViewBridge::CardUnmaskPromptViewBridge( |
31 CardUnmaskPromptController* controller) | 52 CardUnmaskPromptController* controller) |
32 : controller_(controller) { | 53 : controller_(controller) { |
33 sheet_controller_.reset([[CardUnmaskPromptViewCocoa alloc] | 54 view_controller_.reset([[CardUnmaskPromptViewCocoa alloc] |
34 initWithWebContents:controller_->GetWebContents() | 55 initWithWebContents:controller_->GetWebContents() |
35 bridge:this]); | 56 bridge:this]); |
57 | |
58 // Setup the constrained window that will show the view. | |
59 base::scoped_nsobject<NSWindow> window([[ConstrainedWindowCustomWindow alloc] | |
60 initWithContentRect:[[view_controller_ view] bounds]]); | |
61 [[window contentView] addSubview:[view_controller_ view]]; | |
groby-ooo-7-16
2015/02/18 19:01:19
Are you sure you don't just want to replace the co
bondd
2015/02/26 01:25:08
Done.
| |
36 base::scoped_nsobject<CustomConstrainedWindowSheet> sheet( | 62 base::scoped_nsobject<CustomConstrainedWindowSheet> sheet( |
37 [[CustomConstrainedWindowSheet alloc] | 63 [[CustomConstrainedWindowSheet alloc] initWithCustomWindow:window]); |
38 initWithCustomWindow:[sheet_controller_ window]]); | |
39 constrained_window_.reset( | 64 constrained_window_.reset( |
40 new ConstrainedWindowMac(this, controller_->GetWebContents(), sheet)); | 65 new ConstrainedWindowMac(this, controller_->GetWebContents(), sheet)); |
41 } | 66 } |
42 | 67 |
43 CardUnmaskPromptViewBridge::~CardUnmaskPromptViewBridge() { | 68 CardUnmaskPromptViewBridge::~CardUnmaskPromptViewBridge() { |
44 } | 69 } |
45 | 70 |
46 void CardUnmaskPromptViewBridge::ControllerGone() { | 71 void CardUnmaskPromptViewBridge::ControllerGone() { |
72 controller_ = nullptr; | |
73 PerformClose(); | |
47 } | 74 } |
48 | 75 |
49 void CardUnmaskPromptViewBridge::DisableAndWaitForVerification() { | 76 void CardUnmaskPromptViewBridge::DisableAndWaitForVerification() { |
50 } | 77 } |
51 | 78 |
52 void CardUnmaskPromptViewBridge::GotVerificationResult(bool success) { | 79 void CardUnmaskPromptViewBridge::GotVerificationResult(bool success) { |
53 } | 80 } |
54 | 81 |
55 void CardUnmaskPromptViewBridge::OnConstrainedWindowClosed( | 82 void CardUnmaskPromptViewBridge::OnConstrainedWindowClosed( |
56 ConstrainedWindowMac* window) { | 83 ConstrainedWindowMac* window) { |
57 constrained_window_.reset(); | 84 constrained_window_.reset(); |
58 controller_->OnUnmaskDialogClosed(); | 85 controller_->OnUnmaskDialogClosed(); |
59 } | 86 } |
60 | 87 |
88 CardUnmaskPromptController* CardUnmaskPromptViewBridge::GetController() { | |
89 return controller_; | |
90 } | |
91 | |
61 void CardUnmaskPromptViewBridge::PerformClose() { | 92 void CardUnmaskPromptViewBridge::PerformClose() { |
62 constrained_window_->CloseWebContentsModalDialog(); | 93 constrained_window_->CloseWebContentsModalDialog(); |
63 } | 94 } |
64 | 95 |
65 } // autofill | 96 } // autofill |
66 | 97 |
67 #pragma mark CardUnmaskPromptViewCocoa | 98 #pragma mark CardUnmaskPromptViewCocoa |
68 | 99 |
69 @implementation CardUnmaskPromptViewCocoa | 100 @implementation CardUnmaskPromptViewCocoa |
70 | 101 |
71 - (id)initWithWebContents:(content::WebContents*)webContents | 102 - (id)initWithWebContents:(content::WebContents*)webContents |
72 bridge:(autofill::CardUnmaskPromptViewBridge*)bridge { | 103 bridge:(autofill::CardUnmaskPromptViewBridge*)bridge { |
73 DCHECK(webContents); | 104 DCHECK(webContents); |
74 DCHECK(bridge); | 105 DCHECK(bridge); |
75 | 106 |
76 NSRect frame = NSMakeRect(0, 0, 550, 600); | 107 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; | 108 webContents_ = webContents; |
81 bridge_ = bridge; | 109 bridge_ = bridge; |
82 | |
83 [self buildWindowButtons]; | |
84 } | 110 } |
85 return self; | 111 return self; |
86 } | 112 } |
87 | 113 |
88 - (IBAction)closeSheet:(id)sender { | 114 - (IBAction)closeSheet:(id)sender { |
89 bridge_->PerformClose(); | 115 bridge_->PerformClose(); |
90 } | 116 } |
91 | 117 |
92 - (void)buildWindowButtons { | 118 - (void)loadView { |
93 base::scoped_nsobject<NSView> buttonContainer( | 119 self.view = [[[NSView alloc] initWithFrame:NSZeroRect] autorelease]; |
groby-ooo-7-16
2015/02/18 19:01:19
Ideally, loadView does not reference [self view] -
bondd
2015/02/26 01:25:08
Done.
| |
94 [[NSView alloc] initWithFrame:NSZeroRect]); | |
95 | 120 |
96 base::scoped_nsobject<NSButton> button( | 121 autofill::CardUnmaskPromptController* controller = bridge_->GetController(); |
122 if (!controller) | |
123 return; | |
bondd
2015/02/18 02:49:28
Is this okay? Should I expose WeakPtr from CardUnm
groby-ooo-7-16
2015/02/18 19:01:19
I can't see any benefit from exposing the WeakPtr
bondd
2015/02/26 01:25:08
Okay, assuming all of this code is run on the same
| |
124 | |
125 // Title label. | |
126 NSTextField* title = constrained_window::CreateLabel(); | |
127 [title setAttributedStringValue:constrained_window::GetAttributedLabelString( | |
groby-ooo-7-16
2015/02/18 19:01:19
Is that clang-format? Because it looks horrible :)
bondd
2015/02/26 01:25:09
Added an intermediate variable to make the formatt
| |
128 SysUTF16ToNSString( | |
129 controller->GetWindowTitle()), | |
130 chrome_style::kTitleFontStyle, | |
131 NSNaturalTextAlignment, | |
132 NSLineBreakByWordWrapping)]; | |
133 [title sizeToFit]; | |
134 [[self view] addSubview:title]; | |
135 | |
136 // Instructions label. | |
137 NSTextField* instructions = constrained_window::CreateLabel(); | |
138 [instructions | |
139 setAttributedStringValue:constrained_window::GetAttributedLabelString( | |
140 SysUTF16ToNSString( | |
141 controller->GetInstructionsMessage()), | |
142 chrome_style::kTextFontStyle, | |
143 NSNaturalTextAlignment, | |
144 NSLineBreakByWordWrapping)]; | |
145 // No need to call sizeToFit here. Size is calculated later. | |
146 [[self view] addSubview:instructions]; | |
147 | |
148 base::scoped_nsobject<AutofillPopUpButton> monthPopup; | |
groby-ooo-7-16
2015/02/18 19:01:19
Do you ever parent these popups to a view?
bondd
2015/02/26 01:25:08
-addSubview is sent 5 lines below this comment. Or
| |
149 base::scoped_nsobject<AutofillPopUpButton> yearPopup; | |
150 if (controller->ShouldRequestExpirationDate()) { | |
groby-ooo-7-16
2015/02/18 19:01:19
There are 3 different places that special-case Sho
bondd
2015/02/26 01:25:08
I've reduced it to two places: once for creation a
| |
151 // Month. | |
152 monthPopup.reset(CreateDatePopup(month_combobox_model_)); | |
153 [[self view] addSubview:monthPopup]; | |
154 | |
155 // Year. | |
156 yearPopup.reset(CreateDatePopup(year_combobox_model_)); | |
157 [[self view] addSubview:yearPopup]; | |
158 } | |
159 | |
160 // CVC text input. | |
161 base::scoped_nsobject<AutofillTextField> cvcInput( | |
groby-ooo-7-16
2015/02/18 19:01:19
Does this need to be an AutofillTextField?
bondd
2015/02/26 01:25:09
Done.
| |
162 [[AutofillTextField alloc] init]); | |
groby-ooo-7-16
2015/02/18 19:01:19
You should prefer initWithFrame: over init - init
bondd
2015/02/26 01:25:08
Done.
| |
163 [[cvcInput cell] | |
164 setPlaceholderString:l10n_util::GetNSString( | |
165 IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC)]; | |
166 [[cvcInput cell] setScrollable:YES]; | |
167 [cvcInput sizeToFit]; | |
168 [cvcInput | |
169 setFrameSize:NSMakeSize(kCvcInputWidth, NSHeight([cvcInput frame]))]; | |
170 [[self view] addSubview:cvcInput]; | |
171 | |
172 // CVC image. | |
173 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
174 NSImage* image = | |
175 rb.GetNativeImageNamed(controller->GetCvcImageRid()).ToNSImage(); | |
176 | |
177 base::scoped_nsobject<NSImageView> cvcImage([[NSImageView alloc] init]); | |
178 [cvcImage setImage:image]; | |
179 | |
180 const CGFloat inputRowHeight = NSHeight([cvcInput frame]); | |
bondd
2015/02/18 02:49:28
This assumes that cvcInput is the tallest element
groby-ooo-7-16
2015/02/18 19:01:19
I have no idea what the guarantees are :) In gener
bondd
2015/02/26 01:25:08
Changed it to make no assumptions about element he
| |
181 [cvcImage setFrameSize:NSMakeSize([image size].width, inputRowHeight)]; | |
182 [[self view] addSubview:cvcImage]; | |
183 | |
184 // Cancel button. | |
185 base::scoped_nsobject<NSButton> cancelButton( | |
97 [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]); | 186 [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]); |
98 [button setTitle:l10n_util::GetNSStringWithFixup(IDS_CANCEL)]; | 187 [cancelButton setTitle:l10n_util::GetNSStringWithFixup(IDS_CANCEL)]; |
99 [button setKeyEquivalent:kKeyEquivalentEscape]; | 188 [cancelButton setKeyEquivalent:kKeyEquivalentEscape]; |
100 [button setTarget:self]; | 189 [cancelButton setTarget:self]; |
101 [button setAction:@selector(closeSheet:)]; | 190 [cancelButton setAction:@selector(closeSheet:)]; |
102 [button sizeToFit]; | 191 [cancelButton sizeToFit]; |
103 [buttonContainer addSubview:button]; | 192 [[self view] addSubview:cancelButton]; |
104 | 193 |
105 CGFloat nextX = NSMaxX([button frame]) + kButtonGap; | 194 // Verify button. |
106 button.reset([[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]); | 195 base::scoped_nsobject<NSButton> verifyButton( |
107 [button setFrameOrigin:NSMakePoint(nextX, 0)]; | 196 [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]); |
108 [button setTitle:l10n_util::GetNSStringWithFixup( | 197 // TODO(bondd): use l10n string. |
109 IDS_AUTOFILL_DIALOG_SUBMIT_BUTTON)]; | 198 [verifyButton setTitle:@"Verify"]; |
110 [button setKeyEquivalent:kKeyEquivalentReturn]; | 199 [verifyButton setKeyEquivalent:kKeyEquivalentReturn]; |
111 [button setTarget:self]; | 200 [verifyButton setTarget:self]; |
112 [button setAction:@selector(closeSheet:)]; | 201 [verifyButton setAction:@selector(closeSheet:)]; |
113 [button sizeToFit]; | 202 [verifyButton sizeToFit]; |
114 [buttonContainer addSubview:button]; | 203 [[self view] addSubview:verifyButton]; |
115 | 204 |
116 const CGFloat dialogOffset = NSWidth([[self window] frame]) - | 205 // Calculate dialog width. |
117 chrome_style::kHorizontalPadding - | 206 CGFloat inputRowWidth = |
118 NSMaxX([button frame]); | 207 NSWidth([cvcInput frame]) + kButtonGap + NSWidth([cvcImage frame]); |
119 [buttonContainer | 208 if (controller->ShouldRequestExpirationDate()) { |
120 setFrame:NSMakeRect(dialogOffset, chrome_style::kClientBottomPadding, | 209 inputRowWidth += NSWidth([monthPopup frame]) + NSWidth([yearPopup frame]) + |
121 NSMaxX([button frame]), NSMaxY([button frame]))]; | 210 kButtonGap * 2; |
211 } | |
212 CGFloat dialogWidth = std::max(NSWidth([title frame]), inputRowWidth) + | |
213 chrome_style::kHorizontalPadding * 2; | |
214 dialogWidth = std::max(dialogWidth, kDialogMinWidth); | |
122 | 215 |
123 [[[self window] contentView] addSubview:buttonContainer]; | 216 // Layout the elements, starting at the bottom and moving up. |
bondd
2015/02/18 02:49:28
Doing creation and layout in the same message, per
groby-ooo-7-16
2015/02/18 19:01:19
Perfectly fine, unless you'll need to re-layout. Y
| |
217 | |
218 CGFloat curX = dialogWidth - chrome_style::kHorizontalPadding; | |
219 CGFloat curY = chrome_style::kClientBottomPadding; | |
220 | |
221 // Verify and Cancel buttons. | |
222 curX -= NSWidth([verifyButton frame]); | |
223 [verifyButton setFrameOrigin:NSMakePoint(curX, curY)]; | |
224 curX -= kButtonGap + NSWidth([cancelButton frame]); | |
225 [cancelButton setFrameOrigin:NSMakePoint(curX, curY)]; | |
226 curY += NSHeight([cancelButton frame]); | |
227 | |
228 // Input row. | |
229 curX = chrome_style::kHorizontalPadding; | |
230 curY += chrome_style::kRowPadding; | |
231 | |
232 if (controller->ShouldRequestExpirationDate()) { | |
233 [monthPopup setFrameOrigin:NSMakePoint(curX, curY)]; | |
234 curX += NSWidth([monthPopup frame]) + kButtonGap; | |
235 [yearPopup setFrameOrigin:NSMakePoint(curX, curY)]; | |
236 curX += NSWidth([yearPopup frame]) + kButtonGap; | |
237 } | |
238 | |
239 [cvcInput setFrameOrigin:NSMakePoint(curX, curY)]; | |
240 curX += NSWidth([cvcInput frame]) + kButtonGap; | |
241 [cvcImage setFrameOrigin:NSMakePoint(curX, curY)]; | |
242 curX += NSWidth([cvcImage frame]); | |
243 | |
244 // Instruction label. | |
245 curX = chrome_style::kHorizontalPadding; | |
246 curY += inputRowHeight + chrome_style::kRowPadding; | |
247 [instructions setFrameOrigin:NSMakePoint(curX, curY)]; | |
248 CGFloat maxTextWidth = dialogWidth - chrome_style::kHorizontalPadding * 2; | |
249 NSSize instructionsSize = [[instructions cell] | |
groby-ooo-7-16
2015/02/18 19:01:19
Why use cellsize? This ignores any chrome around t
bondd
2015/02/26 01:25:08
Instructions text needs to wrap onto multiple line
groby-ooo-7-16
2015/02/28 00:49:17
Acknowledged.
| |
250 cellSizeForBounds:NSMakeRect(0.0, 0.0, maxTextWidth, CGFLOAT_MAX)]; | |
251 [instructions setFrameSize:instructionsSize]; | |
252 | |
253 // Title label. | |
254 curY += instructionsSize.height + chrome_style::kRowPadding; | |
255 [title setFrameOrigin:NSMakePoint(curX, curY)]; | |
256 | |
257 // Dialog size. | |
258 CGFloat dialogHeight = | |
259 curY + NSHeight([title frame]) + chrome_style::kTitleTopPadding; | |
260 | |
261 [[self view] setFrame:NSMakeRect(0, 0, dialogWidth, dialogHeight)]; | |
124 } | 262 } |
125 | 263 |
126 @end | 264 @end |
OLD | NEW |