summaryrefslogtreecommitdiffstats
path: root/chrome/browser/autofill
diff options
context:
space:
mode:
authordhollowa@chromium.org <dhollowa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-09 17:19:57 +0000
committerdhollowa@chromium.org <dhollowa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-09 17:19:57 +0000
commitcff83feff679cf3f593f1c591ac91fc3b47277bd (patch)
tree052429411724e60429b6b4c5905fd4e469e283d4 /chrome/browser/autofill
parentba4874ea3edd4142f1f56d533dad25274e484edb (diff)
downloadchromium_src-cff83feff679cf3f593f1c591ac91fc3b47277bd.zip
chromium_src-cff83feff679cf3f593f1c591ac91fc3b47277bd.tar.gz
chromium_src-cff83feff679cf3f593f1c591ac91fc3b47277bd.tar.bz2
AutoFill Profiles dialog implemented according to new mocks on Mac
New mocks are attached to bug 44622. These changes replace the in-place editing of address and credit card records with a table of records and separate sheets for manipulating the record data. Changes to the layout of fields on the sheets has been done also. AutoFillDialog.xib changes: Replaced disclosure based list of address and credit cards with an NSTableView of the same data. Added buttons for "Add", "Edit", and "Remove". Replaced AutoFillAddressViewController.xib with sheet-based AutoFillAddressSheetController.xib. Replaced AutoFillCreditCardViewController.xib with sheet-based AutoFillCreditCardSheetController.xib. BUG=44621 TEST=AutoFillAddressModelTest,AutoFillAddressSheetControllerTest,AutoFillCreditCardModelTest,AutoFillCreditCardSheetControllerTest,AutoFillDialogControllerTest Review URL: http://codereview.chromium.org/2673006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@49274 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/autofill')
-rw-r--r--chrome/browser/autofill/autofill_address_model_mac.h13
-rw-r--r--chrome/browser/autofill/autofill_address_model_mac.mm44
-rw-r--r--chrome/browser/autofill/autofill_address_model_mac_unittest.mm10
-rw-r--r--chrome/browser/autofill/autofill_address_sheet_controller_mac.h (renamed from chrome/browser/autofill/autofill_address_view_controller_mac.h)43
-rw-r--r--chrome/browser/autofill/autofill_address_sheet_controller_mac.mm66
-rw-r--r--chrome/browser/autofill/autofill_address_sheet_controller_mac_unittest.mm (renamed from chrome/browser/autofill/autofill_address_view_controller_mac_unittest.mm)13
-rw-r--r--chrome/browser/autofill/autofill_address_view_controller_mac.mm73
-rw-r--r--chrome/browser/autofill/autofill_credit_card_model_mac.h6
-rw-r--r--chrome/browser/autofill/autofill_credit_card_model_mac.mm26
-rw-r--r--chrome/browser/autofill/autofill_credit_card_model_mac_unittest.mm3
-rw-r--r--chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.h (renamed from chrome/browser/autofill/autofill_credit_card_view_controller_mac.h)60
-rw-r--r--chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.mm165
-rw-r--r--chrome/browser/autofill/autofill_credit_card_sheet_controller_mac_unittest.mm (renamed from chrome/browser/autofill/autofill_credit_card_view_controller_mac_unittest.mm)13
-rw-r--r--chrome/browser/autofill/autofill_credit_card_view_controller_mac.mm128
-rw-r--r--chrome/browser/autofill/autofill_dialog_controller_mac.h98
-rw-r--r--chrome/browser/autofill/autofill_dialog_controller_mac.mm711
-rw-r--r--chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm60
-rw-r--r--chrome/browser/autofill/contact_info.cc22
18 files changed, 929 insertions, 625 deletions
diff --git a/chrome/browser/autofill/autofill_address_model_mac.h b/chrome/browser/autofill/autofill_address_model_mac.h
index 9ea052f..611fc7f 100644
--- a/chrome/browser/autofill/autofill_address_model_mac.h
+++ b/chrome/browser/autofill/autofill_address_model_mac.h
@@ -12,7 +12,6 @@ class AutoFillProfile;
// A "model" class used with bindings mechanism and the
// |AutoFillAddressViewController| to achieve the form-like view
// of autofill data in the Chrome options UI.
-// Note that |summary| is a derived property.
// Model objects are initialized from a given profile using the designated
// initializer |initWithProfile:|.
// Users of this class must be prepared to handle nil string return values.
@@ -22,9 +21,7 @@ class AutoFillProfile;
@private
// These are not scoped_nsobjects because we use them via KVO/bindings.
NSString* label_;
- NSString* firstName_;
- NSString* middleName_;
- NSString* lastName_;
+ NSString* fullName_;
NSString* email_;
NSString* companyName_;
NSString* addressLine1_;
@@ -37,14 +34,8 @@ class AutoFillProfile;
NSString* faxWholeNumber_;
}
-// |summary| is a derived property based on |firstName|, |lastName| and
-// |addressLine1|. KVO observers receive change notifications for |summary|
-// when any of these properties change.
-@property (readonly) NSString* summary;
@property (nonatomic, copy) NSString* label;
-@property (nonatomic, copy) NSString* firstName;
-@property (nonatomic, copy) NSString* middleName;
-@property (nonatomic, copy) NSString* lastName;
+@property (nonatomic, copy) NSString* fullName;
@property (nonatomic, copy) NSString* email;
@property (nonatomic, copy) NSString* companyName;
@property (nonatomic, copy) NSString* addressLine1;
diff --git a/chrome/browser/autofill/autofill_address_model_mac.mm b/chrome/browser/autofill/autofill_address_model_mac.mm
index a3b2089..773f8fb 100644
--- a/chrome/browser/autofill/autofill_address_model_mac.mm
+++ b/chrome/browser/autofill/autofill_address_model_mac.mm
@@ -10,11 +10,8 @@
@implementation AutoFillAddressModel
-@dynamic summary;
@synthesize label = label_;
-@synthesize firstName = firstName_;
-@synthesize middleName = middleName_;
-@synthesize lastName = lastName_;
+@synthesize fullName = fullName_;
@synthesize email = email_;
@synthesize companyName = companyName_;
@synthesize addressLine1 = addressLine1_;
@@ -26,27 +23,11 @@
@synthesize phoneWholeNumber = phoneWholeNumber_;
@synthesize faxWholeNumber = faxWholeNumber_;
-// Sets up the KVO dependency between "summary" and dependent fields.
-+ (NSSet*)keyPathsForValuesAffectingValueForKey:(NSString*)key {
- NSSet* keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
-
- if ([key isEqualToString:@"summary"]) {
- NSSet* affectingKeys =
- [NSSet setWithObjects:@"firstName", @"lastName", @"addressLine1", nil];
- keyPaths = [keyPaths setByAddingObjectsFromSet:affectingKeys];
- }
- return keyPaths;
-}
-
- (id)initWithProfile:(const AutoFillProfile&)profile {
if ((self = [super init])) {
[self setLabel:SysUTF16ToNSString(profile.Label())];
- [self setFirstName:SysUTF16ToNSString(
- profile.GetFieldText(AutoFillType(NAME_FIRST)))];
- [self setMiddleName:SysUTF16ToNSString(
- profile.GetFieldText(AutoFillType(NAME_MIDDLE)))];
- [self setLastName:SysUTF16ToNSString(
- profile.GetFieldText(AutoFillType(NAME_LAST)))];
+ [self setFullName:SysUTF16ToNSString(
+ profile.GetFieldText(AutoFillType(NAME_FULL)))];
[self setEmail:SysUTF16ToNSString(
profile.GetFieldText(AutoFillType(EMAIL_ADDRESS)))];
[self setCompanyName:SysUTF16ToNSString(
@@ -73,9 +54,7 @@
- (void)dealloc {
[label_ release];
- [firstName_ release];
- [middleName_ release];
- [lastName_ release];
+ [fullName_ release];
[email_ release];
[companyName_ release];
[addressLine1_ release];
@@ -89,22 +68,11 @@
[super dealloc];
}
-- (NSString*)summary {
- // Create a temporary |profile| to generate summary string.
- AutoFillProfile profile(string16(), 0);
- [self copyModelToProfile:&profile];
- return SysUTF16ToNSString(profile.PreviewSummary());
-}
-
- (void)copyModelToProfile:(AutoFillProfile*)profile {
DCHECK(profile);
profile->set_label(base::SysNSStringToUTF16([self label]));
- profile->SetInfo(AutoFillType(NAME_FIRST),
- base::SysNSStringToUTF16([self firstName]));
- profile->SetInfo(AutoFillType(NAME_MIDDLE),
- base::SysNSStringToUTF16([self middleName]));
- profile->SetInfo(AutoFillType(NAME_LAST),
- base::SysNSStringToUTF16([self lastName]));
+ profile->SetInfo(AutoFillType(NAME_FULL),
+ base::SysNSStringToUTF16([self fullName]));
profile->SetInfo(AutoFillType(EMAIL_ADDRESS),
base::SysNSStringToUTF16([self email]));
profile->SetInfo(AutoFillType(COMPANY_NAME),
diff --git a/chrome/browser/autofill/autofill_address_model_mac_unittest.mm b/chrome/browser/autofill/autofill_address_model_mac_unittest.mm
index 9265e04..fcdd1cc 100644
--- a/chrome/browser/autofill/autofill_address_model_mac_unittest.mm
+++ b/chrome/browser/autofill/autofill_address_model_mac_unittest.mm
@@ -45,9 +45,7 @@ TEST(AutoFillAddressModelTest, InitializationFromProfile) {
EXPECT_TRUE(model.get());
EXPECT_TRUE([[model label] isEqualToString:@"Billing"]);
- EXPECT_TRUE([[model firstName] isEqualToString:@"Marion"]);
- EXPECT_TRUE([[model middleName] isEqualToString:@"Mitchell"]);
- EXPECT_TRUE([[model lastName] isEqualToString:@"Morrison"]);
+ EXPECT_TRUE([[model fullName] isEqualToString:@"Marion Mitchell Morrison"]);
EXPECT_TRUE([[model email] isEqualToString:@"johnwayne@me.xyz"]);
EXPECT_TRUE([[model companyName] isEqualToString:@"Fox"]);
EXPECT_TRUE([[model addressLine1] isEqualToString:@"123 Zoo St."]);
@@ -82,9 +80,7 @@ TEST(AutoFillAddressModelTest, CopyModelToProfile) {
EXPECT_TRUE(model.get());
[model setLabel:@"BillingX"];
- [model setFirstName:@"MarionX"];
- [model setMiddleName:@"MitchellX"];
- [model setLastName:@"MorrisonX"];
+ [model setFullName:@"MarionX MitchellX MorrisonX"];
[model setEmail:@"trigger@me.xyz"];
[model setCompanyName:@"FoxX"];
[model setAddressLine1:@"123 Xoo St."];
@@ -105,6 +101,8 @@ TEST(AutoFillAddressModelTest, CopyModelToProfile) {
profile.GetFieldText(AutoFillType(NAME_MIDDLE)));
EXPECT_EQ(ASCIIToUTF16("MorrisonX"),
profile.GetFieldText(AutoFillType(NAME_LAST)));
+ EXPECT_EQ(ASCIIToUTF16("MarionX MitchellX MorrisonX"),
+ profile.GetFieldText(AutoFillType(NAME_FULL)));
EXPECT_EQ(ASCIIToUTF16("trigger@me.xyz"),
profile.GetFieldText(AutoFillType(EMAIL_ADDRESS)));
EXPECT_EQ(ASCIIToUTF16("FoxX"),
diff --git a/chrome/browser/autofill/autofill_address_view_controller_mac.h b/chrome/browser/autofill/autofill_address_sheet_controller_mac.h
index 2367f8d..963d4ff 100644
--- a/chrome/browser/autofill/autofill_address_view_controller_mac.h
+++ b/chrome/browser/autofill/autofill_address_sheet_controller_mac.h
@@ -2,52 +2,57 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_ADDRESS_VIEW_CONTROLLER_MAC_
-#define CHROME_BROWSER_AUTOFILL_AUTOFILL_ADDRESS_VIEW_CONTROLLER_MAC_
+#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_ADDRESS_SHEET_CONTROLLER_MAC_
+#define CHROME_BROWSER_AUTOFILL_AUTOFILL_ADDRESS_SHEET_CONTROLLER_MAC_
#import <Cocoa/Cocoa.h>
-#import "chrome/browser/cocoa/disclosure_view_controller.h"
@class AutoFillAddressModel;
@class AutoFillDialogController;
class AutoFillProfile;
+// The sheet can be invoked in "Add" or "Edit" mode. This dictates the caption
+// seen at the top of the sheet.
+enum {
+ kAutoFillAddressAddMode = 0,
+ kAutoFillAddressEditMode = 1
+};
+typedef NSInteger AutoFillAddressMode;
+
// A class that coordinates the |addressModel| and the associated view
-// held in AutoFillAddressFormView.xib.
+// held in AutoFillAddressSheet.xib.
// |initWithProfile:| is the designated initializer. It takes |profile|
// and transcribes it to |addressModel| to which the view is bound.
-@interface AutoFillAddressViewController : DisclosureViewController {
+@interface AutoFillAddressSheetController : NSWindowController {
@private
+ // The caption at top of dialog. Text changes according to usage. Either
+ // "New address" or "Edit address" depending on |mode_|.
+ IBOutlet NSTextField* caption_;
+
// The primary model for this controller. The model is instantiated
// from within |initWithProfile:|. We do not hold it as a scoped_nsobject
// because it is exposed as a KVO compliant property.
// Strong reference.
AutoFillAddressModel* addressModel_;
- // A reference to our parent controller. Used for notifying parent if/when
- // deletion occurs. Also used to notify parent when the label of the address
- // changes. May be not be nil.
- // Weak reference, owns us.
- AutoFillDialogController* parentController_;
+ // Either "Add" or "Edit" mode of sheet.
+ AutoFillAddressMode mode_;
}
@property (nonatomic, retain) AutoFillAddressModel* addressModel;
+// IBActions for save and cancel buttons. Both invoke |endSheet:|.
+- (IBAction)save:(id)sender;
+- (IBAction)cancel:(id)sender;
+
// Designated initializer. Takes a copy of the data in |profile|,
// it is not held as a reference.
- (id)initWithProfile:(const AutoFillProfile&)profile
- disclosure:(NSCellStateValue)disclosureState
- controller:(AutoFillDialogController*) parentController;
-
-// Action to remove this address from the dialog. Forwards the request to
-// |parentController_| which does all the actual work. We have the action
-// here so that the delete button in the AutoFillAddressViewFormView.xib has
-// something to call.
-- (IBAction)deleteAddress:(id)sender;
+ mode:(AutoFillAddressMode)mode;
// Copy data from internal model to |profile|.
- (void)copyModelToProfile:(AutoFillProfile*)profile;
@end
-#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_ADDRESS_VIEW_CONTROLLER_MAC_
+#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_ADDRESS_SHEET_CONTROLLER_MAC_
diff --git a/chrome/browser/autofill/autofill_address_sheet_controller_mac.mm b/chrome/browser/autofill/autofill_address_sheet_controller_mac.mm
new file mode 100644
index 0000000..1a6305d
--- /dev/null
+++ b/chrome/browser/autofill/autofill_address_sheet_controller_mac.mm
@@ -0,0 +1,66 @@
+// Copyright (c) 2010 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/autofill/autofill_address_sheet_controller_mac.h"
+
+#include "app/l10n_util.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_dialog_controller_mac.h"
+#include "chrome/browser/autofill/autofill_profile.h"
+#include "grit/generated_resources.h"
+
+@implementation AutoFillAddressSheetController
+
+@synthesize addressModel = addressModel_;
+
+- (id)initWithProfile:(const AutoFillProfile&)profile
+ mode:(AutoFillAddressMode)mode {
+ NSString* nibPath = [mac_util::MainAppBundle()
+ pathForResource:@"AutoFillAddressSheet"
+ ofType:@"nib"];
+ self = [super initWithWindowNibPath:nibPath owner:self];
+ if (self) {
+ // Create the model.
+ [self setAddressModel:[[[AutoFillAddressModel alloc]
+ initWithProfile:profile] autorelease]];
+
+ mode_ = mode;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [addressModel_ release];
+ [super dealloc];
+}
+
+- (void)awakeFromNib {
+ NSString* caption;
+ if (mode_ == kAutoFillAddressAddMode)
+ caption = l10n_util::GetNSString(IDS_AUTOFILL_ADD_ADDRESS_CAPTION);
+ else if (mode_ == kAutoFillAddressEditMode)
+ caption = l10n_util::GetNSString(IDS_AUTOFILL_EDIT_ADDRESS_CAPTION);
+ else
+ NOTREACHED();
+ [caption_ setStringValue:caption];
+}
+
+- (IBAction)save:(id)sender {
+ // Call |makeFirstResponder:| to commit pending text field edits.
+ [[self window] makeFirstResponder:[self window]];
+
+ [NSApp endSheet:[self window] returnCode:1];
+}
+
+- (IBAction)cancel:(id)sender {
+ [NSApp endSheet:[self window] returnCode:0];
+}
+
+- (void)copyModelToProfile:(AutoFillProfile*)profile {
+ [addressModel_ copyModelToProfile:profile];
+}
+
+@end
diff --git a/chrome/browser/autofill/autofill_address_view_controller_mac_unittest.mm b/chrome/browser/autofill/autofill_address_sheet_controller_mac_unittest.mm
index b5c857c..f46425d 100644
--- a/chrome/browser/autofill/autofill_address_view_controller_mac_unittest.mm
+++ b/chrome/browser/autofill/autofill_address_sheet_controller_mac_unittest.mm
@@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "base/scoped_nsobject.h"
-#import "chrome/browser/autofill/autofill_address_view_controller_mac.h"
+#import "chrome/browser/autofill/autofill_address_sheet_controller_mac.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/cocoa/browser_test_helper.h"
#import "chrome/browser/cocoa/cocoa_test_helper.h"
@@ -11,17 +11,16 @@
namespace {
-typedef CocoaTest AutoFillAddressViewControllerTest;
+typedef CocoaTest AutoFillAddressSheetControllerTest;
-TEST(AutoFillAddressViewControllerTest, Basic) {
+TEST(AutoFillAddressSheetControllerTest, Basic) {
// A basic test that creates a new instance and releases.
// Aids valgrind leak detection.
AutoFillProfile profile(ASCIIToUTF16("Home"), 0);
- scoped_nsobject<AutoFillAddressViewController> controller(
- [[AutoFillAddressViewController alloc]
+ scoped_nsobject<AutoFillAddressSheetController> controller(
+ [[AutoFillAddressSheetController alloc]
initWithProfile:profile
- disclosure:NSOffState
- controller:nil]);
+ mode:kAutoFillAddressAddMode]);
EXPECT_TRUE(controller.get());
}
diff --git a/chrome/browser/autofill/autofill_address_view_controller_mac.mm b/chrome/browser/autofill/autofill_address_view_controller_mac.mm
deleted file mode 100644
index e3163f8..0000000
--- a/chrome/browser/autofill/autofill_address_view_controller_mac.mm
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 2010 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/autofill/autofill_address_view_controller_mac.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_dialog_controller_mac.h"
-#include "chrome/browser/autofill/autofill_profile.h"
-#import "third_party/GTM/Foundation/GTMNSObject+KeyValueObserving.h"
-
-@interface AutoFillAddressViewController (PrivateMethods)
-- (void)labelChanged:(GTMKeyValueChangeNotification*)notification;
-@end
-
-@implementation AutoFillAddressViewController
-
-@synthesize addressModel = addressModel_;
-
-- (id)initWithProfile:(const AutoFillProfile&)profile
- disclosure:(NSCellStateValue)disclosureState
- controller:(AutoFillDialogController*) parentController {
- self = [super initWithNibName:@"AutoFillAddressFormView"
- bundle:mac_util::MainAppBundle()
- disclosure:disclosureState];
- if (self) {
- // Pull in the view for initialization.
- [self view];
-
- // Create the model.
- [self setAddressModel:[[[AutoFillAddressModel alloc]
- initWithProfile:profile] autorelease]];
-
- // We keep track of our parent controller for model-update purposes.
- parentController_ = parentController;
-
- // Register |self| as observer so we can notify parent controller. See
- // |labelChanged:| for details.
- [addressModel_ gtm_addObserver:self
- forKeyPath:@"label"
- selector:@selector(labelChanged:)
- userInfo:nil
- options:0];
- }
- return self;
-}
-
-- (void)dealloc {
- [addressModel_ gtm_removeObserver:self
- forKeyPath:@"label"
- selector:@selector(labelChanged:)];
- [addressModel_ release];
- [super dealloc];
-}
-
-// Override KVO method to notify parent controller when the address "label"
-// changes. Credit card UI updates accordingly.
-- (void)labelChanged:(GTMKeyValueChangeNotification*)notification {
- [parentController_ notifyAddressChange:self];
-}
-
-- (IBAction)deleteAddress:(id)sender {
- [parentController_ deleteAddress:self];
-}
-
-- (void)copyModelToProfile:(AutoFillProfile*)profile {
- [addressModel_ copyModelToProfile:profile];
-}
-
-@end
-
-
diff --git a/chrome/browser/autofill/autofill_credit_card_model_mac.h b/chrome/browser/autofill/autofill_credit_card_model_mac.h
index 97dfb67..202202e 100644
--- a/chrome/browser/autofill/autofill_credit_card_model_mac.h
+++ b/chrome/browser/autofill/autofill_credit_card_model_mac.h
@@ -12,7 +12,6 @@ class CreditCard;
// A "model" class used with bindings mechanism and the
// |AutoFillCreditCardViewController| to achieve the form-like view
// of autofill data in the Chrome options UI.
-// Note that |summary| is a derived property.
// Model objects are initialized from the given |creditCard| using the
// designated initializer |initWithCreditCard:|.
// Users of this class must be prepared to handle nil string return values.
@@ -31,10 +30,6 @@ class CreditCard;
NSString* shippingAddress_;
}
-// |summary| is a derived property based on |creditCardNumber|,
-// |expirationMonth| and |expirationYear|. KVO observers receive change
-// notifications for |summary| when any of these properties change.
-@property (readonly) NSString* summary;
@property (nonatomic, copy) NSString* label;
@property (nonatomic, copy) NSString* nameOnCard;
@property (nonatomic, copy) NSString* creditCardNumber;
@@ -42,7 +37,6 @@ class CreditCard;
@property (nonatomic, copy) NSString* expirationYear;
@property (nonatomic, copy) NSString* cvcCode;
@property (nonatomic, copy) NSString* billingAddress;
-@property (nonatomic, copy) NSString* shippingAddress;
// Designated initializer. Initializes the property strings to values retrieved
// from the |creditCard| object.
diff --git a/chrome/browser/autofill/autofill_credit_card_model_mac.mm b/chrome/browser/autofill/autofill_credit_card_model_mac.mm
index c75e14f..f75bd05 100644
--- a/chrome/browser/autofill/autofill_credit_card_model_mac.mm
+++ b/chrome/browser/autofill/autofill_credit_card_model_mac.mm
@@ -11,7 +11,6 @@
@implementation AutoFillCreditCardModel
-@dynamic summary;
@synthesize label = label_;
@synthesize nameOnCard = nameOnCard_;
@synthesize creditCardNumber = creditCardNumber_;
@@ -19,19 +18,6 @@
@synthesize expirationYear = expirationYear_;
@synthesize cvcCode = cvcCode_;
@synthesize billingAddress = billingAddress_;
-@synthesize shippingAddress = shippingAddress_;
-
-// Sets up the KVO dependency between "summary" and dependent fields.
-+ (NSSet*)keyPathsForValuesAffectingValueForKey:(NSString*)key {
- NSSet* keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
-
- if ([key isEqualToString:@"summary"]) {
- NSSet* affectingKeys = [NSSet setWithObjects:@"creditCardNumber",
- @"expirationMonth", @"expirationYear", nil];
- keyPaths = [keyPaths setByAddingObjectsFromSet:affectingKeys];
- }
- return keyPaths;
-}
- (id)initWithCreditCard:(const CreditCard&)creditCard {
if ((self = [super init])) {
@@ -48,8 +34,6 @@
creditCard.GetFieldText(AutoFillType(CREDIT_CARD_VERIFICATION_CODE)))];
[self setBillingAddress:SysUTF16ToNSString(
creditCard.billing_address())];
- [self setShippingAddress:SysUTF16ToNSString(
- creditCard.shipping_address())];
}
return self;
}
@@ -62,17 +46,9 @@
[expirationYear_ release];
[cvcCode_ release];
[billingAddress_ release];
- [shippingAddress_ release];
[super dealloc];
}
-- (NSString*)summary {
- // Create a temporary |creditCard| to generate summary string.
- CreditCard creditCard(string16(), 0);
- [self copyModelToCreditCard:&creditCard];
- return SysUTF16ToNSString(creditCard.PreviewSummary());
-}
-
- (void)copyModelToCreditCard:(CreditCard*)creditCard {
DCHECK(creditCard);
creditCard->set_label(base::SysNSStringToUTF16([self label]));
@@ -88,8 +64,6 @@
base::SysNSStringToUTF16([self cvcCode]));
creditCard->set_billing_address(
base::SysNSStringToUTF16([self billingAddress]));
- creditCard->set_shipping_address(
- base::SysNSStringToUTF16([self shippingAddress]));
}
@end
diff --git a/chrome/browser/autofill/autofill_credit_card_model_mac_unittest.mm b/chrome/browser/autofill/autofill_credit_card_model_mac_unittest.mm
index 6fdb1142..6d77e20 100644
--- a/chrome/browser/autofill/autofill_credit_card_model_mac_unittest.mm
+++ b/chrome/browser/autofill/autofill_credit_card_model_mac_unittest.mm
@@ -47,7 +47,6 @@ TEST(AutoFillCreditCardModelTest, InitializationFromCreditCard) {
EXPECT_TRUE([[model expirationYear] isEqualToString:@"2010"]);
EXPECT_TRUE([[model cvcCode] isEqualToString:@"123"]);
EXPECT_TRUE([[model billingAddress] isEqualToString:@"Chicago"]);
- EXPECT_TRUE([[model shippingAddress] isEqualToString:@"Indianapolis"]);
}
TEST(AutoFillCreditCardModelTest, CopyModelToCreditCard) {
@@ -74,7 +73,6 @@ TEST(AutoFillCreditCardModelTest, CopyModelToCreditCard) {
[model setExpirationYear:@"2011"];
[model setCvcCode:@"223"];
[model setBillingAddress:@"New York"];
- [model setShippingAddress:@"Boston"];
[model copyModelToCreditCard:&credit_card];
@@ -92,7 +90,6 @@ TEST(AutoFillCreditCardModelTest, CopyModelToCreditCard) {
credit_card.GetFieldText(
AutoFillType(CREDIT_CARD_VERIFICATION_CODE)));
EXPECT_EQ(ASCIIToUTF16("New York"), credit_card.billing_address());
- EXPECT_EQ(ASCIIToUTF16("Boston"), credit_card.shipping_address());
}
} // namespace
diff --git a/chrome/browser/autofill/autofill_credit_card_view_controller_mac.h b/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.h
index 054252f..6fa281d 100644
--- a/chrome/browser/autofill/autofill_credit_card_view_controller_mac.h
+++ b/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.h
@@ -2,24 +2,36 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_CREDIT_CARD_VIEW_CONTROLLER_MAC_
-#define CHROME_BROWSER_AUTOFILL_AUTOFILL_CREDIT_CARD_VIEW_CONTROLLER_MAC_
+#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_CREDIT_CARD_SHEET_CONTROLLER_MAC_
+#define CHROME_BROWSER_AUTOFILL_AUTOFILL_CREDIT_CARD_SHEET_CONTROLLER_MAC_
#import <Cocoa/Cocoa.h>
-#import "chrome/browser/cocoa/disclosure_view_controller.h"
@class AutoFillCreditCardModel;
@class AutoFillDialogController;
class CreditCard;
+// The sheet can be invoked in "Add" or "Edit" mode. This dictates the caption
+// seen at the top of the sheet.
+enum {
+ kAutoFillCreditCardAddMode = 0,
+ kAutoFillCreditCardEditMode = 1
+};
+typedef NSInteger AutoFillCreditCardMode;
+
// A class that coordinates the |creditCardModel| and the associated view
-// held in AutoFillCreditCardFormView.xib.
+// held in AutoFillCreditCardSheet.xib.
// |initWithCreditCard:| is the designated initializer. It takes |creditCard|
// and transcribes it to |creditCardModel| to which the view is bound.
-@interface AutoFillCreditCardViewController : DisclosureViewController {
+@interface AutoFillCreditCardSheetController : NSWindowController {
@private
IBOutlet NSPopUpButton* billingAddressPopup_;
- IBOutlet NSPopUpButton* shippingAddressPopup_;
+ IBOutlet NSPopUpButton* expirationMonthPopup_;
+ IBOutlet NSPopUpButton* expirationYearPopup_;
+
+ // The caption at top of dialog. Text changes according to usage. Either
+ // "New credit card" or "Edit credit card" depending on context.
+ IBOutlet NSTextField* caption_;
// The primary model for this controller. The model is instantiated
// from within |initWithCreditCard:|. We do not hold it as a scoped_nsobject
@@ -32,41 +44,39 @@ class CreditCard;
// of addresses change in the |parentController_|.
NSArray* billingAddressContents_;
- // Array of strings that populate the |shippingAddressPopup_| control. We
- // do not hold this as scoped_nsobject because it is exposed as a KVO
- // compliant property. The values of this array may change as the list
- // of addresses change in the |parentController_|.
- NSArray* shippingAddressContents_;
+ // Contents of the expiration month and year popups. Strongly owned. We do
+ // not hold them as scoped_nsobjects because they are exposed as KVO compliant
+ // properties.
+ NSArray* expirationMonthContents_;
+ NSArray* expirationYearContents_;
- // A reference to our parent controller. Used for notifying parent if/when
- // deletion occurs. May be not be nil.
+ // A reference to our parent controller. Used for fetching billing address
+ // labels. May be not be nil.
// Weak reference, owns us.
AutoFillDialogController* parentController_;
+
+ // Either "Add" or "Edit" mode of sheet.
+ AutoFillCreditCardMode mode_;
}
@property (nonatomic, retain) AutoFillCreditCardModel* creditCardModel;
@property (nonatomic, retain) NSArray* billingAddressContents;
-@property (nonatomic, retain) NSArray* shippingAddressContents;
+@property (nonatomic, retain) NSArray* expirationMonthContents;
+@property (nonatomic, retain) NSArray* expirationYearContents;
// Designated initializer. Takes a copy of the data in |creditCard|,
// it is not held as a reference.
- (id)initWithCreditCard:(const CreditCard&)creditCard
- disclosure:(NSCellStateValue)disclosureState
+ mode:(AutoFillCreditCardMode)mode
controller:(AutoFillDialogController*)parentController;
-// Action to remove this credit card from the dialog. Forwards the request to
-// |parentController_| which does all the actual work. We have the action
-// here so that the delete button in the AutoFillCreditCardViewFormView.xib has
-// something to call.
-- (IBAction)deleteCreditCard:(id)sender;
-
-// Action to notify observers of the address list when changes have occured.
-// For the credit card controller this means rebuild the popup menus.
-- (IBAction)onAddressesChanged:(id)sender;
+// IBActions for save and cancel buttons. Both invoke |endSheet:|.
+- (IBAction)save:(id)sender;
+- (IBAction)cancel:(id)sender;
// Copy data from internal model to |creditCard|.
- (void)copyModelToCreditCard:(CreditCard*)creditCard;
@end
-#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_CREDIT_CARD_VIEW_CONTROLLER_MAC_
+#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_CREDIT_CARD_SHEET_CONTROLLER_MAC_
diff --git a/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.mm b/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.mm
new file mode 100644
index 0000000..11a6302
--- /dev/null
+++ b/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.mm
@@ -0,0 +1,165 @@
+// Copyright (c) 2010 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/autofill/autofill_credit_card_sheet_controller_mac.h"
+
+#include "app/l10n_util.h"
+#include "base/mac_util.h"
+#include "base/sys_string_conversions.h"
+#import "chrome/browser/autofill/autofill_credit_card_model_mac.h"
+#import "chrome/browser/autofill/autofill_dialog_controller_mac.h"
+#include "chrome/browser/autofill/credit_card.h"
+#include "grit/generated_resources.h"
+
+// Private methods for the |AutoFillCreditCardSheetController| class.
+@interface AutoFillCreditCardSheetController (PrivateMethods)
+- (void)buildBillingAddressContents;
+- (void)buildExpirationMonthContents;
+- (void)buildExpirationYearContents;
+@end
+
+@implementation AutoFillCreditCardSheetController
+
+@synthesize creditCardModel = creditCardModel_;
+@synthesize billingAddressContents = billingAddressContents_;
+@synthesize expirationMonthContents = expirationMonthContents_;
+@synthesize expirationYearContents = expirationYearContents_;
+
+- (id)initWithCreditCard:(const CreditCard&)creditCard
+ mode:(AutoFillCreditCardMode)mode
+ controller:(AutoFillDialogController*)parentController {
+ NSString* nibPath = [mac_util::MainAppBundle()
+ pathForResource:@"AutoFillCreditCardSheet"
+ ofType:@"nib"];
+ self = [super initWithWindowNibPath:nibPath owner:self];
+ if (self) {
+ // Create the model. We use setter here for KVO.
+ [self setCreditCardModel:[[[AutoFillCreditCardModel alloc]
+ initWithCreditCard:creditCard] autorelease]];
+
+ // We keep track of our parent controller for model-update purposes.
+ parentController_ = parentController;
+
+ mode_ = mode;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [creditCardModel_ release];
+ [billingAddressContents_ release];
+ [expirationMonthContents_ release];
+ [expirationYearContents_ release];
+ [super dealloc];
+}
+
+- (void)awakeFromNib {
+ // Setup initial state of popups.
+ [self buildBillingAddressContents];
+ [self buildExpirationMonthContents];
+ [self buildExpirationYearContents];
+
+ // Turn menu autoenable off. We manually govern this.
+ [billingAddressPopup_ setAutoenablesItems:NO];
+ [expirationMonthPopup_ setAutoenablesItems:NO];
+ [expirationYearPopup_ setAutoenablesItems:NO];
+
+ // Set the caption based on the mode.
+ NSString* caption;
+ if (mode_ == kAutoFillCreditCardAddMode)
+ caption = l10n_util::GetNSString(IDS_AUTOFILL_ADD_CREDITCARD_CAPTION);
+ else if (mode_ == kAutoFillCreditCardEditMode)
+ caption = l10n_util::GetNSString(IDS_AUTOFILL_EDIT_CREDITCARD_CAPTION);
+ else
+ NOTREACHED();
+ [caption_ setStringValue:caption];
+}
+
+- (IBAction)save:(id)sender {
+ // Call |makeFirstResponder:| to commit pending text field edits.
+ [[self window] makeFirstResponder:[self window]];
+
+ [NSApp endSheet:[self window] returnCode:1];
+}
+
+- (IBAction)cancel:(id)sender {
+ [NSApp endSheet:[self window] returnCode:0];
+}
+
+- (void)copyModelToCreditCard:(CreditCard*)creditCard {
+ // The model copies the popup values blindly. We need to clear the strings
+ // in the case that our special menus are in effect.
+ if ([billingAddressPopup_ indexOfSelectedItem] <= 0)
+ [creditCardModel_ setBillingAddress:@""];
+ if ([expirationMonthPopup_ indexOfSelectedItem] <= 0)
+ [creditCardModel_ setExpirationMonth:@""];
+ if ([expirationYearPopup_ indexOfSelectedItem] <= 0)
+ [creditCardModel_ setExpirationYear:@""];
+
+ [creditCardModel_ copyModelToCreditCard:creditCard];
+}
+
+// Builds the |billingAddressContents_| array of strings from the list of
+// addresses returned by the |parentController_| and additional UI string.
+// Ensures that current selection is valid. If not, reset it.
+- (void)buildBillingAddressContents {
+ NSString* menuString = l10n_util::GetNSString(
+ IDS_AUTOFILL_DIALOG_CHOOSE_EXISTING_ADDRESS);
+
+ // Build the menu array and set it.
+ NSArray* addressStrings = [parentController_ addressLabels];
+ NSArray* newArray = [[NSArray arrayWithObject:menuString]
+ arrayByAddingObjectsFromArray:addressStrings];
+ [self setBillingAddressContents:newArray];
+
+ // If the addresses no longer contain our selected item, reset the selection.
+ if ([addressStrings
+ indexOfObject:[creditCardModel_ billingAddress]] == NSNotFound) {
+ [creditCardModel_ setBillingAddress:menuString];
+ }
+
+ // Disable first item in menu. "Choose existing address" is a non-item.
+ [[billingAddressPopup_ itemAtIndex:0] setEnabled:NO];
+}
+
+// Builds array of valid months. Uses special @" " to indicate no selection.
+- (void)buildExpirationMonthContents {
+ NSArray* newArray = [NSArray arrayWithObjects:@" ",
+ @"01", @"02", @"03", @"04", @"05", @"06",
+ @"07", @"08", @"09", @"10", @"11", @"12", nil ];
+
+ [self setExpirationMonthContents:newArray];
+
+ // If the value from the model is not found in the array then set to the empty
+ // item @" ".
+ if ([newArray
+ indexOfObject:[creditCardModel_ expirationMonth]] == NSNotFound) {
+ [creditCardModel_ setExpirationMonth:@" "];
+ }
+
+ // Disable first item in menu. @" " is a non-item.
+ [[expirationMonthPopup_ itemAtIndex:0] setEnabled:NO];
+}
+
+// Builds array of valid years. Uses special @" " to indicate no selection.
+- (void)buildExpirationYearContents {
+ NSArray* newArray = [NSArray arrayWithObjects:@" ",
+ @"2010", @"2011", @"2012", @"2013", @"2014", @"2015",
+ @"2016", @"2017", @"2018", @"2019", @"2020", @"2021", nil ];
+
+ [self setExpirationYearContents:newArray];
+
+ // If the value from the model is not found in the array then set to the empty
+ // item @" ".
+ if ([newArray
+ indexOfObject:[creditCardModel_ expirationYear]] == NSNotFound) {
+ [creditCardModel_ setExpirationYear:@" "];
+ }
+
+ // Disable first item in menu. @" " is a non-item.
+ [[expirationYearPopup_ itemAtIndex:0] setEnabled:NO];
+}
+
+@end
+
diff --git a/chrome/browser/autofill/autofill_credit_card_view_controller_mac_unittest.mm b/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac_unittest.mm
index 8724f4b..a15b421 100644
--- a/chrome/browser/autofill/autofill_credit_card_view_controller_mac_unittest.mm
+++ b/chrome/browser/autofill/autofill_credit_card_sheet_controller_mac_unittest.mm
@@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "base/scoped_nsobject.h"
-#import "chrome/browser/autofill/autofill_credit_card_view_controller_mac.h"
+#import "chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.h"
#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/cocoa/browser_test_helper.h"
#import "chrome/browser/cocoa/cocoa_test_helper.h"
@@ -11,18 +11,19 @@
namespace {
-typedef CocoaTest AutoFillCreditCardViewControllerTest;
+typedef CocoaTest AutoFillCreditCardSheetControllerTest;
-TEST(AutoFillCreditCardViewControllerTest, Basic) {
+TEST(AutoFillCreditCardSheetControllerTest, Basic) {
// A basic test that creates a new instance and releases.
// Aids valgrind leak detection.
CreditCard credit_card(ASCIIToUTF16("myCC"), 0);
- scoped_nsobject<AutoFillCreditCardViewController> controller(
- [[AutoFillCreditCardViewController alloc]
+ scoped_nsobject<AutoFillCreditCardSheetController> controller(
+ [[AutoFillCreditCardSheetController alloc]
initWithCreditCard:credit_card
- disclosure:NSOffState
+ mode:kAutoFillCreditCardAddMode
controller:nil]);
EXPECT_TRUE(controller.get());
}
} // namespace
+
diff --git a/chrome/browser/autofill/autofill_credit_card_view_controller_mac.mm b/chrome/browser/autofill/autofill_credit_card_view_controller_mac.mm
deleted file mode 100644
index 8e7b29c..0000000
--- a/chrome/browser/autofill/autofill_credit_card_view_controller_mac.mm
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright (c) 2010 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/autofill/autofill_credit_card_view_controller_mac.h"
-#include "app/l10n_util.h"
-#include "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#import "chrome/browser/autofill/autofill_credit_card_model_mac.h"
-#import "chrome/browser/autofill/autofill_dialog_controller_mac.h"
-#include "chrome/browser/autofill/credit_card.h"
-#include "grit/generated_resources.h"
-
-// Private methods for the |AutoFillCreditCardViewController| class.
-@interface AutoFillCreditCardViewController (PrivateMethods)
-- (void)rebuildBillingAddressContents;
-- (void)rebuildShippingAddressContents;
-@end
-
-@implementation AutoFillCreditCardViewController
-
-@synthesize creditCardModel = creditCardModel_;
-@synthesize billingAddressContents = billingAddressContents_;
-@synthesize shippingAddressContents = shippingAddressContents_;
-
-- (id)initWithCreditCard:(const CreditCard&)creditCard
- disclosure:(NSCellStateValue)disclosureState
- controller:(AutoFillDialogController*)parentController {
- self = [super initWithNibName:@"AutoFillCreditCardFormView"
- bundle:mac_util::MainAppBundle()
- disclosure:disclosureState];
- if (self) {
- // Pull in the view for initialization.
- [self view];
-
- // Create the model. We use setter here for KVO.
- [self setCreditCardModel:[[[AutoFillCreditCardModel alloc]
- initWithCreditCard:creditCard] autorelease]];
-
- // We keep track of our parent controller for model-update purposes.
- parentController_ = parentController;
-
- // Setup initial state of popups.
- [self onAddressesChanged:self];
- }
- return self;
-}
-
-- (void)dealloc {
- [creditCardModel_ release];
- [billingAddressContents_ release];
- [shippingAddressContents_ release];
- [super dealloc];
-}
-
-- (void)awakeFromNib {
- [super awakeFromNib];
-
- // Turn menu autoenable off. We manually govern this.
- [billingAddressPopup_ setAutoenablesItems:NO];
- [shippingAddressPopup_ setAutoenablesItems:NO];
-}
-
-- (IBAction)deleteCreditCard:(id)sender {
- [parentController_ deleteCreditCard:self];
-}
-
-- (IBAction)onAddressesChanged:(id)sender {
- [self rebuildBillingAddressContents];
- [self rebuildShippingAddressContents];
-}
-
-- (void)copyModelToCreditCard:(CreditCard*)creditCard {
- [creditCardModel_ copyModelToCreditCard:creditCard];
-
- // The model copies the shipping and billing addresses blindly. We need
- // to clear the strings in the case that our special menus are in effect.
- if ([billingAddressPopup_ indexOfSelectedItem] <= 0)
- creditCard->set_billing_address(string16());
- if ([shippingAddressPopup_ indexOfSelectedItem] <= 0)
- creditCard->set_shipping_address(string16());
-}
-
-// Builds the |billingAddressContents_| array of strings from the list of
-// addresses returned by the |parentController_| and additional UI string.
-// Ensures that current selection is valid, if not reset it.
-- (void)rebuildBillingAddressContents {
- NSString* menuString = l10n_util::GetNSString(
- IDS_AUTOFILL_DIALOG_CHOOSE_EXISTING_ADDRESS);
-
- // Build the menu array and set it.
- NSArray* addressStrings = [parentController_ addressLabels];
- NSArray* newArray = [[NSArray arrayWithObject:menuString]
- arrayByAddingObjectsFromArray:addressStrings];
- [self setBillingAddressContents:newArray];
-
- // If the addresses no longer contain our selected item, reset the selection.
- if ([addressStrings
- indexOfObject:[creditCardModel_ billingAddress]] == NSNotFound) {
- [creditCardModel_ setBillingAddress:menuString];
- }
-
- // Disable first item in menu. "Choose existing address" is a non-item.
- [[billingAddressPopup_ itemAtIndex:0] setEnabled:NO];
-}
-
-// Builds the |shippingAddressContents_| array of strings from the list of
-// addresses returned by the |parentController_| and additional UI string.
-// Ensures that current selection is valid, if not reset it.
-- (void)rebuildShippingAddressContents {
- NSString* menuString = l10n_util::GetNSString(
- IDS_AUTOFILL_DIALOG_SAME_AS_BILLING);
-
- // Build the menu array and set it.
- NSArray* addressStrings = [parentController_ addressLabels];
- NSArray* newArray = [[NSArray arrayWithObject:menuString]
- arrayByAddingObjectsFromArray:addressStrings];
- [self setShippingAddressContents:newArray];
-
- // If the addresses no longer contain our selected item, reset the selection.
- if ([addressStrings
- indexOfObject:[creditCardModel_ shippingAddress]] == NSNotFound) {
- [creditCardModel_ setShippingAddress:menuString];
- }
-}
-
-@end
-
diff --git a/chrome/browser/autofill/autofill_dialog_controller_mac.h b/chrome/browser/autofill/autofill_dialog_controller_mac.h
index 3ea6900..ba4c4d4 100644
--- a/chrome/browser/autofill/autofill_dialog_controller_mac.h
+++ b/chrome/browser/autofill/autofill_dialog_controller_mac.h
@@ -17,10 +17,10 @@ namespace AutoFillDialogControllerInternal {
class PersonalDataManagerObserver;
} // AutoFillDialogControllerInternal
-@class AutoFillAddressViewController;
-@class AutoFillCreditCardViewController;
+@class AutoFillAddressSheetController;
+@class AutoFillCreditCardSheetController;
+@class AutoFillTableView;
class Profile;
-@class SectionSeparatorView;
@class WindowSizeAutosaver;
// A window controller for managing the autofill options dialog.
@@ -28,30 +28,52 @@ class Profile;
// personal address and credit card information.
@interface AutoFillDialogController : NSWindowController {
@private
- IBOutlet NSView* childView_;
- IBOutlet NSView* addressSection_;
- IBOutlet SectionSeparatorView* addressSectionBox_;
- IBOutlet NSView* creditCardSection_;
+ // Outlet to the main NSTableView object listing both addresses and credit
+ // cards with section headers for both.
+ IBOutlet AutoFillTableView* tableView_;
- // Note on ownership: the controllers are strongly owned by the dialog
- // controller. Their views are inserted into the dialog's view hierarchy
- // but are retained by these controllers as well.
+ // This observer is passed in by the caller of the dialog. When the dialog
+ // is dismissed |observer_| is called with new values for the addresses and
+ // credit cards.
+ // Weak, not retained.
+ AutoFillDialogObserver* observer_;
- // Array of |AutoFillAddressViewController|.
- scoped_nsobject<NSMutableArray> addressFormViewControllers_;
+ // Reference to input parameter.
+ // Weak, not retained.
+ Profile* profile_;
- // Array of |AutoFillCreditCardViewController|.
- scoped_nsobject<NSMutableArray> creditCardFormViewControllers_;
+ // Reference to input parameter.
+ // Weak, not retained.
+ AutoFillProfile* importedProfile_;
- AutoFillDialogObserver* observer_; // Weak, not retained.
- Profile* profile_; // Weak, not retained.
- AutoFillProfile* importedProfile_; // Weak, not retained.
- CreditCard* importedCreditCard_; // Weak, not retained.
+ // Reference to input parameter.
+ // Weak, not retained.
+ CreditCard* importedCreditCard_;
+
+ // Working list of input profiles.
std::vector<AutoFillProfile> profiles_;
+
+ // Working list of input credit cards.
std::vector<CreditCard> creditCards_;
+
+ // State of checkbox for enabling Mac Address Book integration.
BOOL auxiliaryEnabled_;
+
+ // State for |itemIsSelected| property used in bindings for "Edit..." and
+ // "Remove" buttons.
+ BOOL itemIsSelected_;
+
+ // Utility object to save and restore dialog position.
scoped_nsobject<WindowSizeAutosaver> sizeSaver_;
+ // Transient reference to address "Add" / "Edit" sheet for address
+ // information.
+ scoped_nsobject<AutoFillAddressSheetController> addressSheetController;
+
+ // Transient reference to address "Add" / "Edit" sheet for credit card
+ // information.
+ scoped_nsobject<AutoFillCreditCardSheetController> creditCardSheetController;
+
// Manages PersonalDataManager loading.
scoped_ptr<AutoFillDialogControllerInternal::PersonalDataManagerObserver>
personalDataManagerObserver_;
@@ -61,7 +83,11 @@ class Profile;
// bound to this in nib.
@property (nonatomic) BOOL auxiliaryEnabled;
-// Main interface for displaying an application modal autofill dialog on screen.
+// Property representing selection state in |tableView_|. Enabled state of
+// edit and delete buttons are bound to this property.
+@property (nonatomic) BOOL itemIsSelected;
+
+// Main interface for displaying an application modal AutoFill dialog on screen.
// This class method creates a new |AutoFillDialogController| and runs it as a
// modal dialog. The controller autoreleases itself when the dialog is closed.
// |observer| can be NULL, but if it is, then no notification is sent during
@@ -86,21 +112,25 @@ class Profile;
- (IBAction)addNewAddress:(id)sender;
- (IBAction)addNewCreditCard:(id)sender;
-// IBActions for deleting items. |sender| is expected to be either a
-// |AutoFillAddressViewController| or a |AutoFillCreditCardViewController|.
-- (IBAction)deleteAddress:(id)sender;
-- (IBAction)deleteCreditCard:(id)sender;
+// IBAction for deleting an item. |sender| is expected to be the "Remove"
+// button. The deletion acts on the selected item in either the address or
+// credit card list.
+- (IBAction)deleteSelection:(id)sender;
-// IBAction for sender to alert dialog that an address label has changed.
-- (IBAction)notifyAddressChange:(id)sender;
+// IBActions for editing an item. |sender| is expected to be the "Edit..."
+// button. The editing acts on the selected item in either the address or
+// credit card list.
+- (IBAction)editSelection:(id)sender;
-// Returns an array of labels representing the addresses in the
-// |addressFormViewControllers_|.
-- (NSArray*)addressLabels;
+// NSTableView data source methods.
+- (id)tableView:(NSTableView *)tableView
+ objectValueForTableColumn:(NSTableColumn *)tableColumn
+ row:(NSInteger)rowIndex;
-// Returns an array of labels representing the credit cards in the
-// |creditCardFormViewControllers_|.
-- (NSArray*)creditCardLabels;
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView;
+
+// Returns an array of labels representing the addresses in the |profiles_|.
+- (NSArray*)addressLabels;
@end
@@ -119,9 +149,11 @@ class Profile;
profile:(Profile*)profile
importedProfile:(AutoFillProfile*)importedProfile
importedCreditCard:(CreditCard*)importedCreditCard;
-- (NSMutableArray*)addressFormViewControllers;
-- (NSMutableArray*)creditCardFormViewControllers;
- (void)closeDialog;
+- (AutoFillAddressSheetController*)addressSheetController;
+- (AutoFillCreditCardSheetController*)creditCardSheetController;
+- (void)selectAddressAtIndex:(size_t)i;
+- (void)selectCreditCardAtIndex:(size_t)i;
@end
#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_DIALOG_CONTROLLER_MAC_
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
diff --git a/chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm b/chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm
index b82c377..07c7af0 100644
--- a/chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm
+++ b/chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm
@@ -4,9 +4,9 @@
#include "base/ref_counted.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/autofill_dialog_controller_mac.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/personal_data_manager.h"
@@ -240,11 +240,11 @@ TEST_F(AutoFillDialogControllerTest, NoEditsGiveBackOriginalCreditCard) {
TEST_F(AutoFillDialogControllerTest, AutoFillDataMutation) {
AutoFillProfile profile(ASCIIToUTF16("Home"), 17);
- profile.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("David"));
+ profile.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("John"));
profile.SetInfo(AutoFillType(NAME_MIDDLE), ASCIIToUTF16("C"));
- profile.SetInfo(AutoFillType(NAME_LAST), ASCIIToUTF16("Holloway"));
+ profile.SetInfo(AutoFillType(NAME_LAST), ASCIIToUTF16("Smith"));
profile.SetInfo(AutoFillType(EMAIL_ADDRESS),
- ASCIIToUTF16("dhollowa@chromium.org"));
+ ASCIIToUTF16("john@chromium.org"));
profile.SetInfo(AutoFillType(COMPANY_NAME), ASCIIToUTF16("Google Inc."));
profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE1),
ASCIIToUTF16("1122 Mountain View Road"));
@@ -261,14 +261,15 @@ TEST_F(AutoFillDialogControllerTest, AutoFillDataMutation) {
profiles().push_back(&profile);
LoadDialog();
+ [controller_ selectAddressAtIndex:0];
+ [controller_ editSelection:nil];
- AutoFillAddressModel* am = [[[controller_ addressFormViewControllers]
- objectAtIndex:0] addressModel];
+ AutoFillAddressSheetController* sheet = [controller_ addressSheetController];
+ ASSERT_TRUE(sheet != nil);
+ AutoFillAddressModel* am = [sheet addressModel];
EXPECT_TRUE([[am label] isEqualToString:@"Home"]);
- EXPECT_TRUE([[am firstName] isEqualToString:@"David"]);
- EXPECT_TRUE([[am middleName] isEqualToString:@"C"]);
- EXPECT_TRUE([[am lastName] isEqualToString:@"Holloway"]);
- EXPECT_TRUE([[am email] isEqualToString:@"dhollowa@chromium.org"]);
+ EXPECT_TRUE([[am fullName] isEqualToString:@"John C Smith"]);
+ EXPECT_TRUE([[am email] isEqualToString:@"john@chromium.org"]);
EXPECT_TRUE([[am companyName] isEqualToString:@"Google Inc."]);
EXPECT_TRUE([[am addressLine1] isEqualToString:@"1122 Mountain View Road"]);
EXPECT_TRUE([[am addressLine2] isEqualToString:@"Suite #1"]);
@@ -278,6 +279,7 @@ TEST_F(AutoFillDialogControllerTest, AutoFillDataMutation) {
EXPECT_TRUE([[am phoneWholeNumber] isEqualToString:@"014155552258"]);
EXPECT_TRUE([[am faxWholeNumber] isEqualToString:@"024087172258"]);
+ [sheet save:nil];
[controller_ save:nil];
ASSERT_TRUE(observer_.hit_);
@@ -300,9 +302,13 @@ TEST_F(AutoFillDialogControllerTest, CreditCardDataMutation) {
credit_cards().push_back(&credit_card);
LoadDialog();
+ [controller_ selectCreditCardAtIndex:0];
+ [controller_ editSelection:nil];
- AutoFillCreditCardModel* cm = [[[controller_ creditCardFormViewControllers]
- objectAtIndex:0] creditCardModel];
+ AutoFillCreditCardSheetController* sheet =
+ [controller_ creditCardSheetController];
+ ASSERT_TRUE(sheet != nil);
+ AutoFillCreditCardModel* cm = [sheet creditCardModel];
EXPECT_TRUE([[cm label] isEqualToString:@"myCC"]);
EXPECT_TRUE([[cm nameOnCard] isEqualToString:@"DCH"]);
EXPECT_TRUE([[cm creditCardNumber] isEqualToString:@"1234 5678 9101 1121"]);
@@ -310,6 +316,7 @@ TEST_F(AutoFillDialogControllerTest, CreditCardDataMutation) {
EXPECT_TRUE([[cm expirationYear] isEqualToString:@"2012"]);
EXPECT_TRUE([[cm cvcCode] isEqualToString:@"222"]);
+ [sheet save:nil];
[controller_ save:nil];
ASSERT_TRUE(observer_.hit_);
@@ -373,6 +380,9 @@ TEST_F(AutoFillDialogControllerTest, AddNewProfile) {
profiles().push_back(&profile);
LoadDialog();
[controller_ addNewAddress:nil];
+ AutoFillAddressSheetController* sheet = [controller_ addressSheetController];
+ ASSERT_TRUE(sheet != nil);
+ [sheet save:nil];
[controller_ save:nil];
// Should hit our observer.
@@ -393,6 +403,10 @@ TEST_F(AutoFillDialogControllerTest, AddNewCreditCard) {
credit_cards().push_back(&credit_card);
LoadDialog();
[controller_ addNewCreditCard:nil];
+ AutoFillCreditCardSheetController* sheet =
+ [controller_ creditCardSheetController];
+ ASSERT_TRUE(sheet != nil);
+ [sheet save:nil];
[controller_ save:nil];
// Should hit our observer.
@@ -412,10 +426,8 @@ TEST_F(AutoFillDialogControllerTest, DeleteProfile) {
profile.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Joe"));
profiles().push_back(&profile);
LoadDialog();
- EXPECT_EQ([[[controller_ addressFormViewControllers] lastObject]
- retainCount], 1UL);
- [controller_ deleteAddress:[[controller_ addressFormViewControllers]
- lastObject]];
+ [controller_ selectAddressAtIndex:0];
+ [controller_ deleteSelection:nil];
[controller_ save:nil];
// Should hit our observer.
@@ -431,10 +443,8 @@ TEST_F(AutoFillDialogControllerTest, DeleteCreditCard) {
credit_card.SetInfo(AutoFillType(CREDIT_CARD_NAME), ASCIIToUTF16("Joe"));
credit_cards().push_back(&credit_card);
LoadDialog();
- EXPECT_EQ([[[controller_ creditCardFormViewControllers] lastObject]
- retainCount], 1UL);
- [controller_ deleteCreditCard:[[controller_ creditCardFormViewControllers]
- lastObject]];
+ [controller_ selectCreditCardAtIndex:0];
+ [controller_ deleteSelection:nil];
[controller_ save:nil];
// Should hit our observer.
@@ -453,8 +463,8 @@ TEST_F(AutoFillDialogControllerTest, TwoProfilesDeleteOne) {
profile2.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Bob"));
profiles().push_back(&profile2);
LoadDialog();
- [controller_ deleteAddress:[[controller_ addressFormViewControllers]
- lastObject]];
+ [controller_ selectAddressAtIndex:1];
+ [controller_ deleteSelection:nil];
[controller_ save:nil];
// Should hit our observer.
@@ -477,8 +487,8 @@ TEST_F(AutoFillDialogControllerTest, TwoCreditCardsDeleteOne) {
credit_card2.SetInfo(AutoFillType(CREDIT_CARD_NAME), ASCIIToUTF16("Bob"));
credit_cards().push_back(&credit_card2);
LoadDialog();
- [controller_ deleteCreditCard:[[controller_ creditCardFormViewControllers]
- lastObject]];
+ [controller_ selectCreditCardAtIndex:1];
+ [controller_ deleteSelection:nil];
[controller_ save:nil];
// Should hit our observer.
diff --git a/chrome/browser/autofill/contact_info.cc b/chrome/browser/autofill/contact_info.cc
index 0355fd0..3c77cda 100644
--- a/chrome/browser/autofill/contact_info.cc
+++ b/chrome/browser/autofill/contact_info.cc
@@ -112,7 +112,27 @@ void ContactInfo::SetInfo(const AutoFillType& type, const string16& value) {
SetLast(value);
else if (field_type == NAME_SUFFIX)
set_suffix(value);
- else if (field_type == EMAIL_ADDRESS)
+ else if (field_type == NAME_FULL) {
+ // TODO(dhollowa): This needs formal spec on how names are split from
+ // unstructured string to structured fields.
+ std::vector<string16> values;
+ SplitStringAlongWhitespace(value, &values);
+ if (values.size() == 1) {
+ SetInfo(AutoFillType(NAME_FIRST), values[0]);
+ } else if (values.size() == 2) {
+ SetInfo(AutoFillType(NAME_FIRST), values[0]);
+ SetInfo(AutoFillType(NAME_LAST), values[1]);
+ } else if (values.size() == 3) {
+ SetInfo(AutoFillType(NAME_FIRST), values[0]);
+ SetInfo(AutoFillType(NAME_MIDDLE), values[1]);
+ SetInfo(AutoFillType(NAME_LAST), values[2]);
+ } else if (values.size() >= 4) {
+ SetInfo(AutoFillType(NAME_FIRST), values[0]);
+ SetInfo(AutoFillType(NAME_MIDDLE), values[1]);
+ SetInfo(AutoFillType(NAME_LAST), values[2]);
+ SetInfo(AutoFillType(NAME_SUFFIX), values[3]);
+ }
+ } else if (field_type == EMAIL_ADDRESS)
email_ = value;
else if (field_type == COMPANY_NAME)
company_name_ = value;