Index: chrome/browser/autofill/autofill_dialog_controller_mac.mm |
diff --git a/chrome/browser/autofill/autofill_dialog_controller_mac.mm b/chrome/browser/autofill/autofill_dialog_controller_mac.mm |
index c867497bcb28ee677aef41f808bed76d1965097e..c39e3e8c086bd912eaaf429a6d11cda0201f03e8 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 |