Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / autofill / autofill_main_container.mm
blobb406df249be8b2127f9620e96df6321b96ef5831
1 // Copyright (c) 2013 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/autofill/autofill_main_container.h"
7 #include <algorithm>
8 #include <cmath>
10 #include "base/mac/foundation_util.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "chrome/browser/ui/autofill/autofill_dialog_view_delegate.h"
13 #include "chrome/browser/ui/chrome_style.h"
14 #import "chrome/browser/ui/cocoa/autofill/autofill_details_container.h"
15 #include "chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h"
16 #import "chrome/browser/ui/cocoa/autofill/autofill_notification_container.h"
17 #import "chrome/browser/ui/cocoa/autofill/autofill_tooltip_controller.h"
18 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
19 #import "chrome/browser/ui/cocoa/key_equivalent_constants.h"
20 #include "grit/theme_resources.h"
21 #include "skia/ext/skia_utils_mac.h"
22 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
23 #import "ui/base/cocoa/controls/blue_label_button.h"
24 #import "ui/base/cocoa/controls/hyperlink_text_view.h"
25 #include "ui/base/cocoa/window_size_constants.h"
26 #include "ui/gfx/range/range.h"
28 namespace {
30 // Padding between buttons and the last suggestion or details view. The mock
31 // has a total of 30px - but 10px are already provided by details/suggestions.
32 const CGFloat kButtonVerticalPadding = 20.0;
34 }  // namespace
36 @interface AutofillMainContainer (Private)
37 - (void)buildWindowButtons;
38 - (void)layoutButtons;
39 - (void)updateButtons;
40 @end
43 @implementation AutofillMainContainer
45 @synthesize target = target_;
47 - (id)initWithDelegate:(autofill::AutofillDialogViewDelegate*)delegate {
48   if (self = [super init]) {
49     delegate_ = delegate;
50   }
51   return self;
54 - (void)loadView {
55   [self buildWindowButtons];
57   base::scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:NSZeroRect]);
58   [view setAutoresizesSubviews:YES];
59   [view setSubviews:@[buttonContainer_]];
60   [self setView:view];
62   // Set up "Save in Chrome" checkbox.
63   saveInChromeCheckbox_.reset([[NSButton alloc] initWithFrame:NSZeroRect]);
64   [saveInChromeCheckbox_ setButtonType:NSSwitchButton];
65   [saveInChromeCheckbox_ setTitle:
66       base::SysUTF16ToNSString(delegate_->SaveLocallyText())];
67   [saveInChromeCheckbox_ sizeToFit];
68   [[self view] addSubview:saveInChromeCheckbox_];
70   saveInChromeTooltip_.reset(
71       [[AutofillTooltipController alloc]
72             initWithArrowLocation:info_bubble::kTopCenter]);
73   [saveInChromeTooltip_ setImage:
74       ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
75           IDR_AUTOFILL_TOOLTIP_ICON).ToNSImage()];
76   [saveInChromeTooltip_ setMessage:
77       base::SysUTF16ToNSString(delegate_->SaveLocallyTooltip())];
78   [[self view] addSubview:[saveInChromeTooltip_ view]];
79   [self updateSaveInChrome];
81   detailsContainer_.reset(
82       [[AutofillDetailsContainer alloc] initWithDelegate:delegate_]);
83   NSSize frameSize = [[detailsContainer_ view] frame].size;
84   [[detailsContainer_ view] setFrameOrigin:
85       NSMakePoint(0, NSHeight([buttonContainer_ frame]))];
86   frameSize.height += NSHeight([buttonContainer_ frame]);
87   [[self view] setFrameSize:frameSize];
88   [[self view] addSubview:[detailsContainer_ view]];
90   notificationContainer_.reset(
91       [[AutofillNotificationContainer alloc] initWithDelegate:delegate_]);
92   [[self view] addSubview:[notificationContainer_ view]];
95 - (NSSize)decorationSizeForWidth:(CGFloat)width {
96   NSSize buttonSize = [buttonContainer_ frame].size;
97   NSSize buttonStripSize =
98       NSMakeSize(buttonSize.width + chrome_style::kHorizontalPadding,
99                  buttonSize.height + kButtonVerticalPadding +
100                      chrome_style::kClientBottomPadding);
102   NSSize size = NSMakeSize(std::max(buttonStripSize.width, width),
103                            buttonStripSize.height);
104   NSSize notificationSize =
105       [notificationContainer_ preferredSizeForWidth:width];
106   size.height += notificationSize.height;
108   return size;
111 - (NSSize)preferredSize {
112   NSSize detailsSize = [detailsContainer_ preferredSize];
113   NSSize decorationSize = [self decorationSizeForWidth:detailsSize.width];
115   NSSize size = NSMakeSize(std::max(decorationSize.width, detailsSize.width),
116                            decorationSize.height + detailsSize.height);
117   size.height += autofill::kDetailVerticalPadding;
119   return size;
122 - (void)performLayout {
123   NSRect bounds = [[self view] bounds];
125   CGFloat currentY = 0.0;
126   NSRect buttonFrame = [buttonContainer_ frame];
127   buttonFrame.origin.y = currentY + chrome_style::kClientBottomPadding;
128   [buttonContainer_ setFrameOrigin:buttonFrame.origin];
129   currentY = NSMaxY(buttonFrame) + kButtonVerticalPadding;
131   NSRect checkboxFrame = [saveInChromeCheckbox_ frame];
132   [saveInChromeCheckbox_ setFrameOrigin:
133       NSMakePoint(chrome_style::kHorizontalPadding,
134                   NSMidY(buttonFrame) - NSHeight(checkboxFrame) / 2.0)];
136   NSRect tooltipFrame = [[saveInChromeTooltip_ view] frame];
137   [[saveInChromeTooltip_ view] setFrameOrigin:
138       NSMakePoint(NSMaxX([saveInChromeCheckbox_ frame]) + autofill::kButtonGap,
139                   NSMidY(buttonFrame) - (NSHeight(tooltipFrame) / 2.0))];
141   NSRect notificationFrame = NSZeroRect;
142   notificationFrame.size = [notificationContainer_ preferredSizeForWidth:
143       NSWidth(bounds)];
145   // Buttons/checkbox/legal take up lower part of view, notifications the
146   // upper part. Adjust the detailsContainer to take up the remainder.
147   CGFloat remainingHeight =
148       NSHeight(bounds) - currentY - NSHeight(notificationFrame);
149   NSRect containerFrame =
150       NSMakeRect(0, currentY, NSWidth(bounds), remainingHeight);
151   [[detailsContainer_ view] setFrame:containerFrame];
152   [detailsContainer_ performLayout];
154   notificationFrame.origin = NSMakePoint(0, NSMaxY(containerFrame));
155   [[notificationContainer_ view] setFrame:notificationFrame];
156   [notificationContainer_ performLayout];
159 - (void)buildWindowButtons {
160   if (buttonContainer_.get())
161     return;
163   buttonContainer_.reset([[GTMWidthBasedTweaker alloc] initWithFrame:
164       ui::kWindowSizeDeterminedLater]);
165   [buttonContainer_
166       setAutoresizingMask:(NSViewMinXMargin | NSViewMaxYMargin)];
168   base::scoped_nsobject<NSButton> button(
169       [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]);
170   [button setKeyEquivalent:kKeyEquivalentEscape];
171   [button setTarget:target_];
172   [button setAction:@selector(cancel:)];
173   [button sizeToFit];
174   [buttonContainer_ addSubview:button];
176   CGFloat nextX = NSMaxX([button frame]) + autofill::kButtonGap;
177   button.reset([[BlueLabelButton alloc] initWithFrame:NSZeroRect]);
178   [button setFrameOrigin:NSMakePoint(nextX, 0)];
179   [button setKeyEquivalent:kKeyEquivalentReturn];
180   [button setTarget:target_];
181   [button setAction:@selector(accept:)];
182   [buttonContainer_ addSubview:button];
183   [self updateButtons];
185   NSRect frame = NSMakeRect(
186       -NSMaxX([button frame]) - chrome_style::kHorizontalPadding, 0,
187       NSMaxX([button frame]), NSHeight([button frame]));
188   [buttonContainer_ setFrame:frame];
191 - (void)layoutButtons {
192   base::scoped_nsobject<GTMUILocalizerAndLayoutTweaker> layoutTweaker(
193       [[GTMUILocalizerAndLayoutTweaker alloc] init]);
194   [layoutTweaker tweakUI:buttonContainer_];
196   // Now ensure both buttons have the same height. The second button is
197   // known to be the larger one.
198   CGFloat buttonHeight =
199       NSHeight([[[buttonContainer_ subviews] objectAtIndex:1] frame]);
201   // Force first button to be the same height.
202   NSView* button = [[buttonContainer_ subviews] objectAtIndex:0];
203   NSSize buttonSize = [button frame].size;
204   buttonSize.height = buttonHeight;
205   [button setFrameSize:buttonSize];
208 - (void)updateButtons {
209   NSButton* button = base::mac::ObjCCastStrict<NSButton>(
210       [[buttonContainer_ subviews] objectAtIndex:0]);
211   [button setTitle:base::SysUTF16ToNSString(delegate_->CancelButtonText())];
212   button = base::mac::ObjCCastStrict<NSButton>(
213     [[buttonContainer_ subviews] objectAtIndex:1]);
214   [button setTitle:base::SysUTF16ToNSString(delegate_->ConfirmButtonText())];
215   [self layoutButtons];
218 - (AutofillSectionContainer*)sectionForId:(autofill::DialogSection)section {
219   return [detailsContainer_ sectionForId:section];
222 - (void)modelChanged {
223   [self updateSaveInChrome];
224   [self updateButtons];
225   [detailsContainer_ modelChanged];
228 - (BOOL)saveDetailsLocally {
229   return [saveInChromeCheckbox_ state] == NSOnState;
232 - (void)updateNotificationArea {
233   [notificationContainer_ setNotifications:delegate_->CurrentNotifications()];
234   id delegate = [[[self view] window] windowController];
235   if ([delegate respondsToSelector:@selector(requestRelayout)])
236     [delegate performSelector:@selector(requestRelayout)];
239 - (BOOL)validate {
240   return [detailsContainer_ validate];
243 - (void)updateSaveInChrome {
244   [saveInChromeCheckbox_ setHidden:!delegate_->ShouldOfferToSaveInChrome()];
245   [[saveInChromeTooltip_ view] setHidden:[saveInChromeCheckbox_ isHidden]];
246   [saveInChromeCheckbox_ setState:
247       (delegate_->ShouldSaveInChrome() ? NSOnState : NSOffState)];
250 - (void)makeFirstInvalidInputFirstResponder {
251   NSView* field = [detailsContainer_ firstInvalidField];
252   if (!field)
253     return;
255   [detailsContainer_ scrollToView:field];
256   [[[self view] window] makeFirstResponder:field];
259 - (void)scrollInitialEditorIntoViewAndMakeFirstResponder {
260   // Try to focus on the first invalid field. If there isn't one, focus on the
261   // first editable field instead.
262   NSView* field = [detailsContainer_ firstInvalidField];
263   if (!field)
264     field = [detailsContainer_ firstVisibleField];
265   if (!field)
266     return;
268   [detailsContainer_ scrollToView:field];
269   [[[self view] window] makeFirstResponder:field];
272 - (void)updateErrorBubble {
273   [detailsContainer_ updateErrorBubble];
276 @end
279 @implementation AutofillMainContainer (Testing)
281 - (NSButton*)saveInChromeCheckboxForTesting {
282   return saveInChromeCheckbox_.get();
285 - (NSButton*)saveInChromeTooltipForTesting {
286   return base::mac::ObjCCast<NSButton>([saveInChromeTooltip_ view]);
289 @end