summaryrefslogtreecommitdiffstats
path: root/chrome/browser/autofill/autofill_dialog_controller_mac.mm
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/autofill/autofill_dialog_controller_mac.mm')
-rw-r--r--chrome/browser/autofill/autofill_dialog_controller_mac.mm711
1 files changed, 493 insertions, 218 deletions
diff --git a/chrome/browser/autofill/autofill_dialog_controller_mac.mm b/chrome/browser/autofill/autofill_dialog_controller_mac.mm
index c867497..c39e3e8 100644
--- a/chrome/browser/autofill/autofill_dialog_controller_mac.mm
+++ b/chrome/browser/autofill/autofill_dialog_controller_mac.mm
@@ -4,29 +4,100 @@
#import "chrome/browser/autofill/autofill_dialog_controller_mac.h"
#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
#include "base/mac_util.h"
#include "base/sys_string_conversions.h"
#import "chrome/browser/autofill/autofill_address_model_mac.h"
-#import "chrome/browser/autofill/autofill_address_view_controller_mac.h"
+#import "chrome/browser/autofill/autofill_address_sheet_controller_mac.h"
#import "chrome/browser/autofill/autofill_credit_card_model_mac.h"
-#import "chrome/browser/autofill/autofill_credit_card_view_controller_mac.h"
+#import "chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.h"
#import "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/browser_process.h"
-#import "chrome/browser/cocoa/disclosure_view_controller.h"
-#import "chrome/browser/cocoa/section_separator_view.h"
#import "chrome/browser/cocoa/window_size_autosaver.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_names.h"
#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+
+// Delegate protocol that needs to be in place for the AutoFillTableView's
+// handling of delete and backspace keys.
+@protocol DeleteKeyDelegate
+- (IBAction)deleteSelection:(id)sender;
+@end
+
+// A subclass of NSTableView that allows for deleting selected elements using
+// the delete or backspace keys.
+@interface AutoFillTableView : NSTableView {
+}
+@end
+
+@implementation AutoFillTableView
+
+// We override the keyDown method to dispatch the |deleteSelection:| action
+// when the user presses the delete or backspace keys. Note a delegate must
+// be present that conforms to the DeleteKeyDelegate protocol.
+- (void)keyDown:(NSEvent *)event {
+ id object = [self delegate];
+ unichar c = [[event characters] characterAtIndex: 0];
+
+ // If the user pressed delete and the delegate supports deleteSelection:
+ if ((c == NSDeleteFunctionKey ||
+ c == NSDeleteCharFunctionKey ||
+ c == NSDeleteCharacter) &&
+ [object respondsToSelector:@selector(deleteSelection:)]) {
+ id <DeleteKeyDelegate> delegate = (id <DeleteKeyDelegate>) object;
+
+ [delegate deleteSelection:self];
+ } else {
+ [super keyDown:event];
+ }
+}
+
+@end
// Private interface.
-@interface AutoFillDialogController (PrivateAPI)
+@interface AutoFillDialogController (PrivateMethods)
// Asyncronous handler for when PersonalDataManager data loads. The
// personal data manager notifies the dialog with this method when the
// data loading is complete and ready to be used.
- (void)onPersonalDataLoaded:(const std::vector<AutoFillProfile*>&)profiles
creditCards:(const std::vector<CreditCard*>&)creditCards;
+
+// Returns true if |row| is an index to a valid profile in |tableView_|, and
+// false otherwise.
+- (BOOL)isProfileRow:(NSInteger)row;
+
+// Returns true if |row| is an index to the profile group row in |tableView_|,
+// and false otherwise.
+- (BOOL)isProfileGroupRow:(NSInteger)row;
+
+// Returns true if |row| is an index to a valid credit card in |tableView_|, and
+// false otherwise.
+- (BOOL)isCreditCardRow:(NSInteger)row;
+
+// Returns true if |row| is the index to the credit card group row in
+// |tableView_|, and false otherwise.
+- (BOOL)isCreditCardGroupRow:(NSInteger)row;
+
+// Returns the index to |profiles_| of the corresponding |row| in |tableView_|.
+- (size_t)profileIndexFromRow:(NSInteger)row;
+
+// Returns the index to |creditCards_| of the corresponding |row| in
+// |tableView_|.
+- (size_t)creditCardIndexFromRow:(NSInteger)row;
+
+// Returns the |row| in |tableView_| that corresponds to the index |i| into
+// |profiles_|.
+- (NSInteger)rowFromProfileIndex:(size_t)i;
+
+// Returns the |row| in |tableView_| that corresponds to the index |i| into
+// |creditCards_|.
+- (NSInteger)rowFromCreditCardIndex:(size_t)row;
+
+// Invokes the modal dialog.
+- (void)runModalDialog;
+
@end
namespace AutoFillDialogControllerInternal {
@@ -94,14 +165,10 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
} // namespace AutoFillDialogControllerInternal
-@interface AutoFillDialogController (PrivateMethods)
-- (void)runModalDialog;
-- (void)installChildViews;
-@end
-
@implementation AutoFillDialogController
@synthesize auxiliaryEnabled = auxiliaryEnabled_;
+@synthesize itemIsSelected = itemIsSelected_;
+ (void)showAutoFillDialogWithObserver:(AutoFillDialogObserver*)observer
profile:(Profile*)profile
@@ -120,8 +187,6 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
}
- (void)awakeFromNib {
- [addressSectionBox_ setShowTopLine:FALSE];
-
PersonalDataManager* personal_data_manager =
profile_->GetPersonalDataManager();
DCHECK(personal_data_manager);
@@ -138,46 +203,27 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
self, personal_data_manager, profile_));
personal_data_manager->SetObserver(personalDataManagerObserver_.get());
}
+
+ // Explicitly load the data in the table before window displays to avoid
+ // nasty flicker as tables update.
+ [tableView_ reloadData];
+
+ // Set up edit when double-clicking on a table row.
+ [tableView_ setDoubleAction:@selector(editSelection:)];
}
// NSWindow Delegate callback. When the window closes the controller can
// be released.
- (void)windowWillClose:(NSNotification *)notification {
- // Force views to go away so they properly remove their observations.
- addressFormViewControllers_.reset();
- creditCardFormViewControllers_.reset();
+ [tableView_ setDataSource:nil];
+ [tableView_ setDelegate:nil];
[self autorelease];
}
// Called when the user clicks the save button.
- (IBAction)save:(id)sender {
- // Call |makeFirstResponder:| to commit pending text field edits.
- [[self window] makeFirstResponder:[self window]];
-
// If we have an |observer_| then communicate the changes back.
if (observer_) {
- profiles_.clear();
- profiles_.resize([addressFormViewControllers_ count]);
- int i = 0;
- for (AutoFillAddressViewController* addressFormViewController in
- addressFormViewControllers_.get()) {
- // Initialize the profile here. The default initializer does not fully
- // initialize.
- profiles_[i] = AutoFillProfile(ASCIIToUTF16(""), 0);
- [addressFormViewController copyModelToProfile:&profiles_[i]];
- i++;
- }
- creditCards_.clear();
- creditCards_.resize([creditCardFormViewControllers_ count]);
- int j = 0;
- for (AutoFillCreditCardViewController* creditCardFormViewController in
- creditCardFormViewControllers_.get()) {
- // Initialize the credit card here. The default initializer does not
- // fully initialize.
- creditCards_[j] = CreditCard(ASCIIToUTF16(""), 0);
- [creditCardFormViewController copyModelToCreditCard:&creditCards_[j]];
- j++;
- }
profile_->GetPrefs()->SetBoolean(prefs::kAutoFillAuxiliaryProfilesEnabled,
auxiliaryEnabled_);
observer_->OnAutoFillDialogApply(&profiles_, &creditCards_);
@@ -191,144 +237,306 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
[self closeDialog];
}
-// Adds new address to bottom of list. A new address controller is created
-// and its view is inserted into the view hierarchy.
+// Invokes the "Add" sheet for address information. If user saves then the new
+// information is added to |profiles_| in |addressAddDidEnd:| method.
- (IBAction)addNewAddress:(id)sender {
- // Insert relative to top of section, or below last address.
- NSView* insertionPoint;
- NSUInteger count = [addressFormViewControllers_.get() count];
- if (count == 0) {
- insertionPoint = addressSection_;
- } else {
- insertionPoint = [[addressFormViewControllers_.get()
- objectAtIndex:[addressFormViewControllers_.get() count] - 1] view];
+ DCHECK(!addressSheetController.get());
+
+ // Create a new default address.
+ string16 newName = l10n_util::GetStringUTF16(IDS_AUTOFILL_NEW_ADDRESS);
+ AutoFillProfile newAddress(newName, 0);
+
+ // Create a new address sheet controller in "Add" mode.
+ addressSheetController.reset(
+ [[AutoFillAddressSheetController alloc]
+ initWithProfile:newAddress
+ mode:kAutoFillAddressAddMode]);
+
+ // Show the sheet.
+ [NSApp beginSheet:[addressSheetController window]
+ modalForWindow:[self window]
+ modalDelegate:self
+ didEndSelector:@selector(addressAddDidEnd:returnCode:contextInfo:)
+ contextInfo:NULL];
+}
+
+// Invokes the "Add" sheet for credit card information. If user saves then the
+// new information is added to |creditCards_| in |creditCardAddDidEnd:| method.
+- (IBAction)addNewCreditCard:(id)sender {
+ DCHECK(!creditCardSheetController.get());
+
+ // Create a new default credit card.
+ string16 newName = l10n_util::GetStringUTF16(IDS_AUTOFILL_NEW_CREDITCARD);
+ CreditCard newCreditCard(newName, 0);
+
+ // Create a new address sheet controller in "Add" mode.
+ creditCardSheetController.reset(
+ [[AutoFillCreditCardSheetController alloc]
+ initWithCreditCard:newCreditCard
+ mode:kAutoFillCreditCardAddMode
+ controller:self]);
+
+ // Show the sheet.
+ [NSApp beginSheet:[creditCardSheetController window]
+ modalForWindow:[self window]
+ modalDelegate:self
+ didEndSelector:@selector(creditCardAddDidEnd:returnCode:contextInfo:)
+ contextInfo:NULL];
+}
+
+// Add address sheet was dismissed. Non-zero |returnCode| indicates a save.
+- (void)addressAddDidEnd:(NSWindow*)sheet
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo {
+ DCHECK(contextInfo == NULL);
+
+ if (returnCode) {
+ // Create a new address and save it to the |profiles_| list.
+ AutoFillProfile newAddress(string16(), 0);
+ [addressSheetController copyModelToProfile:&newAddress];
+ profiles_.push_back(newAddress);
+
+ // Refresh the view based on new data.
+ [tableView_ reloadData];
+
+ // Update the selection to the newly added item.
+ NSInteger row = [self rowFromProfileIndex:profiles_.size() - 1];
+ [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:row]
+ byExtendingSelection:NO];
}
+ [sheet orderOut:self];
+ addressSheetController.reset(nil);
+}
- // Create a new default address, and add it to our array of controllers.
- string16 new_address_name = l10n_util::GetStringUTF16(
- IDS_AUTOFILL_NEW_ADDRESS);
- AutoFillProfile newProfile(new_address_name, 0);
- scoped_nsobject<AutoFillAddressViewController> addressViewController(
- [[AutoFillAddressViewController alloc]
- initWithProfile:newProfile
- disclosure:NSOnState
- controller:self]);
- [self willChangeValueForKey:@"addressLabels"];
- [addressFormViewControllers_.get() addObject:addressViewController];
- [self didChangeValueForKey:@"addressLabels"];
+// Add credit card sheet was dismissed. Non-zero |returnCode| indicates a save.
+- (void)creditCardAddDidEnd:(NSWindow *)sheet
+ returnCode:(int)returnCode
+ contextInfo:(void *)contextInfo {
+ DCHECK(contextInfo == NULL);
+
+ if (returnCode) {
+ // Create a new credit card and save it to the |creditCards_| list.
+ CreditCard newCreditCard(string16(), 0);
+ [creditCardSheetController copyModelToCreditCard:&newCreditCard];
+ creditCards_.push_back(newCreditCard);
+
+ // Refresh the view based on new data.
+ [tableView_ reloadData];
+
+ // Update the selection to the newly added item.
+ NSInteger row = [self rowFromCreditCardIndex:creditCards_.size() - 1];
+ [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:row]
+ byExtendingSelection:NO];
+ }
+ [sheet orderOut:self];
+ creditCardSheetController.reset(nil);
+}
- // Embed the new address into our target view.
- [childView_ addSubview:[addressViewController view]
- positioned:NSWindowBelow relativeTo:insertionPoint];
- [[addressViewController view] setFrameOrigin:NSMakePoint(0, 0)];
+// Deletes selected item, either address or credit card depending on the item
+// selected.
+- (IBAction)deleteSelection:(id)sender {
+ NSInteger selectedRow = [tableView_ selectedRow];
+ if ([self isProfileRow:selectedRow]) {
+ profiles_.erase(profiles_.begin() + [self profileIndexFromRow:selectedRow]);
+
+ // Select the previous row if possible, else current row, else deselect all.
+ if ([self tableView:tableView_ shouldSelectRow:selectedRow-1]) {
+ [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow-1]
+ byExtendingSelection:NO];
+ } else if ([self tableView:tableView_ shouldSelectRow:selectedRow]) {
+ [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow]
+ byExtendingSelection:NO];
+ } else {
+ [tableView_ selectRowIndexes:[NSIndexSet indexSet]
+ byExtendingSelection:NO];
+ }
+ [tableView_ reloadData];
+ } else if ([self isCreditCardRow:selectedRow]) {
+ creditCards_.erase(
+ creditCards_.begin() + [self creditCardIndexFromRow:selectedRow]);
+
+ // Select the previous row if possible, else current row, else deselect all.
+ if ([self tableView:tableView_ shouldSelectRow:selectedRow-1]) {
+ [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow-1]
+ byExtendingSelection:NO];
+ } else if ([self tableView:tableView_ shouldSelectRow:selectedRow]) {
+ [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow]
+ byExtendingSelection:NO];
+ } else {
+ [tableView_ selectRowIndexes:[NSIndexSet indexSet]
+ byExtendingSelection:NO];
+ }
+ [tableView_ reloadData];
+ }
+}
- [self notifyAddressChange:self];
+// Edits the selected item, either address or credit card depending on the item
+// selected.
+- (IBAction)editSelection:(id)sender {
+ NSInteger selectedRow = [tableView_ selectedRow];
+ if ([self isProfileRow:selectedRow]) {
+ if (!addressSheetController.get()) {
+ int i = [self profileIndexFromRow:selectedRow];
+
+ // Create a new address sheet controller in "Edit" mode.
+ addressSheetController.reset(
+ [[AutoFillAddressSheetController alloc]
+ initWithProfile:profiles_[i]
+ mode:kAutoFillAddressEditMode]);
+
+ // Show the sheet.
+ [NSApp beginSheet:[addressSheetController window]
+ modalForWindow:[self window]
+ modalDelegate:self
+ didEndSelector:@selector(addressEditDidEnd:returnCode:contextInfo:)
+ contextInfo:&profiles_[i]];
+ }
+ } else if ([self isCreditCardRow:selectedRow]) {
+ if (!creditCardSheetController.get()) {
+ int i = [self creditCardIndexFromRow:selectedRow];
+
+ // Create a new credit card sheet controller in "Edit" mode.
+ creditCardSheetController.reset(
+ [[AutoFillCreditCardSheetController alloc]
+ initWithCreditCard:creditCards_[i]
+ mode:kAutoFillCreditCardEditMode
+ controller:self]);
+
+ // Show the sheet.
+ [NSApp beginSheet:[creditCardSheetController window]
+ modalForWindow:[self window]
+ modalDelegate:self
+ didEndSelector:@selector(creditCardEditDidEnd:returnCode:contextInfo:)
+ contextInfo:&creditCards_[i]];
+ }
+ }
+}
- // Recalculate key view loop to account for change in view tree.
- [[self window] recalculateKeyViewLoop];
+// Edit address sheet was dismissed. Non-zero |returnCode| indicates a save.
+- (void)addressEditDidEnd:(NSWindow *)sheet
+ returnCode:(int)returnCode
+ contextInfo:(void *)contextInfo {
+ DCHECK(contextInfo != NULL);
+ if (returnCode) {
+ AutoFillProfile* profile = static_cast<AutoFillProfile*>(contextInfo);
+ [addressSheetController copyModelToProfile:profile];
+ [tableView_ reloadData];
+ }
+ [sheet orderOut:self];
+ addressSheetController.reset(nil);
}
-// Adds new credit card to bottom of list. A new credit card controller is
-// created and its view is inserted into the view hierarchy.
-- (IBAction)addNewCreditCard:(id)sender {
- // Insert relative to top of section, or below last address.
- NSView* insertionPoint;
- NSUInteger count = [creditCardFormViewControllers_.get() count];
- if (count == 0) {
- insertionPoint = creditCardSection_;
- } else {
- insertionPoint = [[creditCardFormViewControllers_.get()
- objectAtIndex:[creditCardFormViewControllers_.get() count] - 1] view];
+// Edit credit card sheet was dismissed. Non-zero |returnCode| indicates a
+// save.
+- (void)creditCardEditDidEnd:(NSWindow *)sheet
+ returnCode:(int)returnCode
+ contextInfo:(void *)contextInfo {
+ DCHECK(contextInfo != NULL);
+ if (returnCode) {
+ CreditCard* creditCard = static_cast<CreditCard*>(contextInfo);
+ [creditCardSheetController copyModelToCreditCard:creditCard];
+ [tableView_ reloadData];
}
+ [sheet orderOut:self];
+ creditCardSheetController.reset(nil);
+}
- // Create a new default credit card, and add it to our array of controllers.
- string16 new_credit_card_name = l10n_util::GetStringUTF16(
- IDS_AUTOFILL_NEW_CREDITCARD);
- CreditCard newCreditCard(new_credit_card_name, 0);
- scoped_nsobject<AutoFillCreditCardViewController> creditCardViewController(
- [[AutoFillCreditCardViewController alloc]
- initWithCreditCard:newCreditCard
- disclosure:NSOnState
- controller:self]);
- [self willChangeValueForKey:@"creditCardLabels"];
- [creditCardFormViewControllers_.get() addObject:creditCardViewController];
- [self didChangeValueForKey:@"creditCardLabels"];
-
- // Embed the new address into our target view.
- [childView_ addSubview:[creditCardViewController view]
- positioned:NSWindowBelow relativeTo:insertionPoint];
- [[creditCardViewController view] setFrameOrigin:NSMakePoint(0, 0)];
-
- // Recalculate key view loop to account for change in view tree.
- [[self window] recalculateKeyViewLoop];
-}
-
-- (IBAction)deleteAddress:(id)sender {
- NSUInteger i = [addressFormViewControllers_.get() indexOfObject:sender];
- DCHECK(i != NSNotFound);
-
- // Remove controller's view from superview and remove from list of
- // controllers. Note on lifetime: removing view from super view decrements
- // refcount of view, removing controller from array decrements refcount of
- // controller which in-turn decrement refcount of view. Both should dealloc
- // at this point.
- [[sender view] removeFromSuperview];
- [self willChangeValueForKey:@"addressLabels"];
- [addressFormViewControllers_.get() removeObjectAtIndex:i];
- [self didChangeValueForKey:@"addressLabels"];
-
- [self notifyAddressChange:self];
-
- // Recalculate key view loop to account for change in view tree.
- [[self window] recalculateKeyViewLoop];
-}
-
-- (IBAction)deleteCreditCard:(id)sender {
- NSUInteger i = [creditCardFormViewControllers_.get() indexOfObject:sender];
- DCHECK(i != NSNotFound);
-
- // Remove controller's view from superview and remove from list of
- // controllers. Note on lifetime: removing view from super view decrements
- // refcount of view, removing controller from array decrements refcount of
- // controller which in-turn decrement refcount of view. Both should dealloc
- // at this point.
- [[sender view] removeFromSuperview];
- [self willChangeValueForKey:@"creditCardLabels"];
- [creditCardFormViewControllers_.get() removeObjectAtIndex:i];
- [self didChangeValueForKey:@"creditCardLabels"];
-
- // Recalculate key view loop to account for change in view tree.
- [[self window] recalculateKeyViewLoop];
-}
-
-// Credit card controllers are dependent upon the address labels. So we notify
-// them here that something has changed.
-- (IBAction)notifyAddressChange:(id)sender {
- for (AutoFillCreditCardViewController* creditCardFormViewController in
- creditCardFormViewControllers_.get()) {
- [creditCardFormViewController onAddressesChanged:self];
+// NSTableView Delegate method.
+- (BOOL)tableView:(NSTableView *)tableView isGroupRow:(NSInteger)row {
+ if ([self isProfileGroupRow:row] || [self isCreditCardGroupRow:row])
+ return YES;
+ return NO;
+}
+
+// NSTableView Delegate method.
+- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row {
+ return ![self tableView:tableView isGroupRow:row];
+}
+
+// NSTableView Delegate method.
+- (id)tableView:(NSTableView *)tableView
+ objectValueForTableColumn:(NSTableColumn *)tableColumn
+ row:(NSInteger)row {
+ if ([[tableColumn identifier] isEqualToString:@"Spacer"])
+ return @"";
+
+ // Check that we're initialized before supplying data.
+ if (tableView == tableView_) {
+
+ // Section label.
+ if ([self isProfileGroupRow:row])
+ if ([[tableColumn identifier] isEqualToString:@"Label"])
+ return @"Addresses";
+ else
+ return @"";
+
+ if (row < 0)
+ return @"";
+
+ // Data row.
+ if ([self isProfileRow:row]) {
+ if ([[tableColumn identifier] isEqualToString:@"Label"])
+ return SysUTF16ToNSString(
+ profiles_[[self profileIndexFromRow:row]].Label());
+
+ if ([[tableColumn identifier] isEqualToString:@"Summary"])
+ return SysUTF16ToNSString(
+ profiles_[[self profileIndexFromRow:row]].PreviewSummary());
+
+ return @"";
+ }
+
+ // Section label.
+ if ([self isCreditCardGroupRow:row])
+ if ([[tableColumn identifier] isEqualToString:@"Label"])
+ return @"Credit Cards";
+ else
+ return @"";
+
+ // Data row.
+ if ([self isCreditCardRow:row]) {
+ if ([[tableColumn identifier] isEqualToString:@"Label"])
+ return SysUTF16ToNSString(
+ creditCards_[[self creditCardIndexFromRow:row]].Label());
+
+ if ([[tableColumn identifier] isEqualToString:@"Summary"])
+ return SysUTF16ToNSString(
+ creditCards_[
+ [self creditCardIndexFromRow:row]].PreviewSummary());
+
+ return @"";
+ }
}
+
+ return @"";
}
-- (NSArray*)addressLabels {
- NSUInteger capacity = [addressFormViewControllers_ count];
- NSMutableArray* array = [NSMutableArray arrayWithCapacity:capacity];
+// We implement this delegate method to update our |itemIsSelected| property.
+// The "Edit..." and "Remove" buttons' enabled state depends on having a
+// valid selection in the table.
+- (void)tableViewSelectionDidChange:(NSNotification *)aNotification {
+ if ([tableView_ selectedRow] >= 0)
+ [self setItemIsSelected:YES];
+ else
+ [self setItemIsSelected:NO];
+}
- for (AutoFillAddressViewController* addressFormViewController in
- addressFormViewControllers_.get()) {
- [array addObject:[[addressFormViewController addressModel] label]];
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
+ if (tableView == tableView_) {
+ // 1 section header, the profiles, 1 section header, the credit cards.
+ return 1 + profiles_.size() + 1 + creditCards_.size();
}
- return array;
+ return 0;
}
-- (NSArray*)creditCardLabels {
- NSUInteger capacity = [creditCardFormViewControllers_ count];
+- (NSArray*)addressLabels {
+ NSUInteger capacity = profiles_.size();
NSMutableArray* array = [NSMutableArray arrayWithCapacity:capacity];
- for (AutoFillCreditCardViewController* creditCardFormViewController in
- creditCardFormViewControllers_.get()) {
- [array addObject:[[creditCardFormViewController creditCardModel] label]];
+ std::vector<AutoFillProfile>::iterator i;
+ for (i = profiles_.begin(); i != profiles_.end(); ++i) {
+ [array addObject:SysUTF16ToNSString(i->Label())];
}
return array;
@@ -361,13 +569,14 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
profile:(Profile*)profile
importedProfile:(AutoFillProfile*)importedProfile
importedCreditCard:(CreditCard*)importedCreditCard {
- CHECK(profile);
+ DCHECK(profile);
// Use initWithWindowNibPath: instead of initWithWindowNibName: so we
// can override it in a unit test.
NSString* nibpath = [mac_util::MainAppBundle()
pathForResource:@"AutoFillDialog"
ofType:@"nib"];
if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ // Initialize member variables based on input.
observer_ = observer;
profile_ = profile;
importedProfile_ = importedProfile;
@@ -380,14 +589,6 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
// Do not use [NSMutableArray array] here; we need predictable destruction
// which will be prevented by having a reference held by an autorelease
// pool.
-
- // Initialize array of sub-controllers.
- addressFormViewControllers_.reset(
- [[NSMutableArray alloc] initWithCapacity:0]);
-
- // Initialize array of sub-controllers.
- creditCardFormViewControllers_.reset(
- [[NSMutableArray alloc] initWithCapacity:0]);
}
return self;
}
@@ -398,12 +599,24 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
[NSApp stopModal];
}
-- (NSMutableArray*)addressFormViewControllers {
- return addressFormViewControllers_.get();
+- (AutoFillAddressSheetController*)addressSheetController {
+ return addressSheetController.get();
+}
+
+- (AutoFillCreditCardSheetController*)creditCardSheetController {
+ return creditCardSheetController.get();
+}
+
+- (void)selectAddressAtIndex:(size_t)i {
+ [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:
+ [self rowFromProfileIndex:i]]
+ byExtendingSelection:NO];
}
-- (NSMutableArray*)creditCardFormViewControllers {
- return creditCardFormViewControllers_.get();
+- (void)selectCreditCardAtIndex:(size_t)i {
+ [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:
+ [self rowFromCreditCardIndex:i]]
+ byExtendingSelection:NO];
}
@end
@@ -424,52 +637,6 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
[NSApp runModalForWindow:[self window]];
}
-// Install controller and views for the address form and the credit card form.
-// They are installed into the appropriate sibling order so that they can be
-// arranged vertically by the VerticalLayoutView class. We insert the views
-// into the |childView_| but we hold onto the controllers and release them in
-// our dealloc once the dialog closes.
-- (void)installChildViews {
- NSView* insertionPoint;
- insertionPoint = addressSection_;
- for (size_t i = 0; i < profiles_.size(); i++) {
- // Special case for first address, we want to show full contents.
- NSCellStateValue disclosureState = (i == 0) ? NSOnState : NSOffState;
- scoped_nsobject<AutoFillAddressViewController> addressViewController(
- [[AutoFillAddressViewController alloc]
- initWithProfile:profiles_[i]
- disclosure:disclosureState
- controller:self]);
- [self willChangeValueForKey:@"addressLabels"];
- [addressFormViewControllers_.get() addObject:addressViewController];
- [self didChangeValueForKey:@"addressLabels"];
-
- // Embed the child view into our (owned by us) target view.
- [childView_ addSubview:[addressViewController view]
- positioned:NSWindowBelow relativeTo:insertionPoint];
- insertionPoint = [addressViewController view];
- [[addressViewController view] setFrameOrigin:NSMakePoint(0, 0)];
- }
-
- insertionPoint = creditCardSection_;
- for (size_t i = 0; i < creditCards_.size(); i++) {
- scoped_nsobject<AutoFillCreditCardViewController> creditCardViewController(
- [[AutoFillCreditCardViewController alloc]
- initWithCreditCard:creditCards_[i]
- disclosure:NSOffState
- controller:self]);
- [self willChangeValueForKey:@"creditCardLabels"];
- [creditCardFormViewControllers_.get() addObject:creditCardViewController];
- [self didChangeValueForKey:@"creditCardLabels"];
-
- // Embed the child view into our (owned by us) target view.
- [childView_ addSubview:[creditCardViewController view]
- positioned:NSWindowBelow relativeTo:insertionPoint];
- insertionPoint = [creditCardViewController view];
- [[creditCardViewController view] setFrameOrigin:NSMakePoint(0, 0)];
- }
-}
-
- (void)onPersonalDataLoaded:(const std::vector<AutoFillProfile*>&)profiles
creditCards:(const std::vector<CreditCard*>&)creditCards {
if (importedProfile_) {
@@ -492,8 +659,116 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() {
iter != creditCards.end(); ++iter)
creditCards_.push_back(**iter);
}
+}
+
+- (BOOL)isProfileRow:(NSInteger)row {
+ if (row > 0 && static_cast<size_t>(row) <= profiles_.size())
+ return YES;
+ return NO;
+}
+
+- (BOOL)isProfileGroupRow:(NSInteger)row {
+ if (row == 0)
+ return YES;
+ return NO;
+}
+
+- (BOOL)isCreditCardRow:(NSInteger)row {
+ if (row > 0 &&
+ static_cast<size_t>(row) >= profiles_.size() + 2 &&
+ static_cast<size_t>(row) <= profiles_.size() + creditCards_.size() + 1)
+ return YES;
+ return NO;
+}
+
+- (BOOL)isCreditCardGroupRow:(NSInteger)row {
+ if (row > 0 && static_cast<size_t>(row) == profiles_.size() + 1)
+ return YES;
+ return NO;
+}
+
+- (size_t)profileIndexFromRow:(NSInteger)row {
+ DCHECK([self isProfileRow:row]);
+ return static_cast<size_t>(row) - 1;
+}
+
+- (size_t)creditCardIndexFromRow:(NSInteger)row {
+ DCHECK([self isCreditCardRow:row]);
+ return static_cast<size_t>(row) - (profiles_.size() + 2);
+}
+
+- (NSInteger)rowFromProfileIndex:(size_t)i {
+ return 1 + i;
+}
+
+- (NSInteger)rowFromCreditCardIndex:(size_t)i {
+ return 1 + profiles_.size() + 1 + i;
+}
+
+@end
+
+// An NSValueTransformer subclass for use in validation of empty data entry
+// fields. Transforms a nil or empty string into a warning image. This data
+// transformer is used in the address and credit card sheets for empty label
+// strings.
+@interface MissingAlertTransformer : NSValueTransformer {
+}
+@end
+
+@implementation MissingAlertTransformer
++ (Class)transformedValueClass {
+ return [NSImage class];
+}
+
++ (BOOL)allowsReverseTransformation {
+ return NO;
+}
+
+- (id)transformedValue:(id)string {
+ if (string == nil || [string length] == 0) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSImage* image = rb.GetNSImageNamed(IDR_WARNING);
+ DCHECK(image);
+ return image;
+ }
+ return nil;
+}
+
+@end
+
+// An NSValueTransformer subclass for use in validation of phone number
+// fields. Transforms an invalid phone number string into a warning image.
+// This data transformer is used in the credit card sheet for invalid phone and
+// fax numbers.
+@interface InvalidPhoneTransformer : NSValueTransformer {
+}
+@end
+
+@implementation InvalidPhoneTransformer
++ (Class)transformedValueClass {
+ return [NSImage class];
+}
- [self installChildViews];
++ (BOOL)allowsReverseTransformation {
+ return NO;
+}
+
+- (id)transformedValue:(id)string {
+ if (string != nil && [string length] != 0) {
+ // TODO(dhollowa): Using SetInfo() call to validate phone number. Should
+ // have explicit validation method. More robust validation is needed as
+ // well eventually.
+ AutoFillProfile profile(string16(), 0);
+ profile.SetInfo(AutoFillType(PHONE_HOME_WHOLE_NUMBER),
+ base::SysNSStringToUTF16(string));
+ if (profile.GetFieldText(AutoFillType(PHONE_HOME_WHOLE_NUMBER)).empty()) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ NSImage* image = rb.GetNSImageNamed(IDR_WARNING);
+ DCHECK(image);
+ return image;
+ }
+ }
+ return nil;
}
@end