| Index: chrome/browser/ui/cocoa/autofill/autofill_section_container.mm
|
| diff --git a/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm
|
| deleted file mode 100644
|
| index b6f96d8f9df3725b8de77f90880a8a5725758802..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm
|
| +++ /dev/null
|
| @@ -1,759 +0,0 @@
|
| -// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#import "chrome/browser/ui/cocoa/autofill/autofill_section_container.h"
|
| -
|
| -#include <stddef.h>
|
| -
|
| -#include <algorithm>
|
| -
|
| -#include "base/mac/foundation_util.h"
|
| -#include "base/mac/sdk_forward_declarations.h"
|
| -#include "base/strings/sys_string_conversions.h"
|
| -#include "base/strings/utf_string_conversions.h"
|
| -#include "chrome/browser/ui/autofill/autofill_dialog_view_delegate.h"
|
| -#include "chrome/browser/ui/chrome_style.h"
|
| -#import "chrome/browser/ui/cocoa/autofill/autofill_pop_up_button.h"
|
| -#import "chrome/browser/ui/cocoa/autofill/autofill_section_view.h"
|
| -#import "chrome/browser/ui/cocoa/autofill/autofill_suggestion_container.h"
|
| -#import "chrome/browser/ui/cocoa/autofill/autofill_textfield.h"
|
| -#import "chrome/browser/ui/cocoa/autofill/autofill_tooltip_controller.h"
|
| -#import "chrome/browser/ui/cocoa/autofill/layout_view.h"
|
| -#include "chrome/browser/ui/cocoa/autofill/simple_grid_layout.h"
|
| -#import "chrome/browser/ui/cocoa/image_button_cell.h"
|
| -#import "chrome/browser/ui/cocoa/menu_button.h"
|
| -#include "components/autofill/core/browser/autofill_type.h"
|
| -#include "content/public/browser/native_web_keyboard_event.h"
|
| -#include "grit/components_scaled_resources.h"
|
| -#include "grit/theme_resources.h"
|
| -#import "ui/base/cocoa/menu_controller.h"
|
| -#include "ui/base/l10n/l10n_util_mac.h"
|
| -#include "ui/base/models/combobox_model.h"
|
| -#include "ui/base/resource/resource_bundle.h"
|
| -
|
| -namespace {
|
| -
|
| -// Constants used for layouting controls. These variables are copied from
|
| -// "ui/views/layout/layout_constants.h".
|
| -
|
| -// Horizontal spacing between controls that are logically related.
|
| -const int kRelatedControlHorizontalSpacing = 8;
|
| -
|
| -// Vertical spacing between controls that are logically related.
|
| -const int kRelatedControlVerticalSpacing = 8;
|
| -
|
| -// TODO(estade): pull out these constants, and figure out better values
|
| -// for them. Note: These are duplicated from Views code.
|
| -
|
| -// Fixed width for the details section.
|
| -const int kDetailsWidth = 440;
|
| -
|
| -// Top/bottom inset for contents of a detail section.
|
| -const size_t kDetailSectionInset = 10;
|
| -
|
| -// Vertical padding around the section header.
|
| -const CGFloat kVerticalHeaderPadding = 6;
|
| -
|
| -// If the Autofill data comes from a credit card, make sure to overwrite the
|
| -// CC comboboxes (even if they already have something in them). If the
|
| -// Autofill data comes from an AutofillProfile, leave the comboboxes alone.
|
| -// TODO(groby): This kind of logic should _really_ live on the delegate.
|
| -bool ShouldOverwriteComboboxes(autofill::DialogSection section,
|
| - autofill::ServerFieldType type) {
|
| - if (autofill::AutofillType(type).group() != autofill::CREDIT_CARD) {
|
| - return false;
|
| - }
|
| -
|
| - return section == autofill::SECTION_CC;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -@interface AutofillSectionContainer ()
|
| -
|
| -// An input field has been edited or activated - inform the delegate and
|
| -// possibly reset the validity of the input (if it's a textfield).
|
| -- (void)fieldEditedOrActivated:(NSControl<AutofillInputField>*)field
|
| - edited:(BOOL)edited;
|
| -
|
| -// Convenience method to retrieve a field type via the control's tag.
|
| -- (autofill::ServerFieldType)fieldTypeForControl:(NSControl*)control;
|
| -
|
| -// Find the DetailInput* associated with a field type.
|
| -- (const autofill::DetailInput*)detailInputForType:
|
| - (autofill::ServerFieldType)type;
|
| -
|
| -// Takes an NSArray of controls and builds a FieldValueMap from them.
|
| -// Translates between Cocoa code and delegate, essentially.
|
| -// All controls must inherit from NSControl and conform to AutofillInputView.
|
| -- (void)fillDetailOutputs:(autofill::FieldValueMap*)outputs
|
| - fromControls:(NSArray*)controls;
|
| -
|
| -// Updates input fields based on delegate status. If |shouldClobber| is YES,
|
| -// will clobber existing data and reset fields to the initial values.
|
| -- (void)updateAndClobber:(BOOL)shouldClobber;
|
| -
|
| -// Return YES if this is a section that contains CC info. (And, more
|
| -// importantly, a potential CVV field)
|
| -- (BOOL)isCreditCardSection;
|
| -
|
| -// Create properly styled label for section. Autoreleased.
|
| -- (NSTextField*)makeDetailSectionLabel:(NSString*)labelText;
|
| -
|
| -// Create a button offering input suggestions.
|
| -- (MenuButton*)makeSuggestionButton;
|
| -
|
| -// Create a view with all inputs requested by |delegate_| and resets |input_|.
|
| -- (void)makeInputControls;
|
| -
|
| -// Refresh all field icons based on |delegate_| status.
|
| -- (void)updateFieldIcons;
|
| -
|
| -@end
|
| -
|
| -@implementation AutofillSectionContainer
|
| -
|
| -@synthesize section = section_;
|
| -@synthesize validationDelegate = validationDelegate_;
|
| -
|
| -- (id)initWithDelegate:(autofill::AutofillDialogViewDelegate*)delegate
|
| - forSection:(autofill::DialogSection)section {
|
| - if (self = [super init]) {
|
| - section_ = section;
|
| - delegate_ = delegate;
|
| - }
|
| - return self;
|
| -}
|
| -
|
| -- (void)getInputs:(autofill::FieldValueMap*)output {
|
| - [self fillDetailOutputs:output fromControls:[inputs_ subviews]];
|
| -}
|
| -
|
| -// Note: This corresponds to Views' "UpdateDetailsGroupState".
|
| -- (void)modelChanged {
|
| - ui::MenuModel* suggestionModel = delegate_->MenuModelForSection(section_);
|
| - menuController_.reset([[MenuController alloc] initWithModel:suggestionModel
|
| - useWithPopUpButtonCell:YES]);
|
| - NSMenu* menu = [menuController_ menu];
|
| -
|
| - const BOOL hasSuggestions = [menu numberOfItems] > 0;
|
| - [suggestButton_ setHidden:!hasSuggestions];
|
| -
|
| - [suggestButton_ setAttachedMenu:menu];
|
| -
|
| - [self updateSuggestionState];
|
| -
|
| - if (![[self view] isHidden])
|
| - [self validateFor:autofill::VALIDATE_EDIT];
|
| -
|
| - // Always request re-layout on state change.
|
| - [self requestRelayout];
|
| -}
|
| -
|
| -- (void)requestRelayout {
|
| - id delegate = [[view_ window] windowController];
|
| - if ([delegate respondsToSelector:@selector(requestRelayout)])
|
| - [delegate performSelector:@selector(requestRelayout)];
|
| -}
|
| -
|
| -- (void)loadView {
|
| - [self makeInputControls];
|
| -
|
| - base::string16 labelText = delegate_->LabelForSection(section_);
|
| - label_.reset(
|
| - [[self makeDetailSectionLabel:base::SysUTF16ToNSString(labelText)]
|
| - retain]);
|
| -
|
| - suggestButton_.reset([[self makeSuggestionButton] retain]);
|
| - suggestContainer_.reset([[AutofillSuggestionContainer alloc] init]);
|
| -
|
| - view_.reset([[AutofillSectionView alloc] initWithFrame:NSZeroRect]);
|
| - [self setView:view_];
|
| - [view_ setSubviews:
|
| - @[label_, inputs_, [suggestContainer_ view], suggestButton_]];
|
| - if (tooltipController_) {
|
| - [view_ addSubview:[tooltipController_ view]
|
| - positioned:NSWindowAbove
|
| - relativeTo:inputs_];
|
| - }
|
| -
|
| - if ([self isCreditCardSection]) {
|
| - // Credit card sections *MUST* have a CREDIT_CARD_VERIFICATION_CODE input.
|
| - DCHECK([self detailInputForType:autofill::CREDIT_CARD_VERIFICATION_CODE]);
|
| - [[suggestContainer_ inputField] setTag:
|
| - autofill::CREDIT_CARD_VERIFICATION_CODE];
|
| - [[suggestContainer_ inputField] setInputDelegate:self];
|
| - }
|
| -
|
| - [self modelChanged];
|
| -}
|
| -
|
| -- (NSSize)preferredSize {
|
| - if ([view_ isHidden])
|
| - return NSZeroSize;
|
| -
|
| - NSSize labelSize = [label_ frame].size; // Assumes sizeToFit was called.
|
| - CGFloat controlHeight = [inputs_ preferredHeightForWidth:kDetailsWidth];
|
| - if (showSuggestions_)
|
| - controlHeight = [suggestContainer_ preferredSize].height;
|
| -
|
| - return NSMakeSize(kDetailsWidth + 2 * chrome_style::kHorizontalPadding,
|
| - labelSize.height + kVerticalHeaderPadding +
|
| - controlHeight + 2 * kDetailSectionInset);
|
| -}
|
| -
|
| -- (void)performLayout {
|
| - if ([view_ isHidden])
|
| - return;
|
| -
|
| - NSSize buttonSize = [suggestButton_ frame].size; // Assume sizeToFit.
|
| - NSSize labelSize = [label_ frame].size; // Assumes sizeToFit was called.
|
| - CGFloat controlHeight = [inputs_ preferredHeightForWidth:kDetailsWidth];
|
| - if (showSuggestions_)
|
| - controlHeight = [suggestContainer_ preferredSize].height;
|
| -
|
| - NSRect viewFrame = NSZeroRect;
|
| - viewFrame.size = [self preferredSize];
|
| -
|
| - NSRect contentFrame = NSInsetRect(viewFrame,
|
| - chrome_style::kHorizontalPadding,
|
| - kDetailSectionInset);
|
| - NSRect controlFrame, labelFrame, buttonFrame;
|
| -
|
| - // Label is top left, suggestion button is top right, controls are below that.
|
| - NSDivideRect(contentFrame, &labelFrame, &controlFrame,
|
| - kVerticalHeaderPadding + labelSize.height, NSMaxYEdge);
|
| - NSDivideRect(labelFrame, &buttonFrame, &labelFrame,
|
| - buttonSize.width, NSMaxXEdge);
|
| -
|
| - labelFrame = NSOffsetRect(labelFrame, 0, kVerticalHeaderPadding);
|
| - labelFrame.size = labelSize;
|
| -
|
| - buttonFrame = NSOffsetRect(buttonFrame, 0, 5);
|
| - buttonFrame.size = buttonSize;
|
| -
|
| - if (showSuggestions_) {
|
| - [[suggestContainer_ view] setFrame:controlFrame];
|
| - [suggestContainer_ performLayout];
|
| - } else {
|
| - [inputs_ setFrame:controlFrame];
|
| - }
|
| - [label_ setFrame:labelFrame];
|
| - [suggestButton_ setFrame:buttonFrame];
|
| - [inputs_ setHidden:showSuggestions_];
|
| - [[suggestContainer_ view] setHidden:!showSuggestions_];
|
| - [view_ setFrameSize:viewFrame.size];
|
| - if (tooltipController_) {
|
| - [[tooltipController_ view] setHidden:showSuggestions_];
|
| - NSRect tooltipIconFrame = [tooltipField_ decorationFrame];
|
| - tooltipIconFrame.origin =
|
| - [[self view] convertPoint:tooltipIconFrame.origin
|
| - fromView:[tooltipField_ superview]];
|
| - [[tooltipController_ view] setFrame:tooltipIconFrame];
|
| - }
|
| -}
|
| -
|
| -- (KeyEventHandled)keyEvent:(NSEvent*)event forInput:(id)sender {
|
| - content::NativeWebKeyboardEvent webEvent(event);
|
| -
|
| - // Only handle keyDown, to handle key repeats without duplicates.
|
| - if (webEvent.type != content::NativeWebKeyboardEvent::RawKeyDown)
|
| - return kKeyEventNotHandled;
|
| -
|
| - // Allow the delegate to intercept key messages.
|
| - if (delegate_->HandleKeyPressEventInInput(webEvent))
|
| - return kKeyEventHandled;
|
| - return kKeyEventNotHandled;
|
| -}
|
| -
|
| -- (void)onMouseDown:(NSControl<AutofillInputField>*)field {
|
| - [self fieldEditedOrActivated:field edited:NO];
|
| - [validationDelegate_ updateMessageForField:field];
|
| -}
|
| -
|
| -- (void)fieldBecameFirstResponder:(NSControl<AutofillInputField>*)field {
|
| - [validationDelegate_ updateMessageForField:field];
|
| -}
|
| -
|
| -- (void)didChange:(id)sender {
|
| - [self fieldEditedOrActivated:sender edited:YES];
|
| -}
|
| -
|
| -- (void)didEndEditing:(id)sender {
|
| - delegate_->FocusMoved();
|
| - [validationDelegate_ hideErrorBubble];
|
| - [self validateFor:autofill::VALIDATE_EDIT];
|
| -}
|
| -
|
| -- (void)updateSuggestionState {
|
| - const autofill::SuggestionState& suggestionState =
|
| - delegate_->SuggestionStateForSection(section_);
|
| - showSuggestions_ = suggestionState.visible;
|
| -
|
| - if (!suggestionState.extra_text.empty()) {
|
| - NSString* extraText =
|
| - base::SysUTF16ToNSString(suggestionState.extra_text);
|
| - NSImage* extraIcon = suggestionState.extra_icon.AsNSImage();
|
| - [suggestContainer_ showInputField:extraText withIcon:extraIcon];
|
| - }
|
| -
|
| - // NOTE: It's important to set the input field, if there is one, _before_
|
| - // setting the suggestion text, since the suggestion container needs to
|
| - // account for the input field's width when deciding which of the two string
|
| - // representations to use.
|
| - NSString* verticallyCompactText =
|
| - base::SysUTF16ToNSString(suggestionState.vertically_compact_text);
|
| - NSString* horizontallyCompactText =
|
| - base::SysUTF16ToNSString(suggestionState.horizontally_compact_text);
|
| - [suggestContainer_
|
| - setSuggestionWithVerticallyCompactText:verticallyCompactText
|
| - horizontallyCompactText:horizontallyCompactText
|
| - icon:suggestionState.icon.AsNSImage()
|
| - maxWidth:kDetailsWidth];
|
| -
|
| - [view_ setShouldHighlightOnHover:showSuggestions_];
|
| - if (showSuggestions_)
|
| - [view_ setClickTarget:suggestButton_];
|
| - else
|
| - [view_ setClickTarget:nil];
|
| - [view_ setHidden:!delegate_->SectionIsActive(section_)];
|
| -}
|
| -
|
| -- (void)update {
|
| - [self updateAndClobber:YES];
|
| - [view_ updateHoverState];
|
| -}
|
| -
|
| -- (void)fillForType:(const autofill::ServerFieldType)type {
|
| - // Make sure to overwrite the originating input if it is a text field.
|
| - AutofillTextField* field =
|
| - base::mac::ObjCCast<AutofillTextField>([inputs_ viewWithTag:type]);
|
| - [field setFieldValue:@""];
|
| -
|
| - if (ShouldOverwriteComboboxes(section_, type)) {
|
| - for (NSControl* control in [inputs_ subviews]) {
|
| - AutofillPopUpButton* popup =
|
| - base::mac::ObjCCast<AutofillPopUpButton>(control);
|
| - if (popup) {
|
| - autofill::ServerFieldType fieldType =
|
| - [self fieldTypeForControl:popup];
|
| - if (autofill::AutofillType(fieldType).group() ==
|
| - autofill::CREDIT_CARD) {
|
| - ui::ComboboxModel* model =
|
| - delegate_->ComboboxModelForAutofillType(fieldType);
|
| - DCHECK(model);
|
| - [popup selectItemAtIndex:model->GetDefaultIndex()];
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - [self updateAndClobber:NO];
|
| -}
|
| -
|
| -- (BOOL)validateFor:(autofill::ValidationType)validationType {
|
| - NSArray* fields = nil;
|
| - if (!showSuggestions_) {
|
| - fields = [inputs_ subviews];
|
| - } else if ([self isCreditCardSection]) {
|
| - if (![[suggestContainer_ inputField] isHidden])
|
| - fields = @[ [suggestContainer_ inputField] ];
|
| - }
|
| -
|
| - // Ensure only editable fields are validated.
|
| - fields = [fields filteredArrayUsingPredicate:
|
| - [NSPredicate predicateWithBlock:
|
| - ^BOOL(NSControl<AutofillInputField>* field, NSDictionary* bindings) {
|
| - return [field isEnabled];
|
| - }]];
|
| -
|
| - autofill::FieldValueMap detailOutputs;
|
| - [self fillDetailOutputs:&detailOutputs fromControls:fields];
|
| - autofill::ValidityMessages messages = delegate_->InputsAreValid(
|
| - section_, detailOutputs);
|
| -
|
| - for (NSControl<AutofillInputField>* input in fields) {
|
| - const autofill::ValidityMessage& message =
|
| - messages.GetMessageOrDefault([self fieldTypeForControl:input]);
|
| - if (validationType != autofill::VALIDATE_FINAL && !message.sure)
|
| - continue;
|
| - [input setValidityMessage:base::SysUTF16ToNSString(message.text)];
|
| - [validationDelegate_ updateMessageForField:input];
|
| - }
|
| -
|
| - return !messages.HasErrors();
|
| -}
|
| -
|
| -- (NSString*)suggestionText {
|
| - return showSuggestions_ ? [[suggestContainer_ inputField] stringValue] : nil;
|
| -}
|
| -
|
| -- (void)addInputsToArray:(NSMutableArray*)array {
|
| - [array addObjectsFromArray:[inputs_ subviews]];
|
| -
|
| - // Only credit card sections can have a suggestion input.
|
| - if ([self isCreditCardSection])
|
| - [array addObject:[suggestContainer_ inputField]];
|
| -}
|
| -
|
| -#pragma mark Internal API for AutofillSectionContainer.
|
| -
|
| -- (void)fieldEditedOrActivated:(NSControl<AutofillInputField>*)field
|
| - edited:(BOOL)edited {
|
| - autofill::ServerFieldType type = [self fieldTypeForControl:field];
|
| - base::string16 fieldValue = base::SysNSStringToUTF16([field fieldValue]);
|
| -
|
| - // Get the frame rectangle for the designated field, in screen coordinates.
|
| - NSRect textFrameInScreen = [field convertRect:[field bounds] toView:nil];
|
| - textFrameInScreen = [[field window] convertRectToScreen:textFrameInScreen];
|
| -
|
| - // And adjust for gfx::Rect being flipped compared to OSX coordinates.
|
| - NSScreen* screen = [[NSScreen screens] firstObject];
|
| - textFrameInScreen.origin.y =
|
| - NSMaxY([screen frame]) - NSMaxY(textFrameInScreen);
|
| - gfx::Rect textFrameRect(NSRectToCGRect(textFrameInScreen));
|
| -
|
| - delegate_->UserEditedOrActivatedInput(section_,
|
| - type,
|
| - [self view],
|
| - textFrameRect,
|
| - fieldValue,
|
| - edited);
|
| -
|
| - AutofillTextField* textfield = base::mac::ObjCCast<AutofillTextField>(field);
|
| - if (!textfield)
|
| - return;
|
| -
|
| - // If the field is marked as invalid, check if the text is now valid. Many
|
| - // fields (i.e. CC#) are invalid for most of the duration of editing, so
|
| - // flagging them as invalid prematurely is not helpful. However, correcting a
|
| - // minor mistake (i.e. a wrong CC digit) should immediately result in
|
| - // validation - positive user feedback.
|
| - if ([textfield invalid] && edited) {
|
| - base::string16 message = delegate_->InputValidityMessage(section_,
|
| - type,
|
| - fieldValue);
|
| - [textfield setValidityMessage:base::SysUTF16ToNSString(message)];
|
| -
|
| - // If the field transitioned from invalid to valid, re-validate the group,
|
| - // since inter-field checks become meaningful with valid fields.
|
| - if (![textfield invalid])
|
| - [self validateFor:autofill::VALIDATE_EDIT];
|
| -
|
| - // The validity message has potentially changed - notify the error bubble.
|
| - [validationDelegate_ updateMessageForField:textfield];
|
| - }
|
| -
|
| - // Update the icon if necessary.
|
| - if (delegate_->FieldControlsIcons(type))
|
| - [self updateFieldIcons];
|
| -}
|
| -
|
| -- (autofill::ServerFieldType)fieldTypeForControl:(NSControl*)control {
|
| - DCHECK([control tag]);
|
| - return static_cast<autofill::ServerFieldType>([control tag]);
|
| -}
|
| -
|
| -- (const autofill::DetailInput*)detailInputForType:
|
| - (autofill::ServerFieldType)type {
|
| - for (size_t i = 0; i < detailInputs_.size(); ++i) {
|
| - if (detailInputs_[i]->type == type)
|
| - return detailInputs_[i];
|
| - }
|
| - // TODO(groby): Needs to be NOTREACHED. Can't, due to the fact that tests
|
| - // blindly call setFieldValue:forType:, even for non-existing inputs.
|
| - return NULL;
|
| -}
|
| -
|
| -- (void)fillDetailOutputs:(autofill::FieldValueMap*)outputs
|
| - fromControls:(NSArray*)controls {
|
| - for (NSControl<AutofillInputField>* input in controls) {
|
| - DCHECK([input isKindOfClass:[NSControl class]]);
|
| - DCHECK([input conformsToProtocol:@protocol(AutofillInputField)]);
|
| - outputs->insert(std::make_pair(
|
| - [self fieldTypeForControl:input],
|
| - base::SysNSStringToUTF16([input fieldValue])));
|
| - }
|
| -}
|
| -
|
| -- (NSTextField*)makeDetailSectionLabel:(NSString*)labelText {
|
| - base::scoped_nsobject<NSTextField> label([[NSTextField alloc] init]);
|
| - [label setFont:
|
| - [[NSFontManager sharedFontManager] convertFont:[label font]
|
| - toHaveTrait:NSBoldFontMask]];
|
| - [label setStringValue:labelText];
|
| - [label setEditable:NO];
|
| - [label setBordered:NO];
|
| - [label setDrawsBackground:NO];
|
| - [label sizeToFit];
|
| - return label.autorelease();
|
| -}
|
| -
|
| -- (void)updateAndClobber:(BOOL)shouldClobber {
|
| - if (shouldClobber) {
|
| - // Remember which one of the inputs was first responder so focus can be
|
| - // restored after the inputs are rebuilt.
|
| - NSView* firstResponderView =
|
| - base::mac::ObjCCast<NSView>([[inputs_ window] firstResponder]);
|
| - autofill::ServerFieldType type = autofill::UNKNOWN_TYPE;
|
| - for (NSControl* field in [inputs_ subviews]) {
|
| - if ([firstResponderView isDescendantOf:field]) {
|
| - type = [self fieldTypeForControl:field];
|
| - break;
|
| - }
|
| - }
|
| -
|
| - [self makeInputControls];
|
| -
|
| - if (type != autofill::UNKNOWN_TYPE) {
|
| - NSView* view = [inputs_ viewWithTag:type];
|
| - if (view)
|
| - [[inputs_ window] makeFirstResponder:view];
|
| - }
|
| - } else {
|
| - const autofill::DetailInputs& updatedInputs =
|
| - delegate_->RequestedFieldsForSection(section_);
|
| -
|
| - for (autofill::DetailInputs::const_iterator iter = updatedInputs.begin();
|
| - iter != updatedInputs.end();
|
| - ++iter) {
|
| - NSControl<AutofillInputField>* field = [inputs_ viewWithTag:iter->type];
|
| - DCHECK(field);
|
| - if ([field isDefault])
|
| - [field setFieldValue:base::SysUTF16ToNSString(iter->initial_value)];
|
| - }
|
| - [self updateFieldIcons];
|
| - }
|
| -
|
| - [self modelChanged];
|
| -}
|
| -
|
| -- (BOOL)isCreditCardSection {
|
| - return section_ == autofill::SECTION_CC;
|
| -}
|
| -
|
| -- (MenuButton*)makeSuggestionButton {
|
| - base::scoped_nsobject<MenuButton> button([[MenuButton alloc] init]);
|
| -
|
| - [button setOpenMenuOnClick:YES];
|
| - [button setBordered:NO];
|
| - [button setShowsBorderOnlyWhileMouseInside:YES];
|
| -
|
| - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
|
| - NSImage* image =
|
| - rb.GetNativeImageNamed(IDR_AUTOFILL_DIALOG_MENU_BUTTON).ToNSImage();
|
| - [[button cell] setImage:image
|
| - forButtonState:image_button_cell::kDefaultState];
|
| - image = rb.GetNativeImageNamed(IDR_AUTOFILL_DIALOG_MENU_BUTTON_H).
|
| - ToNSImage();
|
| - [[button cell] setImage:image
|
| - forButtonState:image_button_cell::kHoverState];
|
| - image = rb.GetNativeImageNamed(IDR_AUTOFILL_DIALOG_MENU_BUTTON_P).
|
| - ToNSImage();
|
| - [[button cell] setImage:image
|
| - forButtonState:image_button_cell::kPressedState];
|
| - image = rb.GetNativeImageNamed(IDR_AUTOFILL_DIALOG_MENU_BUTTON_D).
|
| - ToNSImage();
|
| - [[button cell] setImage:image
|
| - forButtonState:image_button_cell::kDisabledState];
|
| -
|
| - // ImageButtonCell's cellSize is not working. (http://crbug.com/298501)
|
| - [button setFrameSize:[image size]];
|
| - return button.autorelease();
|
| -}
|
| -
|
| -// TODO(estade): we should be using Chrome-style constrained window padding
|
| -// values.
|
| -- (void)makeInputControls {
|
| - if (inputs_) {
|
| - // When |inputs_| is replaced in response to a country change, there's a
|
| - // didEndEditing dispatched that segfaults or DCHECKS() as it's operating on
|
| - // stale input fields. Nil out the input delegate so this doesn't happen.
|
| - for (NSControl<AutofillInputField>* input in [inputs_ subviews]) {
|
| - [input setInputDelegate:nil];
|
| - }
|
| - }
|
| -
|
| - detailInputs_.clear();
|
| -
|
| - // Keep a list of weak pointers to DetailInputs.
|
| - const autofill::DetailInputs& inputs =
|
| - delegate_->RequestedFieldsForSection(section_);
|
| -
|
| - // Reverse the order of all the inputs.
|
| - for (int i = inputs.size() - 1; i >= 0; --i) {
|
| - detailInputs_.push_back(&(inputs[i]));
|
| - }
|
| -
|
| - // Then right the reversal in each row.
|
| - std::vector<const autofill::DetailInput*>::iterator it;
|
| - for (it = detailInputs_.begin(); it < detailInputs_.end(); ++it) {
|
| - std::vector<const autofill::DetailInput*>::iterator start = it;
|
| - while (it != detailInputs_.end() &&
|
| - (*it)->length != autofill::DetailInput::LONG) {
|
| - ++it;
|
| - }
|
| - std::reverse(start, it);
|
| - }
|
| -
|
| - base::scoped_nsobject<LayoutView> view([[LayoutView alloc] init]);
|
| - [view setLayoutManager:std::unique_ptr<SimpleGridLayout>(
|
| - new SimpleGridLayout(view))];
|
| - SimpleGridLayout* layout = [view layoutManager];
|
| -
|
| - int column_set_id = 0;
|
| - for (size_t i = 0; i < detailInputs_.size(); ++i) {
|
| - const autofill::DetailInput& input = *detailInputs_[i];
|
| -
|
| - if (input.length == autofill::DetailInput::LONG)
|
| - ++column_set_id;
|
| -
|
| - int kColumnSetId =
|
| - input.length == autofill::DetailInput::NONE ? -1 : column_set_id;
|
| -
|
| - ColumnSet* columnSet = layout->GetColumnSet(kColumnSetId);
|
| - if (!columnSet) {
|
| - // Create a new column set and row.
|
| - columnSet = layout->AddColumnSet(kColumnSetId);
|
| - if (i != 0 && kColumnSetId != -1)
|
| - layout->AddPaddingRow(kRelatedControlVerticalSpacing);
|
| - layout->StartRow(0, kColumnSetId);
|
| - } else {
|
| - // Add a new column to existing row.
|
| - columnSet->AddPaddingColumn(kRelatedControlHorizontalSpacing);
|
| - // Must explicitly skip the padding column since we've already started
|
| - // adding views.
|
| - layout->SkipColumns(1);
|
| - }
|
| -
|
| - columnSet->AddColumn(input.expand_weight ? input.expand_weight : 1.0f);
|
| -
|
| - ui::ComboboxModel* inputModel =
|
| - delegate_->ComboboxModelForAutofillType(input.type);
|
| - base::scoped_nsprotocol<NSControl<AutofillInputField>*> control;
|
| - if (inputModel) {
|
| - base::scoped_nsobject<AutofillPopUpButton> popup(
|
| - [[AutofillPopUpButton alloc] initWithFrame:NSZeroRect pullsDown:NO]);
|
| - for (int i = 0; i < inputModel->GetItemCount(); ++i) {
|
| - if (!inputModel->IsItemSeparatorAt(i)) {
|
| - // Currently, the first item in |inputModel| is duplicated later in
|
| - // the list. The second item is a separator. Because NSPopUpButton
|
| - // de-duplicates, the menu's just left with a separator on the top of
|
| - // the list (with nothing it's separating). For that reason,
|
| - // separators are ignored on Mac for now. http://crbug.com/347653
|
| - [popup addItemWithTitle:
|
| - base::SysUTF16ToNSString(inputModel->GetItemAt(i))];
|
| - }
|
| - }
|
| - [popup setDefaultValue:base::SysUTF16ToNSString(
|
| - inputModel->GetItemAt(inputModel->GetDefaultIndex()))];
|
| - control.reset(popup.release());
|
| - } else {
|
| - base::scoped_nsobject<AutofillTextField> field(
|
| - [[AutofillTextField alloc] init]);
|
| - [field setIsMultiline:input.IsMultiline()];
|
| - [[field cell] setLineBreakMode:NSLineBreakByClipping];
|
| - [[field cell] setScrollable:YES];
|
| - [[field cell] setPlaceholderString:
|
| - l10n_util::FixUpWindowsStyleLabel(input.placeholder_text)];
|
| - NSString* tooltipText =
|
| - base::SysUTF16ToNSString(delegate_->TooltipForField(input.type));
|
| - // VoiceOver onlys seems to pick up the help message on [field cell]
|
| - // (rather than just field).
|
| - BOOL success = [[field cell]
|
| - accessibilitySetOverrideValue:tooltipText
|
| - forAttribute:NSAccessibilityHelpAttribute];
|
| - DCHECK(success);
|
| - if ([tooltipText length] > 0) {
|
| - if (!tooltipController_) {
|
| - tooltipController_.reset(
|
| - [[AutofillTooltipController alloc]
|
| - initWithArrowLocation:info_bubble::kTopRight]);
|
| - }
|
| - tooltipField_ = field.get();
|
| - NSImage* icon =
|
| - ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
|
| - IDR_AUTOFILL_TOOLTIP_ICON).ToNSImage();
|
| - [tooltipController_ setImage:icon];
|
| - [tooltipController_ setMessage:tooltipText];
|
| - [[field cell] setDecorationSize:[icon size]];
|
| - }
|
| - [field setDefaultValue:@""];
|
| - control.reset(field.release());
|
| - }
|
| - [control setTag:input.type];
|
| - [control setFieldValue:base::SysUTF16ToNSString(input.initial_value)];
|
| - [control sizeToFit];
|
| - [control setFrame:NSIntegralRect([control frame])];
|
| - [control setInputDelegate:self];
|
| - // Hide away fields that cannot be edited.
|
| - if (kColumnSetId == -1) {
|
| - [control setFrame:NSZeroRect];
|
| - [control setHidden:YES];
|
| - }
|
| - layout->AddView(control);
|
| -
|
| - if (input.length == autofill::DetailInput::LONG ||
|
| - input.length == autofill::DetailInput::SHORT_EOL) {
|
| - ++column_set_id;
|
| - }
|
| - }
|
| -
|
| - if (inputs_) {
|
| - [[self view] replaceSubview:inputs_ with:view];
|
| - [self requestRelayout];
|
| - }
|
| -
|
| - inputs_ = view;
|
| - [self updateFieldIcons];
|
| -}
|
| -
|
| -- (void)updateFieldIcons {
|
| - autofill::FieldValueMap fieldValues;
|
| - for (NSControl<AutofillInputField>* input in [inputs_ subviews]) {
|
| - DCHECK([input isKindOfClass:[NSControl class]]);
|
| - DCHECK([input conformsToProtocol:@protocol(AutofillInputField)]);
|
| - autofill::ServerFieldType fieldType = [self fieldTypeForControl:input];
|
| - NSString* value = [input fieldValue];
|
| - fieldValues[fieldType] = base::SysNSStringToUTF16(value);
|
| - }
|
| -
|
| - autofill::FieldIconMap fieldIcons = delegate_->IconsForFields(fieldValues);
|
| - for (autofill::FieldIconMap::const_iterator iter = fieldIcons.begin();
|
| - iter!= fieldIcons.end(); ++iter) {
|
| - AutofillTextField* textfield = base::mac::ObjCCastStrict<AutofillTextField>(
|
| - [inputs_ viewWithTag:iter->first]);
|
| - [[textfield cell] setIcon:iter->second.ToNSImage()];
|
| - }
|
| -}
|
| -
|
| -@end
|
| -
|
| -
|
| -@implementation AutofillSectionContainer (ForTesting)
|
| -
|
| -- (NSControl*)getField:(autofill::ServerFieldType)type {
|
| - return [inputs_ viewWithTag:type];
|
| -}
|
| -
|
| -- (void)setFieldValue:(NSString*)text
|
| - forType:(autofill::ServerFieldType)type {
|
| - NSControl<AutofillInputField>* field = [inputs_ viewWithTag:type];
|
| - if (field)
|
| - [field setFieldValue:text];
|
| -}
|
| -
|
| -- (void)setSuggestionFieldValue:(NSString*)text {
|
| - [[suggestContainer_ inputField] setFieldValue:text];
|
| -}
|
| -
|
| -- (void)activateFieldForType:(autofill::ServerFieldType)type {
|
| - NSControl<AutofillInputField>* field = [inputs_ viewWithTag:type];
|
| - if (field) {
|
| - [[field window] makeFirstResponder:field];
|
| - [self fieldEditedOrActivated:field edited:NO];
|
| - }
|
| -}
|
| -
|
| -@end
|
|
|