OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 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 #import "chrome/browser/ui/cocoa/autofill/autofill_section_container.h" | 5 #import "chrome/browser/ui/cocoa/autofill/autofill_section_container.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/mac/foundation_util.h" | 9 #include "base/mac/foundation_util.h" |
10 #include "base/strings/sys_string_conversions.h" | 10 #include "base/strings/sys_string_conversions.h" |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
97 // Return YES if this is a section that contains CC info. (And, more | 97 // Return YES if this is a section that contains CC info. (And, more |
98 // importantly, a potential CVV field) | 98 // importantly, a potential CVV field) |
99 - (BOOL)isCreditCardSection; | 99 - (BOOL)isCreditCardSection; |
100 | 100 |
101 // Create properly styled label for section. Autoreleased. | 101 // Create properly styled label for section. Autoreleased. |
102 - (NSTextField*)makeDetailSectionLabel:(NSString*)labelText; | 102 - (NSTextField*)makeDetailSectionLabel:(NSString*)labelText; |
103 | 103 |
104 // Create a button offering input suggestions. | 104 // Create a button offering input suggestions. |
105 - (MenuButton*)makeSuggestionButton; | 105 - (MenuButton*)makeSuggestionButton; |
106 | 106 |
107 // Create a view with all inputs requested by |delegate_|. Autoreleased. | 107 // Create a view with all inputs requested by |delegate_| and resets |input_|. |
108 - (LayoutView*)makeInputControls; | 108 - (void)makeInputControls; |
109 | 109 |
110 // Refresh all field icons based on |delegate_| status. | 110 // Refresh all field icons based on |delegate_| status. |
111 - (void)updateFieldIcons; | 111 - (void)updateFieldIcons; |
112 | 112 |
113 // Refresh the enabled/disabled state of all input fields. | 113 // Refresh the enabled/disabled state of all input fields. |
114 - (void)updateEditability; | 114 - (void)updateEditability; |
115 | 115 |
116 @end | 116 @end |
117 | 117 |
118 @implementation AutofillSectionContainer | 118 @implementation AutofillSectionContainer |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
152 if (![[self view] isHidden]) | 152 if (![[self view] isHidden]) |
153 [self validateFor:autofill::VALIDATE_EDIT]; | 153 [self validateFor:autofill::VALIDATE_EDIT]; |
154 | 154 |
155 // Always request re-layout on state change. | 155 // Always request re-layout on state change. |
156 id delegate = [[view_ window] windowController]; | 156 id delegate = [[view_ window] windowController]; |
157 if ([delegate respondsToSelector:@selector(requestRelayout)]) | 157 if ([delegate respondsToSelector:@selector(requestRelayout)]) |
158 [delegate performSelector:@selector(requestRelayout)]; | 158 [delegate performSelector:@selector(requestRelayout)]; |
159 } | 159 } |
160 | 160 |
161 - (void)loadView { | 161 - (void)loadView { |
162 // Keep a list of weak pointers to DetailInputs. | 162 [self makeInputControls]; |
163 const autofill::DetailInputs& inputs = | |
164 delegate_->RequestedFieldsForSection(section_); | |
165 | 163 |
166 // Reverse the order of all the inputs. | |
167 for (int i = inputs.size() - 1; i >= 0; --i) { | |
168 detailInputs_.push_back(&(inputs[i])); | |
169 } | |
170 | |
171 // Then right the reversal in each row. | |
172 std::vector<const autofill::DetailInput*>::iterator it; | |
173 for (it = detailInputs_.begin(); it < detailInputs_.end(); ++it) { | |
174 std::vector<const autofill::DetailInput*>::iterator start = it; | |
175 while (it != detailInputs_.end() && | |
176 (*it)->length != autofill::DetailInput::LONG) { | |
177 ++it; | |
178 } | |
179 std::reverse(start, it); | |
180 } | |
181 | |
182 inputs_.reset([[self makeInputControls] retain]); | |
183 base::string16 labelText = delegate_->LabelForSection(section_); | 164 base::string16 labelText = delegate_->LabelForSection(section_); |
184 label_.reset( | 165 label_.reset( |
185 [[self makeDetailSectionLabel:base::SysUTF16ToNSString(labelText)] | 166 [[self makeDetailSectionLabel:base::SysUTF16ToNSString(labelText)] |
186 retain]); | 167 retain]); |
187 | 168 |
188 suggestButton_.reset([[self makeSuggestionButton] retain]); | 169 suggestButton_.reset([[self makeSuggestionButton] retain]); |
189 suggestContainer_.reset([[AutofillSuggestionContainer alloc] init]); | 170 suggestContainer_.reset([[AutofillSuggestionContainer alloc] init]); |
190 | 171 |
191 view_.reset([[AutofillSectionView alloc] initWithFrame:NSZeroRect]); | 172 view_.reset([[AutofillSectionView alloc] initWithFrame:NSZeroRect]); |
192 [self setView:view_]; | 173 [self setView:view_]; |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
296 [validationDelegate_ updateMessageForField:field]; | 277 [validationDelegate_ updateMessageForField:field]; |
297 } | 278 } |
298 | 279 |
299 - (void)didChange:(id)sender { | 280 - (void)didChange:(id)sender { |
300 [self textfieldEditedOrActivated:sender edited:YES]; | 281 [self textfieldEditedOrActivated:sender edited:YES]; |
301 } | 282 } |
302 | 283 |
303 - (void)didEndEditing:(id)sender { | 284 - (void)didEndEditing:(id)sender { |
304 delegate_->FocusMoved(); | 285 delegate_->FocusMoved(); |
305 [validationDelegate_ hideErrorBubble]; | 286 [validationDelegate_ hideErrorBubble]; |
287 | |
288 AutofillPopUpButton* popup = base::mac::ObjCCast<AutofillPopUpButton>(sender); | |
289 if (popup) { | |
groby-ooo-7-16
2014/01/10 01:56:38
If you must get a separate popup notification, I'd
Dan Beam
2014/01/11 04:16:58
see updated code
| |
290 // Add one to account for the spacer at the top of the list. | |
291 int index = [popup indexOfSelectedItem] + 1; | |
292 delegate_->ComboboxItemSelected([self fieldTypeForControl:popup], index); | |
293 } | |
294 | |
306 [self validateFor:autofill::VALIDATE_EDIT]; | 295 [self validateFor:autofill::VALIDATE_EDIT]; |
307 [self updateEditability]; | 296 [self updateEditability]; |
308 } | 297 } |
309 | 298 |
310 - (void)updateSuggestionState { | 299 - (void)updateSuggestionState { |
311 const autofill::SuggestionState& suggestionState = | 300 const autofill::SuggestionState& suggestionState = |
312 delegate_->SuggestionStateForSection(section_); | 301 delegate_->SuggestionStateForSection(section_); |
313 showSuggestions_ = suggestionState.visible; | 302 showSuggestions_ = suggestionState.visible; |
314 | 303 |
315 if (!suggestionState.extra_text.empty()) { | 304 if (!suggestionState.extra_text.empty()) { |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
507 toHaveTrait:NSBoldFontMask]]; | 496 toHaveTrait:NSBoldFontMask]]; |
508 [label setStringValue:labelText]; | 497 [label setStringValue:labelText]; |
509 [label setEditable:NO]; | 498 [label setEditable:NO]; |
510 [label setBordered:NO]; | 499 [label setBordered:NO]; |
511 [label setDrawsBackground:NO]; | 500 [label setDrawsBackground:NO]; |
512 [label sizeToFit]; | 501 [label sizeToFit]; |
513 return label.autorelease(); | 502 return label.autorelease(); |
514 } | 503 } |
515 | 504 |
516 - (void)updateAndClobber:(BOOL)shouldClobber { | 505 - (void)updateAndClobber:(BOOL)shouldClobber { |
517 const autofill::DetailInputs& updatedInputs = | 506 if (shouldClobber) { |
groby-ooo-7-16
2014/01/10 01:56:38
I'd prefer to not rebuild the entire layout whenev
Dan Beam
2014/01/11 04:16:58
we talked about this and will wait until it's noti
| |
518 delegate_->RequestedFieldsForSection(section_); | 507 [self makeInputControls]; |
groby-ooo-7-16
2014/01/10 01:56:38
Also, you presumably want to request a relayout he
Dan Beam
2014/01/11 04:16:58
Done.
| |
508 } else { | |
509 const autofill::DetailInputs& updatedInputs = | |
510 delegate_->RequestedFieldsForSection(section_); | |
519 | 511 |
520 for (autofill::DetailInputs::const_iterator iter = updatedInputs.begin(); | 512 for (autofill::DetailInputs::const_iterator iter = updatedInputs.begin(); |
521 iter != updatedInputs.end(); | 513 iter != updatedInputs.end(); |
522 ++iter) { | 514 ++iter) { |
523 NSControl<AutofillInputField>* field = [inputs_ viewWithTag:iter->type]; | 515 NSControl<AutofillInputField>* field = [inputs_ viewWithTag:iter->type]; |
524 DCHECK(field); | 516 DCHECK(field); |
525 | 517 |
526 if (shouldClobber || [field isDefault]) { | 518 if (shouldClobber || [field isDefault]) { |
527 [field setFieldValue:base::SysUTF16ToNSString(iter->initial_value)]; | 519 [field setFieldValue:base::SysUTF16ToNSString(iter->initial_value)]; |
520 } | |
521 if (shouldClobber) | |
groby-ooo-7-16
2014/01/10 01:56:38
How could shouldClobber ever be true here? You're
Dan Beam
2014/01/11 04:16:58
copy pasta, removed
| |
522 [field setValidityMessage:@""]; | |
528 } | 523 } |
529 if (shouldClobber) | 524 [self updateFieldIcons]; |
530 [field setValidityMessage:@""]; | |
531 } | 525 } |
526 | |
532 [self updateEditability]; | 527 [self updateEditability]; |
533 [self updateFieldIcons]; | |
534 [self modelChanged]; | 528 [self modelChanged]; |
535 } | 529 } |
536 | 530 |
537 - (BOOL)isCreditCardSection { | 531 - (BOOL)isCreditCardSection { |
538 return section_ == autofill::SECTION_CC || | 532 return section_ == autofill::SECTION_CC || |
539 section_ == autofill::SECTION_CC_BILLING; | 533 section_ == autofill::SECTION_CC_BILLING; |
540 } | 534 } |
541 | 535 |
542 - (MenuButton*)makeSuggestionButton { | 536 - (MenuButton*)makeSuggestionButton { |
543 base::scoped_nsobject<MenuButton> button([[MenuButton alloc] init]); | 537 base::scoped_nsobject<MenuButton> button([[MenuButton alloc] init]); |
(...skipping 20 matching lines...) Expand all Loading... | |
564 [[button cell] setImage:image | 558 [[button cell] setImage:image |
565 forButtonState:image_button_cell::kDisabledState]; | 559 forButtonState:image_button_cell::kDisabledState]; |
566 | 560 |
567 // ImageButtonCell's cellSize is not working. (http://crbug.com/298501) | 561 // ImageButtonCell's cellSize is not working. (http://crbug.com/298501) |
568 [button setFrameSize:[image size]]; | 562 [button setFrameSize:[image size]]; |
569 return button.autorelease(); | 563 return button.autorelease(); |
570 } | 564 } |
571 | 565 |
572 // TODO(estade): we should be using Chrome-style constrained window padding | 566 // TODO(estade): we should be using Chrome-style constrained window padding |
573 // values. | 567 // values. |
574 - (LayoutView*)makeInputControls { | 568 - (void)makeInputControls { |
569 detailInputs_.clear(); | |
570 | |
571 // Keep a list of weak pointers to DetailInputs. | |
572 const autofill::DetailInputs& inputs = | |
573 delegate_->RequestedFieldsForSection(section_); | |
574 | |
575 // Reverse the order of all the inputs. | |
576 for (int i = inputs.size() - 1; i >= 0; --i) { | |
577 detailInputs_.push_back(&(inputs[i])); | |
578 } | |
579 | |
580 // Then right the reversal in each row. | |
581 std::vector<const autofill::DetailInput*>::iterator it; | |
582 for (it = detailInputs_.begin(); it < detailInputs_.end(); ++it) { | |
583 std::vector<const autofill::DetailInput*>::iterator start = it; | |
584 while (it != detailInputs_.end() && | |
585 (*it)->length != autofill::DetailInput::LONG) { | |
586 ++it; | |
587 } | |
588 std::reverse(start, it); | |
589 } | |
590 | |
575 base::scoped_nsobject<LayoutView> view([[LayoutView alloc] init]); | 591 base::scoped_nsobject<LayoutView> view([[LayoutView alloc] init]); |
576 [view setLayoutManager: | 592 [view setLayoutManager: |
577 scoped_ptr<SimpleGridLayout>(new SimpleGridLayout(view))]; | 593 scoped_ptr<SimpleGridLayout>(new SimpleGridLayout(view))]; |
578 SimpleGridLayout* layout = [view layoutManager]; | 594 SimpleGridLayout* layout = [view layoutManager]; |
579 | 595 |
580 int column_set_id = 0; | 596 int column_set_id = 0; |
581 for (size_t i = 0; i < detailInputs_.size(); ++i) { | 597 for (size_t i = 0; i < detailInputs_.size(); ++i) { |
582 const autofill::DetailInput& input = *detailInputs_[i]; | 598 const autofill::DetailInput& input = *detailInputs_[i]; |
583 | 599 |
584 if (input.length == autofill::DetailInput::LONG) | 600 if (input.length == autofill::DetailInput::LONG) |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
618 inputModel->GetItemAt(inputModel->GetDefaultIndex()))]; | 634 inputModel->GetItemAt(inputModel->GetDefaultIndex()))]; |
619 control.reset(popup.release()); | 635 control.reset(popup.release()); |
620 } else { | 636 } else { |
621 base::scoped_nsobject<AutofillTextField> field( | 637 base::scoped_nsobject<AutofillTextField> field( |
622 [[AutofillTextField alloc] init]); | 638 [[AutofillTextField alloc] init]); |
623 [[field cell] setPlaceholderString: | 639 [[field cell] setPlaceholderString: |
624 l10n_util::FixUpWindowsStyleLabel(input.placeholder_text)]; | 640 l10n_util::FixUpWindowsStyleLabel(input.placeholder_text)]; |
625 NSString* tooltipText = | 641 NSString* tooltipText = |
626 base::SysUTF16ToNSString(delegate_->TooltipForField(input.type)); | 642 base::SysUTF16ToNSString(delegate_->TooltipForField(input.type)); |
627 if ([tooltipText length] > 0) { | 643 if ([tooltipText length] > 0) { |
628 DCHECK(!tooltipController_); | 644 if (!tooltipController_) { |
629 DCHECK(!tooltipField_); | 645 tooltipController_.reset( |
630 tooltipController_.reset( | 646 [[AutofillTooltipController alloc] |
631 [[AutofillTooltipController alloc] | 647 initWithArrowLocation:info_bubble::kTopRight]); |
632 initWithArrowLocation:info_bubble::kTopRight]); | 648 } |
633 tooltipField_ = field.get(); | 649 tooltipField_ = field.get(); |
634 NSImage* icon = | 650 NSImage* icon = |
635 ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed( | 651 ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed( |
636 IDR_AUTOFILL_TOOLTIP_ICON).ToNSImage(); | 652 IDR_AUTOFILL_TOOLTIP_ICON).ToNSImage(); |
637 [tooltipController_ setImage:icon]; | 653 [tooltipController_ setImage:icon]; |
638 [tooltipController_ setMessage:tooltipText]; | 654 [tooltipController_ setMessage:tooltipText]; |
639 [[field cell] setDecorationSize:[icon size]]; | 655 [[field cell] setDecorationSize:[icon size]]; |
640 } | 656 } |
641 [field setDefaultValue:@""]; | 657 [field setDefaultValue:@""]; |
642 control.reset(field.release()); | 658 control.reset(field.release()); |
643 } | 659 } |
644 [control setFieldValue:base::SysUTF16ToNSString(input.initial_value)]; | 660 [control setFieldValue:base::SysUTF16ToNSString(input.initial_value)]; |
645 [control sizeToFit]; | 661 [control sizeToFit]; |
646 [control setTag:input.type]; | 662 [control setTag:input.type]; |
647 [control setInputDelegate:self]; | 663 [control setInputDelegate:self]; |
648 // Hide away fields that cannot be edited. | 664 // Hide away fields that cannot be edited. |
649 if (kColumnSetId == -1) { | 665 if (kColumnSetId == -1) { |
650 [control setFrame:NSZeroRect]; | 666 [control setFrame:NSZeroRect]; |
651 [control setHidden:YES]; | 667 [control setHidden:YES]; |
652 } | 668 } |
653 layout->AddView(control); | 669 layout->AddView(control); |
654 | 670 |
655 if (input.length == autofill::DetailInput::LONG || | 671 if (input.length == autofill::DetailInput::LONG || |
656 input.length == autofill::DetailInput::SHORT_EOL) { | 672 input.length == autofill::DetailInput::SHORT_EOL) { |
657 ++column_set_id; | 673 ++column_set_id; |
658 } | 674 } |
659 } | 675 } |
660 | 676 |
661 [self updateFieldIcons]; | 677 [self updateFieldIcons]; |
662 return view.autorelease(); | 678 |
679 if (inputs_) | |
680 [[self view] replaceSubview:inputs_ with:view]; | |
681 | |
682 inputs_ = view; | |
663 } | 683 } |
664 | 684 |
665 - (void)updateFieldIcons { | 685 - (void)updateFieldIcons { |
666 autofill::FieldValueMap fieldValues; | 686 autofill::FieldValueMap fieldValues; |
667 for (NSControl<AutofillInputField>* input in [inputs_ subviews]) { | 687 for (NSControl<AutofillInputField>* input in [inputs_ subviews]) { |
668 DCHECK([input isKindOfClass:[NSControl class]]); | 688 DCHECK([input isKindOfClass:[NSControl class]]); |
669 DCHECK([input conformsToProtocol:@protocol(AutofillInputField)]); | 689 DCHECK([input conformsToProtocol:@protocol(AutofillInputField)]); |
670 autofill::ServerFieldType fieldType = [self fieldTypeForControl:input]; | 690 autofill::ServerFieldType fieldType = [self fieldTypeForControl:input]; |
671 NSString* value = [input fieldValue]; | 691 NSString* value = [input fieldValue]; |
672 fieldValues[fieldType] = base::SysNSStringToUTF16(value); | 692 fieldValues[fieldType] = base::SysNSStringToUTF16(value); |
673 } | 693 } |
674 | 694 |
675 autofill::FieldIconMap fieldIcons = delegate_->IconsForFields(fieldValues); | 695 autofill::FieldIconMap fieldIcons = delegate_->IconsForFields(fieldValues); |
676 for (autofill::FieldIconMap::const_iterator iter = fieldIcons.begin(); | 696 for (autofill::FieldIconMap::const_iterator iter = fieldIcons.begin(); |
677 iter!= fieldIcons.end(); ++iter) { | 697 iter!= fieldIcons.end(); ++iter) { |
678 AutofillTextField* textfield = base::mac::ObjCCastStrict<AutofillTextField>( | 698 AutofillTextField* textfield = base::mac::ObjCCastStrict<AutofillTextField>( |
679 [inputs_ viewWithTag:iter->first]); | 699 [inputs_ viewWithTag:iter->first]); |
680 [[textfield cell] setIcon:iter->second.ToNSImage()]; | 700 [[textfield cell] setIcon:iter->second.ToNSImage()]; |
681 } | 701 } |
682 } | 702 } |
683 | 703 |
684 - (void)updateEditability { | 704 - (void)updateEditability { |
685 | |
686 base::scoped_nsobject<NSMutableArray> controls([[NSMutableArray alloc] init]); | 705 base::scoped_nsobject<NSMutableArray> controls([[NSMutableArray alloc] init]); |
687 [self addInputsToArray:controls]; | 706 [self addInputsToArray:controls]; |
688 for (NSControl<AutofillInputField>* control in controls.get()) { | 707 for (NSControl<AutofillInputField>* control in controls.get()) { |
689 autofill::ServerFieldType type = [self fieldTypeForControl:control]; | 708 autofill::ServerFieldType type = [self fieldTypeForControl:control]; |
690 const autofill::DetailInput* input = [self detailInputForType:type]; | 709 const autofill::DetailInput* input = [self detailInputForType:type]; |
691 [control setEnabled:delegate_->InputIsEditable(*input, section_)]; | 710 [control setEnabled:delegate_->InputIsEditable(*input, section_)]; |
692 } | 711 } |
693 } | 712 } |
694 | 713 |
695 @end | 714 @end |
696 | 715 |
697 | 716 |
698 @implementation AutofillSectionContainer (ForTesting) | 717 @implementation AutofillSectionContainer (ForTesting) |
699 | 718 |
700 - (NSControl*)getField:(autofill::ServerFieldType)type { | 719 - (NSControl*)getField:(autofill::ServerFieldType)type { |
701 return [inputs_ viewWithTag:type]; | 720 return [inputs_ viewWithTag:type]; |
702 } | 721 } |
703 | 722 |
704 - (void)setFieldValue:(NSString*)text | 723 - (void)setFieldValue:(NSString*)text |
705 forType:(autofill::ServerFieldType)type { | 724 forType:(autofill::ServerFieldType)type { |
706 NSControl<AutofillInputField>* field = [inputs_ viewWithTag:type]; | 725 NSControl<AutofillInputField>* field = [inputs_ viewWithTag:type]; |
707 if (field) | 726 if (field) { |
727 AutofillPopUpButton* popup = | |
groby-ooo-7-16
2014/01/10 01:56:38
Please do that in AutofillPopUp, not here.
Dan Beam
2014/01/11 04:16:58
Done.
| |
728 base::mac::ObjCCast<AutofillPopUpButton>(field); | |
729 int index = popup ? [popup indexOfSelectedItem] : -1; | |
708 [field setFieldValue:text]; | 730 [field setFieldValue:text]; |
731 if (popup && [popup indexOfSelectedItem] != index) | |
732 [self didEndEditing:field]; | |
733 } | |
709 } | 734 } |
710 | 735 |
711 - (void)setSuggestionFieldValue:(NSString*)text { | 736 - (void)setSuggestionFieldValue:(NSString*)text { |
712 [[suggestContainer_ inputField] setFieldValue:text]; | 737 [[suggestContainer_ inputField] setFieldValue:text]; |
713 } | 738 } |
714 | 739 |
715 - (void)activateFieldForType:(autofill::ServerFieldType)type { | 740 - (void)activateFieldForType:(autofill::ServerFieldType)type { |
716 NSControl<AutofillInputField>* field = [inputs_ viewWithTag:type]; | 741 NSControl<AutofillInputField>* field = [inputs_ viewWithTag:type]; |
717 if (field) { | 742 if (field) { |
718 [[field window] makeFirstResponder:field]; | 743 [[field window] makeFirstResponder:field]; |
719 [self textfieldEditedOrActivated:field edited:NO]; | 744 [self textfieldEditedOrActivated:field edited:NO]; |
720 } | 745 } |
721 } | 746 } |
722 | 747 |
723 @end | 748 @end |
OLD | NEW |