| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/autofill/autofill_dialog_controller_mac.h" | 5 #import "chrome/browser/autofill/autofill_dialog_controller_mac.h" |
| 6 #include "app/l10n_util.h" | 6 #include "app/l10n_util.h" |
| 7 #include "app/resource_bundle.h" |
| 7 #include "base/mac_util.h" | 8 #include "base/mac_util.h" |
| 8 #include "base/sys_string_conversions.h" | 9 #include "base/sys_string_conversions.h" |
| 9 #import "chrome/browser/autofill/autofill_address_model_mac.h" | 10 #import "chrome/browser/autofill/autofill_address_model_mac.h" |
| 10 #import "chrome/browser/autofill/autofill_address_view_controller_mac.h" | 11 #import "chrome/browser/autofill/autofill_address_sheet_controller_mac.h" |
| 11 #import "chrome/browser/autofill/autofill_credit_card_model_mac.h" | 12 #import "chrome/browser/autofill/autofill_credit_card_model_mac.h" |
| 12 #import "chrome/browser/autofill/autofill_credit_card_view_controller_mac.h" | 13 #import "chrome/browser/autofill/autofill_credit_card_sheet_controller_mac.h" |
| 13 #import "chrome/browser/autofill/personal_data_manager.h" | 14 #import "chrome/browser/autofill/personal_data_manager.h" |
| 14 #include "chrome/browser/browser_process.h" | 15 #include "chrome/browser/browser_process.h" |
| 15 #import "chrome/browser/cocoa/disclosure_view_controller.h" | |
| 16 #import "chrome/browser/cocoa/section_separator_view.h" | |
| 17 #import "chrome/browser/cocoa/window_size_autosaver.h" | 16 #import "chrome/browser/cocoa/window_size_autosaver.h" |
| 18 #include "chrome/browser/pref_service.h" | 17 #include "chrome/browser/pref_service.h" |
| 19 #include "chrome/browser/profile.h" | 18 #include "chrome/browser/profile.h" |
| 20 #include "chrome/common/pref_names.h" | 19 #include "chrome/common/pref_names.h" |
| 21 #include "grit/generated_resources.h" | 20 #include "grit/generated_resources.h" |
| 21 #include "grit/theme_resources.h" |
| 22 |
| 23 // Delegate protocol that needs to be in place for the AutoFillTableView's |
| 24 // handling of delete and backspace keys. |
| 25 @protocol DeleteKeyDelegate |
| 26 - (IBAction)deleteSelection:(id)sender; |
| 27 @end |
| 28 |
| 29 // A subclass of NSTableView that allows for deleting selected elements using |
| 30 // the delete or backspace keys. |
| 31 @interface AutoFillTableView : NSTableView { |
| 32 } |
| 33 @end |
| 34 |
| 35 @implementation AutoFillTableView |
| 36 |
| 37 // We override the keyDown method to dispatch the |deleteSelection:| action |
| 38 // when the user presses the delete or backspace keys. Note a delegate must |
| 39 // be present that conforms to the DeleteKeyDelegate protocol. |
| 40 - (void)keyDown:(NSEvent *)event { |
| 41 id object = [self delegate]; |
| 42 unichar c = [[event characters] characterAtIndex: 0]; |
| 43 |
| 44 // If the user pressed delete and the delegate supports deleteSelection: |
| 45 if ((c == NSDeleteFunctionKey || |
| 46 c == NSDeleteCharFunctionKey || |
| 47 c == NSDeleteCharacter) && |
| 48 [object respondsToSelector:@selector(deleteSelection:)]) { |
| 49 id <DeleteKeyDelegate> delegate = (id <DeleteKeyDelegate>) object; |
| 50 |
| 51 [delegate deleteSelection:self]; |
| 52 } else { |
| 53 [super keyDown:event]; |
| 54 } |
| 55 } |
| 56 |
| 57 @end |
| 22 | 58 |
| 23 // Private interface. | 59 // Private interface. |
| 24 @interface AutoFillDialogController (PrivateAPI) | 60 @interface AutoFillDialogController (PrivateMethods) |
| 25 // Asyncronous handler for when PersonalDataManager data loads. The | 61 // Asyncronous handler for when PersonalDataManager data loads. The |
| 26 // personal data manager notifies the dialog with this method when the | 62 // personal data manager notifies the dialog with this method when the |
| 27 // data loading is complete and ready to be used. | 63 // data loading is complete and ready to be used. |
| 28 - (void)onPersonalDataLoaded:(const std::vector<AutoFillProfile*>&)profiles | 64 - (void)onPersonalDataLoaded:(const std::vector<AutoFillProfile*>&)profiles |
| 29 creditCards:(const std::vector<CreditCard*>&)creditCards; | 65 creditCards:(const std::vector<CreditCard*>&)creditCards; |
| 66 |
| 67 // Returns true if |row| is an index to a valid profile in |tableView_|, and |
| 68 // false otherwise. |
| 69 - (BOOL)isProfileRow:(NSInteger)row; |
| 70 |
| 71 // Returns true if |row| is an index to the profile group row in |tableView_|, |
| 72 // and false otherwise. |
| 73 - (BOOL)isProfileGroupRow:(NSInteger)row; |
| 74 |
| 75 // Returns true if |row| is an index to a valid credit card in |tableView_|, and |
| 76 // false otherwise. |
| 77 - (BOOL)isCreditCardRow:(NSInteger)row; |
| 78 |
| 79 // Returns true if |row| is the index to the credit card group row in |
| 80 // |tableView_|, and false otherwise. |
| 81 - (BOOL)isCreditCardGroupRow:(NSInteger)row; |
| 82 |
| 83 // Returns the index to |profiles_| of the corresponding |row| in |tableView_|. |
| 84 - (size_t)profileIndexFromRow:(NSInteger)row; |
| 85 |
| 86 // Returns the index to |creditCards_| of the corresponding |row| in |
| 87 // |tableView_|. |
| 88 - (size_t)creditCardIndexFromRow:(NSInteger)row; |
| 89 |
| 90 // Returns the |row| in |tableView_| that corresponds to the index |i| into |
| 91 // |profiles_|. |
| 92 - (NSInteger)rowFromProfileIndex:(size_t)i; |
| 93 |
| 94 // Returns the |row| in |tableView_| that corresponds to the index |i| into |
| 95 // |creditCards_|. |
| 96 - (NSInteger)rowFromCreditCardIndex:(size_t)row; |
| 97 |
| 98 // Invokes the modal dialog. |
| 99 - (void)runModalDialog; |
| 100 |
| 30 @end | 101 @end |
| 31 | 102 |
| 32 namespace AutoFillDialogControllerInternal { | 103 namespace AutoFillDialogControllerInternal { |
| 33 | 104 |
| 34 // PersonalDataManagerObserver facilitates asynchronous loading of | 105 // PersonalDataManagerObserver facilitates asynchronous loading of |
| 35 // PersonalDataManager data before showing the AutoFill settings data to the | 106 // PersonalDataManager data before showing the AutoFill settings data to the |
| 36 // user. It acts as a C++-based delegate for the |AutoFillDialogController|. | 107 // user. It acts as a C++-based delegate for the |AutoFillDialogController|. |
| 37 class PersonalDataManagerObserver : public PersonalDataManager::Observer { | 108 class PersonalDataManagerObserver : public PersonalDataManager::Observer { |
| 38 public: | 109 public: |
| 39 explicit PersonalDataManagerObserver( | 110 explicit PersonalDataManagerObserver( |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 // The data is ready so display our data. Notify the dialog controller that | 158 // The data is ready so display our data. Notify the dialog controller that |
| 88 // the data is ready. Once done we clear the observer. | 159 // the data is ready. Once done we clear the observer. |
| 89 void PersonalDataManagerObserver::OnPersonalDataLoaded() { | 160 void PersonalDataManagerObserver::OnPersonalDataLoaded() { |
| 90 RemoveObserver(); | 161 RemoveObserver(); |
| 91 [controller_ onPersonalDataLoaded:personal_data_manager_->web_profiles() | 162 [controller_ onPersonalDataLoaded:personal_data_manager_->web_profiles() |
| 92 creditCards:personal_data_manager_->credit_cards()]; | 163 creditCards:personal_data_manager_->credit_cards()]; |
| 93 } | 164 } |
| 94 | 165 |
| 95 } // namespace AutoFillDialogControllerInternal | 166 } // namespace AutoFillDialogControllerInternal |
| 96 | 167 |
| 97 @interface AutoFillDialogController (PrivateMethods) | |
| 98 - (void)runModalDialog; | |
| 99 - (void)installChildViews; | |
| 100 @end | |
| 101 | |
| 102 @implementation AutoFillDialogController | 168 @implementation AutoFillDialogController |
| 103 | 169 |
| 104 @synthesize auxiliaryEnabled = auxiliaryEnabled_; | 170 @synthesize auxiliaryEnabled = auxiliaryEnabled_; |
| 171 @synthesize itemIsSelected = itemIsSelected_; |
| 105 | 172 |
| 106 + (void)showAutoFillDialogWithObserver:(AutoFillDialogObserver*)observer | 173 + (void)showAutoFillDialogWithObserver:(AutoFillDialogObserver*)observer |
| 107 profile:(Profile*)profile | 174 profile:(Profile*)profile |
| 108 importedProfile:(AutoFillProfile*) importedProfile | 175 importedProfile:(AutoFillProfile*) importedProfile |
| 109 importedCreditCard:(CreditCard*) importedCreditCard { | 176 importedCreditCard:(CreditCard*) importedCreditCard { |
| 110 AutoFillDialogController* controller = | 177 AutoFillDialogController* controller = |
| 111 [AutoFillDialogController controllerWithObserver:observer | 178 [AutoFillDialogController controllerWithObserver:observer |
| 112 profile:profile | 179 profile:profile |
| 113 importedProfile:importedProfile | 180 importedProfile:importedProfile |
| 114 importedCreditCard:importedCreditCard]; | 181 importedCreditCard:importedCreditCard]; |
| 115 | 182 |
| 116 // Only run modal dialog if it is not already being shown. | 183 // Only run modal dialog if it is not already being shown. |
| 117 if (![controller isWindowLoaded]) { | 184 if (![controller isWindowLoaded]) { |
| 118 [controller runModalDialog]; | 185 [controller runModalDialog]; |
| 119 } | 186 } |
| 120 } | 187 } |
| 121 | 188 |
| 122 - (void)awakeFromNib { | 189 - (void)awakeFromNib { |
| 123 [addressSectionBox_ setShowTopLine:FALSE]; | |
| 124 | |
| 125 PersonalDataManager* personal_data_manager = | 190 PersonalDataManager* personal_data_manager = |
| 126 profile_->GetPersonalDataManager(); | 191 profile_->GetPersonalDataManager(); |
| 127 DCHECK(personal_data_manager); | 192 DCHECK(personal_data_manager); |
| 128 | 193 |
| 129 if (personal_data_manager->IsDataLoaded()) { | 194 if (personal_data_manager->IsDataLoaded()) { |
| 130 // |personalDataManager| data is loaded, we can proceed with the contents. | 195 // |personalDataManager| data is loaded, we can proceed with the contents. |
| 131 [self onPersonalDataLoaded:personal_data_manager->web_profiles() | 196 [self onPersonalDataLoaded:personal_data_manager->web_profiles() |
| 132 creditCards:personal_data_manager->credit_cards()]; | 197 creditCards:personal_data_manager->credit_cards()]; |
| 133 } else { | 198 } else { |
| 134 // |personalDataManager| data is NOT loaded, so we load it here, installing | 199 // |personalDataManager| data is NOT loaded, so we load it here, installing |
| 135 // our observer. | 200 // our observer. |
| 136 personalDataManagerObserver_.reset( | 201 personalDataManagerObserver_.reset( |
| 137 new AutoFillDialogControllerInternal::PersonalDataManagerObserver( | 202 new AutoFillDialogControllerInternal::PersonalDataManagerObserver( |
| 138 self, personal_data_manager, profile_)); | 203 self, personal_data_manager, profile_)); |
| 139 personal_data_manager->SetObserver(personalDataManagerObserver_.get()); | 204 personal_data_manager->SetObserver(personalDataManagerObserver_.get()); |
| 140 } | 205 } |
| 206 |
| 207 // Explicitly load the data in the table before window displays to avoid |
| 208 // nasty flicker as tables update. |
| 209 [tableView_ reloadData]; |
| 210 |
| 211 // Set up edit when double-clicking on a table row. |
| 212 [tableView_ setDoubleAction:@selector(editSelection:)]; |
| 141 } | 213 } |
| 142 | 214 |
| 143 // NSWindow Delegate callback. When the window closes the controller can | 215 // NSWindow Delegate callback. When the window closes the controller can |
| 144 // be released. | 216 // be released. |
| 145 - (void)windowWillClose:(NSNotification *)notification { | 217 - (void)windowWillClose:(NSNotification *)notification { |
| 146 // Force views to go away so they properly remove their observations. | 218 [tableView_ setDataSource:nil]; |
| 147 addressFormViewControllers_.reset(); | 219 [tableView_ setDelegate:nil]; |
| 148 creditCardFormViewControllers_.reset(); | |
| 149 [self autorelease]; | 220 [self autorelease]; |
| 150 } | 221 } |
| 151 | 222 |
| 152 // Called when the user clicks the save button. | 223 // Called when the user clicks the save button. |
| 153 - (IBAction)save:(id)sender { | 224 - (IBAction)save:(id)sender { |
| 154 // Call |makeFirstResponder:| to commit pending text field edits. | |
| 155 [[self window] makeFirstResponder:[self window]]; | |
| 156 | |
| 157 // If we have an |observer_| then communicate the changes back. | 225 // If we have an |observer_| then communicate the changes back. |
| 158 if (observer_) { | 226 if (observer_) { |
| 159 profiles_.clear(); | |
| 160 profiles_.resize([addressFormViewControllers_ count]); | |
| 161 int i = 0; | |
| 162 for (AutoFillAddressViewController* addressFormViewController in | |
| 163 addressFormViewControllers_.get()) { | |
| 164 // Initialize the profile here. The default initializer does not fully | |
| 165 // initialize. | |
| 166 profiles_[i] = AutoFillProfile(ASCIIToUTF16(""), 0); | |
| 167 [addressFormViewController copyModelToProfile:&profiles_[i]]; | |
| 168 i++; | |
| 169 } | |
| 170 creditCards_.clear(); | |
| 171 creditCards_.resize([creditCardFormViewControllers_ count]); | |
| 172 int j = 0; | |
| 173 for (AutoFillCreditCardViewController* creditCardFormViewController in | |
| 174 creditCardFormViewControllers_.get()) { | |
| 175 // Initialize the credit card here. The default initializer does not | |
| 176 // fully initialize. | |
| 177 creditCards_[j] = CreditCard(ASCIIToUTF16(""), 0); | |
| 178 [creditCardFormViewController copyModelToCreditCard:&creditCards_[j]]; | |
| 179 j++; | |
| 180 } | |
| 181 profile_->GetPrefs()->SetBoolean(prefs::kAutoFillAuxiliaryProfilesEnabled, | 227 profile_->GetPrefs()->SetBoolean(prefs::kAutoFillAuxiliaryProfilesEnabled, |
| 182 auxiliaryEnabled_); | 228 auxiliaryEnabled_); |
| 183 observer_->OnAutoFillDialogApply(&profiles_, &creditCards_); | 229 observer_->OnAutoFillDialogApply(&profiles_, &creditCards_); |
| 184 } | 230 } |
| 185 [self closeDialog]; | 231 [self closeDialog]; |
| 186 } | 232 } |
| 187 | 233 |
| 188 // Called when the user clicks the cancel button. All we need to do is stop | 234 // Called when the user clicks the cancel button. All we need to do is stop |
| 189 // the modal session. | 235 // the modal session. |
| 190 - (IBAction)cancel:(id)sender { | 236 - (IBAction)cancel:(id)sender { |
| 191 [self closeDialog]; | 237 [self closeDialog]; |
| 192 } | 238 } |
| 193 | 239 |
| 194 // Adds new address to bottom of list. A new address controller is created | 240 // Invokes the "Add" sheet for address information. If user saves then the new |
| 195 // and its view is inserted into the view hierarchy. | 241 // information is added to |profiles_| in |addressAddDidEnd:| method. |
| 196 - (IBAction)addNewAddress:(id)sender { | 242 - (IBAction)addNewAddress:(id)sender { |
| 197 // Insert relative to top of section, or below last address. | 243 DCHECK(!addressSheetController.get()); |
| 198 NSView* insertionPoint; | 244 |
| 199 NSUInteger count = [addressFormViewControllers_.get() count]; | 245 // Create a new default address. |
| 200 if (count == 0) { | 246 string16 newName = l10n_util::GetStringUTF16(IDS_AUTOFILL_NEW_ADDRESS); |
| 201 insertionPoint = addressSection_; | 247 AutoFillProfile newAddress(newName, 0); |
| 202 } else { | 248 |
| 203 insertionPoint = [[addressFormViewControllers_.get() | 249 // Create a new address sheet controller in "Add" mode. |
| 204 objectAtIndex:[addressFormViewControllers_.get() count] - 1] view]; | 250 addressSheetController.reset( |
| 205 } | 251 [[AutoFillAddressSheetController alloc] |
| 206 | 252 initWithProfile:newAddress |
| 207 // Create a new default address, and add it to our array of controllers. | 253 mode:kAutoFillAddressAddMode]); |
| 208 string16 new_address_name = l10n_util::GetStringUTF16( | 254 |
| 209 IDS_AUTOFILL_NEW_ADDRESS); | 255 // Show the sheet. |
| 210 AutoFillProfile newProfile(new_address_name, 0); | 256 [NSApp beginSheet:[addressSheetController window] |
| 211 scoped_nsobject<AutoFillAddressViewController> addressViewController( | 257 modalForWindow:[self window] |
| 212 [[AutoFillAddressViewController alloc] | 258 modalDelegate:self |
| 213 initWithProfile:newProfile | 259 didEndSelector:@selector(addressAddDidEnd:returnCode:contextInfo:) |
| 214 disclosure:NSOnState | 260 contextInfo:NULL]; |
| 215 controller:self]); | 261 } |
| 216 [self willChangeValueForKey:@"addressLabels"]; | 262 |
| 217 [addressFormViewControllers_.get() addObject:addressViewController]; | 263 // Invokes the "Add" sheet for credit card information. If user saves then the |
| 218 [self didChangeValueForKey:@"addressLabels"]; | 264 // new information is added to |creditCards_| in |creditCardAddDidEnd:| method. |
| 219 | |
| 220 // Embed the new address into our target view. | |
| 221 [childView_ addSubview:[addressViewController view] | |
| 222 positioned:NSWindowBelow relativeTo:insertionPoint]; | |
| 223 [[addressViewController view] setFrameOrigin:NSMakePoint(0, 0)]; | |
| 224 | |
| 225 [self notifyAddressChange:self]; | |
| 226 | |
| 227 // Recalculate key view loop to account for change in view tree. | |
| 228 [[self window] recalculateKeyViewLoop]; | |
| 229 } | |
| 230 | |
| 231 // Adds new credit card to bottom of list. A new credit card controller is | |
| 232 // created and its view is inserted into the view hierarchy. | |
| 233 - (IBAction)addNewCreditCard:(id)sender { | 265 - (IBAction)addNewCreditCard:(id)sender { |
| 234 // Insert relative to top of section, or below last address. | 266 DCHECK(!creditCardSheetController.get()); |
| 235 NSView* insertionPoint; | 267 |
| 236 NSUInteger count = [creditCardFormViewControllers_.get() count]; | 268 // Create a new default credit card. |
| 237 if (count == 0) { | 269 string16 newName = l10n_util::GetStringUTF16(IDS_AUTOFILL_NEW_CREDITCARD); |
| 238 insertionPoint = creditCardSection_; | 270 CreditCard newCreditCard(newName, 0); |
| 239 } else { | 271 |
| 240 insertionPoint = [[creditCardFormViewControllers_.get() | 272 // Create a new address sheet controller in "Add" mode. |
| 241 objectAtIndex:[creditCardFormViewControllers_.get() count] - 1] view]; | 273 creditCardSheetController.reset( |
| 242 } | 274 [[AutoFillCreditCardSheetController alloc] |
| 243 | |
| 244 // Create a new default credit card, and add it to our array of controllers. | |
| 245 string16 new_credit_card_name = l10n_util::GetStringUTF16( | |
| 246 IDS_AUTOFILL_NEW_CREDITCARD); | |
| 247 CreditCard newCreditCard(new_credit_card_name, 0); | |
| 248 scoped_nsobject<AutoFillCreditCardViewController> creditCardViewController( | |
| 249 [[AutoFillCreditCardViewController alloc] | |
| 250 initWithCreditCard:newCreditCard | 275 initWithCreditCard:newCreditCard |
| 251 disclosure:NSOnState | 276 mode:kAutoFillCreditCardAddMode |
| 252 controller:self]); | 277 controller:self]); |
| 253 [self willChangeValueForKey:@"creditCardLabels"]; | 278 |
| 254 [creditCardFormViewControllers_.get() addObject:creditCardViewController]; | 279 // Show the sheet. |
| 255 [self didChangeValueForKey:@"creditCardLabels"]; | 280 [NSApp beginSheet:[creditCardSheetController window] |
| 256 | 281 modalForWindow:[self window] |
| 257 // Embed the new address into our target view. | 282 modalDelegate:self |
| 258 [childView_ addSubview:[creditCardViewController view] | 283 didEndSelector:@selector(creditCardAddDidEnd:returnCode:contextInfo:) |
| 259 positioned:NSWindowBelow relativeTo:insertionPoint]; | 284 contextInfo:NULL]; |
| 260 [[creditCardViewController view] setFrameOrigin:NSMakePoint(0, 0)]; | 285 } |
| 261 | 286 |
| 262 // Recalculate key view loop to account for change in view tree. | 287 // Add address sheet was dismissed. Non-zero |returnCode| indicates a save. |
| 263 [[self window] recalculateKeyViewLoop]; | 288 - (void)addressAddDidEnd:(NSWindow*)sheet |
| 264 } | 289 returnCode:(int)returnCode |
| 265 | 290 contextInfo:(void*)contextInfo { |
| 266 - (IBAction)deleteAddress:(id)sender { | 291 DCHECK(contextInfo == NULL); |
| 267 NSUInteger i = [addressFormViewControllers_.get() indexOfObject:sender]; | 292 |
| 268 DCHECK(i != NSNotFound); | 293 if (returnCode) { |
| 269 | 294 // Create a new address and save it to the |profiles_| list. |
| 270 // Remove controller's view from superview and remove from list of | 295 AutoFillProfile newAddress(string16(), 0); |
| 271 // controllers. Note on lifetime: removing view from super view decrements | 296 [addressSheetController copyModelToProfile:&newAddress]; |
| 272 // refcount of view, removing controller from array decrements refcount of | 297 profiles_.push_back(newAddress); |
| 273 // controller which in-turn decrement refcount of view. Both should dealloc | 298 |
| 274 // at this point. | 299 // Refresh the view based on new data. |
| 275 [[sender view] removeFromSuperview]; | 300 [tableView_ reloadData]; |
| 276 [self willChangeValueForKey:@"addressLabels"]; | 301 |
| 277 [addressFormViewControllers_.get() removeObjectAtIndex:i]; | 302 // Update the selection to the newly added item. |
| 278 [self didChangeValueForKey:@"addressLabels"]; | 303 NSInteger row = [self rowFromProfileIndex:profiles_.size() - 1]; |
| 279 | 304 [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:row] |
| 280 [self notifyAddressChange:self]; | 305 byExtendingSelection:NO]; |
| 281 | 306 } |
| 282 // Recalculate key view loop to account for change in view tree. | 307 [sheet orderOut:self]; |
| 283 [[self window] recalculateKeyViewLoop]; | 308 addressSheetController.reset(nil); |
| 284 } | 309 } |
| 285 | 310 |
| 286 - (IBAction)deleteCreditCard:(id)sender { | 311 // Add credit card sheet was dismissed. Non-zero |returnCode| indicates a save. |
| 287 NSUInteger i = [creditCardFormViewControllers_.get() indexOfObject:sender]; | 312 - (void)creditCardAddDidEnd:(NSWindow *)sheet |
| 288 DCHECK(i != NSNotFound); | 313 returnCode:(int)returnCode |
| 289 | 314 contextInfo:(void *)contextInfo { |
| 290 // Remove controller's view from superview and remove from list of | 315 DCHECK(contextInfo == NULL); |
| 291 // controllers. Note on lifetime: removing view from super view decrements | 316 |
| 292 // refcount of view, removing controller from array decrements refcount of | 317 if (returnCode) { |
| 293 // controller which in-turn decrement refcount of view. Both should dealloc | 318 // Create a new credit card and save it to the |creditCards_| list. |
| 294 // at this point. | 319 CreditCard newCreditCard(string16(), 0); |
| 295 [[sender view] removeFromSuperview]; | 320 [creditCardSheetController copyModelToCreditCard:&newCreditCard]; |
| 296 [self willChangeValueForKey:@"creditCardLabels"]; | 321 creditCards_.push_back(newCreditCard); |
| 297 [creditCardFormViewControllers_.get() removeObjectAtIndex:i]; | 322 |
| 298 [self didChangeValueForKey:@"creditCardLabels"]; | 323 // Refresh the view based on new data. |
| 299 | 324 [tableView_ reloadData]; |
| 300 // Recalculate key view loop to account for change in view tree. | 325 |
| 301 [[self window] recalculateKeyViewLoop]; | 326 // Update the selection to the newly added item. |
| 302 } | 327 NSInteger row = [self rowFromCreditCardIndex:creditCards_.size() - 1]; |
| 303 | 328 [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:row] |
| 304 // Credit card controllers are dependent upon the address labels. So we notify | 329 byExtendingSelection:NO]; |
| 305 // them here that something has changed. | 330 } |
| 306 - (IBAction)notifyAddressChange:(id)sender { | 331 [sheet orderOut:self]; |
| 307 for (AutoFillCreditCardViewController* creditCardFormViewController in | 332 creditCardSheetController.reset(nil); |
| 308 creditCardFormViewControllers_.get()) { | 333 } |
| 309 [creditCardFormViewController onAddressesChanged:self]; | 334 |
| 310 } | 335 // Deletes selected item, either address or credit card depending on the item |
| 336 // selected. |
| 337 - (IBAction)deleteSelection:(id)sender { |
| 338 NSInteger selectedRow = [tableView_ selectedRow]; |
| 339 if ([self isProfileRow:selectedRow]) { |
| 340 profiles_.erase(profiles_.begin() + [self profileIndexFromRow:selectedRow]); |
| 341 |
| 342 // Select the previous row if possible, else current row, else deselect all. |
| 343 if ([self tableView:tableView_ shouldSelectRow:selectedRow-1]) { |
| 344 [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow-1] |
| 345 byExtendingSelection:NO]; |
| 346 } else if ([self tableView:tableView_ shouldSelectRow:selectedRow]) { |
| 347 [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow] |
| 348 byExtendingSelection:NO]; |
| 349 } else { |
| 350 [tableView_ selectRowIndexes:[NSIndexSet indexSet] |
| 351 byExtendingSelection:NO]; |
| 352 } |
| 353 [tableView_ reloadData]; |
| 354 } else if ([self isCreditCardRow:selectedRow]) { |
| 355 creditCards_.erase( |
| 356 creditCards_.begin() + [self creditCardIndexFromRow:selectedRow]); |
| 357 |
| 358 // Select the previous row if possible, else current row, else deselect all. |
| 359 if ([self tableView:tableView_ shouldSelectRow:selectedRow-1]) { |
| 360 [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow-1] |
| 361 byExtendingSelection:NO]; |
| 362 } else if ([self tableView:tableView_ shouldSelectRow:selectedRow]) { |
| 363 [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow] |
| 364 byExtendingSelection:NO]; |
| 365 } else { |
| 366 [tableView_ selectRowIndexes:[NSIndexSet indexSet] |
| 367 byExtendingSelection:NO]; |
| 368 } |
| 369 [tableView_ reloadData]; |
| 370 } |
| 371 } |
| 372 |
| 373 // Edits the selected item, either address or credit card depending on the item |
| 374 // selected. |
| 375 - (IBAction)editSelection:(id)sender { |
| 376 NSInteger selectedRow = [tableView_ selectedRow]; |
| 377 if ([self isProfileRow:selectedRow]) { |
| 378 if (!addressSheetController.get()) { |
| 379 int i = [self profileIndexFromRow:selectedRow]; |
| 380 |
| 381 // Create a new address sheet controller in "Edit" mode. |
| 382 addressSheetController.reset( |
| 383 [[AutoFillAddressSheetController alloc] |
| 384 initWithProfile:profiles_[i] |
| 385 mode:kAutoFillAddressEditMode]); |
| 386 |
| 387 // Show the sheet. |
| 388 [NSApp beginSheet:[addressSheetController window] |
| 389 modalForWindow:[self window] |
| 390 modalDelegate:self |
| 391 didEndSelector:@selector(addressEditDidEnd:returnCode:contextInfo:) |
| 392 contextInfo:&profiles_[i]]; |
| 393 } |
| 394 } else if ([self isCreditCardRow:selectedRow]) { |
| 395 if (!creditCardSheetController.get()) { |
| 396 int i = [self creditCardIndexFromRow:selectedRow]; |
| 397 |
| 398 // Create a new credit card sheet controller in "Edit" mode. |
| 399 creditCardSheetController.reset( |
| 400 [[AutoFillCreditCardSheetController alloc] |
| 401 initWithCreditCard:creditCards_[i] |
| 402 mode:kAutoFillCreditCardEditMode |
| 403 controller:self]); |
| 404 |
| 405 // Show the sheet. |
| 406 [NSApp beginSheet:[creditCardSheetController window] |
| 407 modalForWindow:[self window] |
| 408 modalDelegate:self |
| 409 didEndSelector:@selector(creditCardEditDidEnd:returnCode:contextInfo:) |
| 410 contextInfo:&creditCards_[i]]; |
| 411 } |
| 412 } |
| 413 } |
| 414 |
| 415 // Edit address sheet was dismissed. Non-zero |returnCode| indicates a save. |
| 416 - (void)addressEditDidEnd:(NSWindow *)sheet |
| 417 returnCode:(int)returnCode |
| 418 contextInfo:(void *)contextInfo { |
| 419 DCHECK(contextInfo != NULL); |
| 420 if (returnCode) { |
| 421 AutoFillProfile* profile = static_cast<AutoFillProfile*>(contextInfo); |
| 422 [addressSheetController copyModelToProfile:profile]; |
| 423 [tableView_ reloadData]; |
| 424 } |
| 425 [sheet orderOut:self]; |
| 426 addressSheetController.reset(nil); |
| 427 } |
| 428 |
| 429 // Edit credit card sheet was dismissed. Non-zero |returnCode| indicates a |
| 430 // save. |
| 431 - (void)creditCardEditDidEnd:(NSWindow *)sheet |
| 432 returnCode:(int)returnCode |
| 433 contextInfo:(void *)contextInfo { |
| 434 DCHECK(contextInfo != NULL); |
| 435 if (returnCode) { |
| 436 CreditCard* creditCard = static_cast<CreditCard*>(contextInfo); |
| 437 [creditCardSheetController copyModelToCreditCard:creditCard]; |
| 438 [tableView_ reloadData]; |
| 439 } |
| 440 [sheet orderOut:self]; |
| 441 creditCardSheetController.reset(nil); |
| 442 } |
| 443 |
| 444 // NSTableView Delegate method. |
| 445 - (BOOL)tableView:(NSTableView *)tableView isGroupRow:(NSInteger)row { |
| 446 if ([self isProfileGroupRow:row] || [self isCreditCardGroupRow:row]) |
| 447 return YES; |
| 448 return NO; |
| 449 } |
| 450 |
| 451 // NSTableView Delegate method. |
| 452 - (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row { |
| 453 return ![self tableView:tableView isGroupRow:row]; |
| 454 } |
| 455 |
| 456 // NSTableView Delegate method. |
| 457 - (id)tableView:(NSTableView *)tableView |
| 458 objectValueForTableColumn:(NSTableColumn *)tableColumn |
| 459 row:(NSInteger)row { |
| 460 if ([[tableColumn identifier] isEqualToString:@"Spacer"]) |
| 461 return @""; |
| 462 |
| 463 // Check that we're initialized before supplying data. |
| 464 if (tableView == tableView_) { |
| 465 |
| 466 // Section label. |
| 467 if ([self isProfileGroupRow:row]) |
| 468 if ([[tableColumn identifier] isEqualToString:@"Label"]) |
| 469 return @"Addresses"; |
| 470 else |
| 471 return @""; |
| 472 |
| 473 if (row < 0) |
| 474 return @""; |
| 475 |
| 476 // Data row. |
| 477 if ([self isProfileRow:row]) { |
| 478 if ([[tableColumn identifier] isEqualToString:@"Label"]) |
| 479 return SysUTF16ToNSString( |
| 480 profiles_[[self profileIndexFromRow:row]].Label()); |
| 481 |
| 482 if ([[tableColumn identifier] isEqualToString:@"Summary"]) |
| 483 return SysUTF16ToNSString( |
| 484 profiles_[[self profileIndexFromRow:row]].PreviewSummary()); |
| 485 |
| 486 return @""; |
| 487 } |
| 488 |
| 489 // Section label. |
| 490 if ([self isCreditCardGroupRow:row]) |
| 491 if ([[tableColumn identifier] isEqualToString:@"Label"]) |
| 492 return @"Credit Cards"; |
| 493 else |
| 494 return @""; |
| 495 |
| 496 // Data row. |
| 497 if ([self isCreditCardRow:row]) { |
| 498 if ([[tableColumn identifier] isEqualToString:@"Label"]) |
| 499 return SysUTF16ToNSString( |
| 500 creditCards_[[self creditCardIndexFromRow:row]].Label()); |
| 501 |
| 502 if ([[tableColumn identifier] isEqualToString:@"Summary"]) |
| 503 return SysUTF16ToNSString( |
| 504 creditCards_[ |
| 505 [self creditCardIndexFromRow:row]].PreviewSummary()); |
| 506 |
| 507 return @""; |
| 508 } |
| 509 } |
| 510 |
| 511 return @""; |
| 512 } |
| 513 |
| 514 // We implement this delegate method to update our |itemIsSelected| property. |
| 515 // The "Edit..." and "Remove" buttons' enabled state depends on having a |
| 516 // valid selection in the table. |
| 517 - (void)tableViewSelectionDidChange:(NSNotification *)aNotification { |
| 518 if ([tableView_ selectedRow] >= 0) |
| 519 [self setItemIsSelected:YES]; |
| 520 else |
| 521 [self setItemIsSelected:NO]; |
| 522 } |
| 523 |
| 524 - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { |
| 525 if (tableView == tableView_) { |
| 526 // 1 section header, the profiles, 1 section header, the credit cards. |
| 527 return 1 + profiles_.size() + 1 + creditCards_.size(); |
| 528 } |
| 529 |
| 530 return 0; |
| 311 } | 531 } |
| 312 | 532 |
| 313 - (NSArray*)addressLabels { | 533 - (NSArray*)addressLabels { |
| 314 NSUInteger capacity = [addressFormViewControllers_ count]; | 534 NSUInteger capacity = profiles_.size(); |
| 315 NSMutableArray* array = [NSMutableArray arrayWithCapacity:capacity]; | 535 NSMutableArray* array = [NSMutableArray arrayWithCapacity:capacity]; |
| 316 | 536 |
| 317 for (AutoFillAddressViewController* addressFormViewController in | 537 std::vector<AutoFillProfile>::iterator i; |
| 318 addressFormViewControllers_.get()) { | 538 for (i = profiles_.begin(); i != profiles_.end(); ++i) { |
| 319 [array addObject:[[addressFormViewController addressModel] label]]; | 539 [array addObject:SysUTF16ToNSString(i->Label())]; |
| 320 } | 540 } |
| 321 | 541 |
| 322 return array; | 542 return array; |
| 323 } | |
| 324 | |
| 325 - (NSArray*)creditCardLabels { | |
| 326 NSUInteger capacity = [creditCardFormViewControllers_ count]; | |
| 327 NSMutableArray* array = [NSMutableArray arrayWithCapacity:capacity]; | |
| 328 | |
| 329 for (AutoFillCreditCardViewController* creditCardFormViewController in | |
| 330 creditCardFormViewControllers_.get()) { | |
| 331 [array addObject:[[creditCardFormViewController creditCardModel] label]]; | |
| 332 } | |
| 333 | |
| 334 return array; | |
| 335 } | 543 } |
| 336 | 544 |
| 337 @end | 545 @end |
| 338 | 546 |
| 339 @implementation AutoFillDialogController (ExposedForUnitTests) | 547 @implementation AutoFillDialogController (ExposedForUnitTests) |
| 340 | 548 |
| 341 + (AutoFillDialogController*)controllerWithObserver: | 549 + (AutoFillDialogController*)controllerWithObserver: |
| 342 (AutoFillDialogObserver*)observer | 550 (AutoFillDialogObserver*)observer |
| 343 profile:(Profile*)profile | 551 profile:(Profile*)profile |
| 344 importedProfile:(AutoFillProfile*)importedProfile | 552 importedProfile:(AutoFillProfile*)importedProfile |
| 345 importedCreditCard:(CreditCard*)importedCreditCard { | 553 importedCreditCard:(CreditCard*)importedCreditCard { |
| 346 | 554 |
| 347 // Deallocation is done upon window close. See |windowWillClose:|. | 555 // Deallocation is done upon window close. See |windowWillClose:|. |
| 348 AutoFillDialogController* controller = | 556 AutoFillDialogController* controller = |
| 349 [[self alloc] initWithObserver:observer | 557 [[self alloc] initWithObserver:observer |
| 350 profile:profile | 558 profile:profile |
| 351 importedProfile:importedProfile | 559 importedProfile:importedProfile |
| 352 importedCreditCard:importedCreditCard]; | 560 importedCreditCard:importedCreditCard]; |
| 353 return controller; | 561 return controller; |
| 354 } | 562 } |
| 355 | 563 |
| 356 | 564 |
| 357 // This is the designated initializer for this class. | 565 // This is the designated initializer for this class. |
| 358 // |profiles| are non-retained immutable list of autofill profiles. | 566 // |profiles| are non-retained immutable list of autofill profiles. |
| 359 // |creditCards| are non-retained immutable list of credit card info. | 567 // |creditCards| are non-retained immutable list of credit card info. |
| 360 - (id)initWithObserver:(AutoFillDialogObserver*)observer | 568 - (id)initWithObserver:(AutoFillDialogObserver*)observer |
| 361 profile:(Profile*)profile | 569 profile:(Profile*)profile |
| 362 importedProfile:(AutoFillProfile*)importedProfile | 570 importedProfile:(AutoFillProfile*)importedProfile |
| 363 importedCreditCard:(CreditCard*)importedCreditCard { | 571 importedCreditCard:(CreditCard*)importedCreditCard { |
| 364 CHECK(profile); | 572 DCHECK(profile); |
| 365 // Use initWithWindowNibPath: instead of initWithWindowNibName: so we | 573 // Use initWithWindowNibPath: instead of initWithWindowNibName: so we |
| 366 // can override it in a unit test. | 574 // can override it in a unit test. |
| 367 NSString* nibpath = [mac_util::MainAppBundle() | 575 NSString* nibpath = [mac_util::MainAppBundle() |
| 368 pathForResource:@"AutoFillDialog" | 576 pathForResource:@"AutoFillDialog" |
| 369 ofType:@"nib"]; | 577 ofType:@"nib"]; |
| 370 if ((self = [super initWithWindowNibPath:nibpath owner:self])) { | 578 if ((self = [super initWithWindowNibPath:nibpath owner:self])) { |
| 579 // Initialize member variables based on input. |
| 371 observer_ = observer; | 580 observer_ = observer; |
| 372 profile_ = profile; | 581 profile_ = profile; |
| 373 importedProfile_ = importedProfile; | 582 importedProfile_ = importedProfile; |
| 374 importedCreditCard_ = importedCreditCard; | 583 importedCreditCard_ = importedCreditCard; |
| 375 | 584 |
| 376 // Use property here to trigger KVO binding. | 585 // Use property here to trigger KVO binding. |
| 377 [self setAuxiliaryEnabled:profile_->GetPrefs()->GetBoolean( | 586 [self setAuxiliaryEnabled:profile_->GetPrefs()->GetBoolean( |
| 378 prefs::kAutoFillAuxiliaryProfilesEnabled)]; | 587 prefs::kAutoFillAuxiliaryProfilesEnabled)]; |
| 379 | 588 |
| 380 // Do not use [NSMutableArray array] here; we need predictable destruction | 589 // Do not use [NSMutableArray array] here; we need predictable destruction |
| 381 // which will be prevented by having a reference held by an autorelease | 590 // which will be prevented by having a reference held by an autorelease |
| 382 // pool. | 591 // pool. |
| 383 | |
| 384 // Initialize array of sub-controllers. | |
| 385 addressFormViewControllers_.reset( | |
| 386 [[NSMutableArray alloc] initWithCapacity:0]); | |
| 387 | |
| 388 // Initialize array of sub-controllers. | |
| 389 creditCardFormViewControllers_.reset( | |
| 390 [[NSMutableArray alloc] initWithCapacity:0]); | |
| 391 } | 592 } |
| 392 return self; | 593 return self; |
| 393 } | 594 } |
| 394 | 595 |
| 395 // Close the dialog. | 596 // Close the dialog. |
| 396 - (void)closeDialog { | 597 - (void)closeDialog { |
| 397 [[self window] close]; | 598 [[self window] close]; |
| 398 [NSApp stopModal]; | 599 [NSApp stopModal]; |
| 399 } | 600 } |
| 400 | 601 |
| 401 - (NSMutableArray*)addressFormViewControllers { | 602 - (AutoFillAddressSheetController*)addressSheetController { |
| 402 return addressFormViewControllers_.get(); | 603 return addressSheetController.get(); |
| 403 } | 604 } |
| 404 | 605 |
| 405 - (NSMutableArray*)creditCardFormViewControllers { | 606 - (AutoFillCreditCardSheetController*)creditCardSheetController { |
| 406 return creditCardFormViewControllers_.get(); | 607 return creditCardSheetController.get(); |
| 608 } |
| 609 |
| 610 - (void)selectAddressAtIndex:(size_t)i { |
| 611 [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex: |
| 612 [self rowFromProfileIndex:i]] |
| 613 byExtendingSelection:NO]; |
| 614 } |
| 615 |
| 616 - (void)selectCreditCardAtIndex:(size_t)i { |
| 617 [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex: |
| 618 [self rowFromCreditCardIndex:i]] |
| 619 byExtendingSelection:NO]; |
| 407 } | 620 } |
| 408 | 621 |
| 409 @end | 622 @end |
| 410 | 623 |
| 411 @implementation AutoFillDialogController (PrivateMethods) | 624 @implementation AutoFillDialogController (PrivateMethods) |
| 412 | 625 |
| 413 // Run application modal. | 626 // Run application modal. |
| 414 - (void)runModalDialog { | 627 - (void)runModalDialog { |
| 415 // Use stored window geometry if it exists. | 628 // Use stored window geometry if it exists. |
| 416 if (g_browser_process && g_browser_process->local_state()) { | 629 if (g_browser_process && g_browser_process->local_state()) { |
| 417 sizeSaver_.reset([[WindowSizeAutosaver alloc] | 630 sizeSaver_.reset([[WindowSizeAutosaver alloc] |
| 418 initWithWindow:[self window] | 631 initWithWindow:[self window] |
| 419 prefService:g_browser_process->local_state() | 632 prefService:g_browser_process->local_state() |
| 420 path:prefs::kAutoFillDialogPlacement | 633 path:prefs::kAutoFillDialogPlacement |
| 421 state:kSaveWindowPos]); | 634 state:kSaveWindowPos]); |
| 422 } | 635 } |
| 423 | 636 |
| 424 [NSApp runModalForWindow:[self window]]; | 637 [NSApp runModalForWindow:[self window]]; |
| 425 } | 638 } |
| 426 | 639 |
| 427 // Install controller and views for the address form and the credit card form. | |
| 428 // They are installed into the appropriate sibling order so that they can be | |
| 429 // arranged vertically by the VerticalLayoutView class. We insert the views | |
| 430 // into the |childView_| but we hold onto the controllers and release them in | |
| 431 // our dealloc once the dialog closes. | |
| 432 - (void)installChildViews { | |
| 433 NSView* insertionPoint; | |
| 434 insertionPoint = addressSection_; | |
| 435 for (size_t i = 0; i < profiles_.size(); i++) { | |
| 436 // Special case for first address, we want to show full contents. | |
| 437 NSCellStateValue disclosureState = (i == 0) ? NSOnState : NSOffState; | |
| 438 scoped_nsobject<AutoFillAddressViewController> addressViewController( | |
| 439 [[AutoFillAddressViewController alloc] | |
| 440 initWithProfile:profiles_[i] | |
| 441 disclosure:disclosureState | |
| 442 controller:self]); | |
| 443 [self willChangeValueForKey:@"addressLabels"]; | |
| 444 [addressFormViewControllers_.get() addObject:addressViewController]; | |
| 445 [self didChangeValueForKey:@"addressLabels"]; | |
| 446 | |
| 447 // Embed the child view into our (owned by us) target view. | |
| 448 [childView_ addSubview:[addressViewController view] | |
| 449 positioned:NSWindowBelow relativeTo:insertionPoint]; | |
| 450 insertionPoint = [addressViewController view]; | |
| 451 [[addressViewController view] setFrameOrigin:NSMakePoint(0, 0)]; | |
| 452 } | |
| 453 | |
| 454 insertionPoint = creditCardSection_; | |
| 455 for (size_t i = 0; i < creditCards_.size(); i++) { | |
| 456 scoped_nsobject<AutoFillCreditCardViewController> creditCardViewController( | |
| 457 [[AutoFillCreditCardViewController alloc] | |
| 458 initWithCreditCard:creditCards_[i] | |
| 459 disclosure:NSOffState | |
| 460 controller:self]); | |
| 461 [self willChangeValueForKey:@"creditCardLabels"]; | |
| 462 [creditCardFormViewControllers_.get() addObject:creditCardViewController]; | |
| 463 [self didChangeValueForKey:@"creditCardLabels"]; | |
| 464 | |
| 465 // Embed the child view into our (owned by us) target view. | |
| 466 [childView_ addSubview:[creditCardViewController view] | |
| 467 positioned:NSWindowBelow relativeTo:insertionPoint]; | |
| 468 insertionPoint = [creditCardViewController view]; | |
| 469 [[creditCardViewController view] setFrameOrigin:NSMakePoint(0, 0)]; | |
| 470 } | |
| 471 } | |
| 472 | |
| 473 - (void)onPersonalDataLoaded:(const std::vector<AutoFillProfile*>&)profiles | 640 - (void)onPersonalDataLoaded:(const std::vector<AutoFillProfile*>&)profiles |
| 474 creditCards:(const std::vector<CreditCard*>&)creditCards { | 641 creditCards:(const std::vector<CreditCard*>&)creditCards { |
| 475 if (importedProfile_) { | 642 if (importedProfile_) { |
| 476 profiles_.push_back(*importedProfile_); | 643 profiles_.push_back(*importedProfile_); |
| 477 } | 644 } |
| 478 | 645 |
| 479 if (importedCreditCard_) { | 646 if (importedCreditCard_) { |
| 480 creditCards_.push_back(*importedCreditCard_); | 647 creditCards_.push_back(*importedCreditCard_); |
| 481 } | 648 } |
| 482 | 649 |
| 483 // If we're not using imported data then use the data fetch from the web db. | 650 // If we're not using imported data then use the data fetch from the web db. |
| 484 if (!importedProfile_ && !importedCreditCard_) { | 651 if (!importedProfile_ && !importedCreditCard_) { |
| 485 // Make local copy of |profiles|. | 652 // Make local copy of |profiles|. |
| 486 for (std::vector<AutoFillProfile*>::const_iterator iter = profiles.begin(); | 653 for (std::vector<AutoFillProfile*>::const_iterator iter = profiles.begin(); |
| 487 iter != profiles.end(); ++iter) | 654 iter != profiles.end(); ++iter) |
| 488 profiles_.push_back(**iter); | 655 profiles_.push_back(**iter); |
| 489 | 656 |
| 490 // Make local copy of |creditCards|. | 657 // Make local copy of |creditCards|. |
| 491 for (std::vector<CreditCard*>::const_iterator iter = creditCards.begin(); | 658 for (std::vector<CreditCard*>::const_iterator iter = creditCards.begin(); |
| 492 iter != creditCards.end(); ++iter) | 659 iter != creditCards.end(); ++iter) |
| 493 creditCards_.push_back(**iter); | 660 creditCards_.push_back(**iter); |
| 494 } | 661 } |
| 662 } |
| 495 | 663 |
| 496 [self installChildViews]; | 664 - (BOOL)isProfileRow:(NSInteger)row { |
| 665 if (row > 0 && static_cast<size_t>(row) <= profiles_.size()) |
| 666 return YES; |
| 667 return NO; |
| 668 } |
| 669 |
| 670 - (BOOL)isProfileGroupRow:(NSInteger)row { |
| 671 if (row == 0) |
| 672 return YES; |
| 673 return NO; |
| 674 } |
| 675 |
| 676 - (BOOL)isCreditCardRow:(NSInteger)row { |
| 677 if (row > 0 && |
| 678 static_cast<size_t>(row) >= profiles_.size() + 2 && |
| 679 static_cast<size_t>(row) <= profiles_.size() + creditCards_.size() + 1) |
| 680 return YES; |
| 681 return NO; |
| 682 } |
| 683 |
| 684 - (BOOL)isCreditCardGroupRow:(NSInteger)row { |
| 685 if (row > 0 && static_cast<size_t>(row) == profiles_.size() + 1) |
| 686 return YES; |
| 687 return NO; |
| 688 } |
| 689 |
| 690 - (size_t)profileIndexFromRow:(NSInteger)row { |
| 691 DCHECK([self isProfileRow:row]); |
| 692 return static_cast<size_t>(row) - 1; |
| 693 } |
| 694 |
| 695 - (size_t)creditCardIndexFromRow:(NSInteger)row { |
| 696 DCHECK([self isCreditCardRow:row]); |
| 697 return static_cast<size_t>(row) - (profiles_.size() + 2); |
| 698 } |
| 699 |
| 700 - (NSInteger)rowFromProfileIndex:(size_t)i { |
| 701 return 1 + i; |
| 702 } |
| 703 |
| 704 - (NSInteger)rowFromCreditCardIndex:(size_t)i { |
| 705 return 1 + profiles_.size() + 1 + i; |
| 497 } | 706 } |
| 498 | 707 |
| 499 @end | 708 @end |
| 709 |
| 710 // An NSValueTransformer subclass for use in validation of empty data entry |
| 711 // fields. Transforms a nil or empty string into a warning image. This data |
| 712 // transformer is used in the address and credit card sheets for empty label |
| 713 // strings. |
| 714 @interface MissingAlertTransformer : NSValueTransformer { |
| 715 } |
| 716 @end |
| 717 |
| 718 @implementation MissingAlertTransformer |
| 719 + (Class)transformedValueClass { |
| 720 return [NSImage class]; |
| 721 } |
| 722 |
| 723 + (BOOL)allowsReverseTransformation { |
| 724 return NO; |
| 725 } |
| 726 |
| 727 - (id)transformedValue:(id)string { |
| 728 if (string == nil || [string length] == 0) { |
| 729 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 730 NSImage* image = rb.GetNSImageNamed(IDR_WARNING); |
| 731 DCHECK(image); |
| 732 return image; |
| 733 } |
| 734 return nil; |
| 735 } |
| 736 |
| 737 @end |
| 738 |
| 739 // An NSValueTransformer subclass for use in validation of phone number |
| 740 // fields. Transforms an invalid phone number string into a warning image. |
| 741 // This data transformer is used in the credit card sheet for invalid phone and |
| 742 // fax numbers. |
| 743 @interface InvalidPhoneTransformer : NSValueTransformer { |
| 744 } |
| 745 @end |
| 746 |
| 747 @implementation InvalidPhoneTransformer |
| 748 + (Class)transformedValueClass { |
| 749 return [NSImage class]; |
| 750 } |
| 751 |
| 752 + (BOOL)allowsReverseTransformation { |
| 753 return NO; |
| 754 } |
| 755 |
| 756 - (id)transformedValue:(id)string { |
| 757 if (string != nil && [string length] != 0) { |
| 758 // TODO(dhollowa): Using SetInfo() call to validate phone number. Should |
| 759 // have explicit validation method. More robust validation is needed as |
| 760 // well eventually. |
| 761 AutoFillProfile profile(string16(), 0); |
| 762 profile.SetInfo(AutoFillType(PHONE_HOME_WHOLE_NUMBER), |
| 763 base::SysNSStringToUTF16(string)); |
| 764 if (profile.GetFieldText(AutoFillType(PHONE_HOME_WHOLE_NUMBER)).empty()) { |
| 765 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 766 NSImage* image = rb.GetNSImageNamed(IDR_WARNING); |
| 767 DCHECK(image); |
| 768 return image; |
| 769 } |
| 770 } |
| 771 return nil; |
| 772 } |
| 773 |
| 774 @end |
| OLD | NEW |