diff options
4 files changed, 184 insertions, 67 deletions
diff --git a/chrome/app/nibs/AutoFillDialog.xib b/chrome/app/nibs/AutoFillDialog.xib index 9b7d996..f7edaa9 100644 --- a/chrome/app/nibs/AutoFillDialog.xib +++ b/chrome/app/nibs/AutoFillDialog.xib @@ -181,7 +181,7 @@ </object> </object> <double key="NSRowHeight">17</double> - <int key="NSTvFlags">306184192</int> + <int key="NSTvFlags">440401920</int> <reference key="NSDelegate"/> <reference key="NSDataSource"/> <int key="NSColumnAutoresizingStyle">4</int> @@ -670,7 +670,7 @@ <string key="label">enabled2: autoFillEnabled</string> <reference key="source" ref="457244217"/> <reference key="destination" ref="1001"/> - <object class="NSNibBindingConnector" key="connector"> + <object class="NSNibBindingConnector" key="connector" id="270191331"> <reference key="NSSource" ref="457244217"/> <reference key="NSDestination" ref="1001"/> <string key="NSLabel">enabled2: autoFillEnabled</string> @@ -749,6 +749,50 @@ </object> <int key="connectionID">215</int> </object> + <object class="IBConnectionRecord"> + <object class="IBBindingConnection" key="connection"> + <string key="label">enabled3: multipleSelected</string> + <reference key="source" ref="457244217"/> + <reference key="destination" ref="1001"/> + <object class="NSNibBindingConnector" key="connector"> + <reference key="NSSource" ref="457244217"/> + <reference key="NSDestination" ref="1001"/> + <string key="NSLabel">enabled3: multipleSelected</string> + <string key="NSBinding">enabled3</string> + <string key="NSKeyPath">multipleSelected</string> + <object class="NSDictionary" key="NSOptions"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>NSMultipleValuesPlaceholder</string> + <string>NSNoSelectionPlaceholder</string> + <string>NSNotApplicablePlaceholder</string> + <string>NSNullPlaceholder</string> + <string>NSValueTransformerName</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <integer value="-1"/> + <integer value="-1"/> + <integer value="-1"/> + <integer value="-1"/> + <string>NSNegateBoolean</string> + </object> + </object> + <reference key="NSPreviousConnector" ref="270191331"/> + <int key="NSNibBindingConnectorVersion">2</int> + </object> + </object> + <int key="connectionID">218</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">editButton_</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="457244217"/> + </object> + <int key="connectionID">219</int> + </object> </object> <object class="IBMutableOrderedSet" key="objectRecords"> <object class="NSArray" key="orderedObjects"> @@ -1108,7 +1152,7 @@ </object> </object> <nil key="sourceID"/> - <int key="maxID">215</int> + <int key="maxID">219</int> </object> <object class="IBClassDescriber" key="IBDocument.Classes"> <object class="NSMutableArray" key="referencedPartialClassDescriptions"> @@ -1140,8 +1184,17 @@ </object> </object> <object class="NSMutableDictionary" key="outlets"> - <string key="NS.key.0">tableView_</string> - <string key="NS.object.0">AutoFillTableView</string> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>editButton_</string> + <string>tableView_</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>NSButton</string> + <string>AutoFillTableView</string> + </object> </object> <object class="IBClassDescriptionSource" key="sourceIdentifier"> <string key="majorKey">IBProjectSource</string> @@ -1798,27 +1851,6 @@ <string key="className">NSObject</string> <object class="IBClassDescriptionSource" key="sourceIdentifier"> <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">QuartzCore.framework/Headers/CAAnimation.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">QuartzCore.framework/Headers/CALayer.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">QuartzCore.framework/Headers/CIImageProvider.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> <string key="minorKey">SecurityInterface.framework/Headers/SFAuthorizationView.h</string> </object> </object> diff --git a/chrome/browser/autofill/autofill_dialog_controller_mac.h b/chrome/browser/autofill/autofill_dialog_controller_mac.h index 3318443..7a7faa7 100644 --- a/chrome/browser/autofill/autofill_dialog_controller_mac.h +++ b/chrome/browser/autofill/autofill_dialog_controller_mac.h @@ -34,6 +34,9 @@ class Profile; // cards with section headers for both. IBOutlet AutoFillTableView* tableView_; + // Outlet to "Edit..." button. Here for unit testing purposes. + IBOutlet NSButton* editButton_; + // 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. @@ -68,6 +71,10 @@ class Profile; // "Remove" buttons. BOOL itemIsSelected_; + // State for |multipleSelected| property used in bindings for "Edit..." + // button. + BOOL multipleSelected_; + // Utility object to save and restore dialog position. scoped_nsobject<WindowSizeAutosaver> sizeSaver_; @@ -97,6 +104,10 @@ class Profile; // edit and delete buttons are bound to this property. @property (nonatomic) BOOL itemIsSelected; +// Property representing multiple selection state in |tableView_|. Enabled +// state of edit button is bound to this property. +@property (nonatomic) BOOL multipleSelected; + // 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. @@ -168,6 +179,9 @@ class Profile; - (AutoFillCreditCardSheetController*)creditCardSheetController; - (void)selectAddressAtIndex:(size_t)i; - (void)selectCreditCardAtIndex:(size_t)i; +- (void)addSelectedAddressAtIndex:(size_t)i; +- (void)addSelectedCreditCardAtIndex:(size_t)i; +- (BOOL)editButtonEnabled; @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 377e1cd..d0e16ae 100644 --- a/chrome/browser/autofill/autofill_dialog_controller_mac.mm +++ b/chrome/browser/autofill/autofill_dialog_controller_mac.mm @@ -191,6 +191,7 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() { @synthesize autoFillEnabled = autoFillEnabled_; @synthesize auxiliaryEnabled = auxiliaryEnabled_; @synthesize itemIsSelected = itemIsSelected_; +@synthesize multipleSelected = multipleSelected_; + (void)showAutoFillDialogWithObserver:(AutoFillDialogObserver*)observer profile:(Profile*)profile @@ -356,43 +357,45 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() { creditCardSheetController.reset(nil); } -// Deletes selected item, either address or credit card depending on the item -// selected. +// Deletes selected items; either addresses, credit cards, or a mixture of the +// two depending on the items selected. - (IBAction)deleteSelection:(id)sender { + NSIndexSet* selectedRows = [tableView_ selectedRowIndexes]; 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]; + NSInteger rowCount = [tableView_ numberOfRows]; + + // Loop through from last to first deleting selected items as we go. + for (NSInteger i = rowCount-1; i>=0; --i) { + if (![selectedRows containsIndex:i]) + continue; + + // We keep track of the "top most" selection in the list so we know where + // to to set new selection below. + if (i < selectedRow) + selectedRow = i; + + if ([self isProfileRow:i]) { + profiles_.erase( + profiles_.begin() + [self profileIndexFromRow:i]); + } else if ([self isCreditCardRow:i]) { + creditCards_.erase( + creditCards_.begin() + [self creditCardIndexFromRow:i]); } - UpdateProfileLabels(&profiles_); - [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]; } + + // 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]; + } + + UpdateProfileLabels(&profiles_); + [tableView_ reloadData]; } // Edits the selected item, either address or credit card depending on the item @@ -542,14 +545,18 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() { return @""; } -// We implement this delegate method to update our |itemIsSelected| property. +// We implement this delegate method to update our |itemIsSelected| and +// |multipleSelected| properties. // The "Edit..." and "Remove" buttons' enabled state depends on having a -// valid selection in the table. +// valid selection in the table. The "Edit..." button depends on having +// exactly one item selected. - (void)tableViewSelectionDidChange:(NSNotification *)aNotification { if ([tableView_ selectedRow] >= 0) [self setItemIsSelected:YES]; else [self setItemIsSelected:NO]; + + [self setMultipleSelected:([[tableView_ selectedRowIndexes] count] > 1UL)]; } - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { @@ -654,6 +661,22 @@ void PersonalDataManagerObserver::OnPersonalDataLoaded() { byExtendingSelection:NO]; } +- (void)addSelectedAddressAtIndex:(size_t)i { + [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex: + [self rowFromProfileIndex:i]] + byExtendingSelection:YES]; +} + +- (void)addSelectedCreditCardAtIndex:(size_t)i { + [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex: + [self rowFromCreditCardIndex:i]] + byExtendingSelection:YES]; +} + +- (BOOL)editButtonEnabled { + return [editButton_ isEnabled]; +} + @end @implementation AutoFillDialogController (PrivateMethods) diff --git a/chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm b/chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm index d3e2550..80678077 100644 --- a/chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm +++ b/chrome/browser/autofill/autofill_dialog_controller_mac_unittest.mm @@ -389,7 +389,7 @@ TEST_F(AutoFillDialogControllerTest, AddNewProfile) { // Should hit our observer. ASSERT_TRUE(observer_.hit_); - // Sizes should match be different. New size should be 2. + // Sizes should be different. New size should be 2. ASSERT_NE(observer_.profiles_.size(), profiles().size()); ASSERT_EQ(observer_.profiles_.size(), 2UL); @@ -413,7 +413,7 @@ TEST_F(AutoFillDialogControllerTest, AddNewCreditCard) { // Should hit our observer. ASSERT_TRUE(observer_.hit_); - // Sizes should match be different. New size should be 2. + // Sizes should be different. New size should be 2. ASSERT_NE(observer_.credit_cards_.size(), credit_cards().size()); ASSERT_EQ(observer_.credit_cards_.size(), 2UL); @@ -434,7 +434,7 @@ TEST_F(AutoFillDialogControllerTest, DeleteProfile) { // Should hit our observer. ASSERT_TRUE(observer_.hit_); - // Sizes should match be different. New size should be 0. + // Sizes should be different. New size should be 0. ASSERT_NE(observer_.profiles_.size(), profiles().size()); ASSERT_EQ(observer_.profiles_.size(), 0UL); } @@ -451,7 +451,7 @@ TEST_F(AutoFillDialogControllerTest, DeleteCreditCard) { // Should hit our observer. ASSERT_TRUE(observer_.hit_); - // Sizes should match be different. New size should be 0. + // Sizes should be different. New size should be 0. ASSERT_NE(observer_.credit_cards_.size(), credit_cards().size()); ASSERT_EQ(observer_.credit_cards_.size(), 0UL); } @@ -471,7 +471,7 @@ TEST_F(AutoFillDialogControllerTest, TwoProfilesDeleteOne) { // Should hit our observer. ASSERT_TRUE(observer_.hit_); - // Sizes should match be different. New size should be 0. + // Sizes should be different. New size should be 1. ASSERT_NE(observer_.profiles_.size(), profiles().size()); ASSERT_EQ(observer_.profiles_.size(), 1UL); @@ -499,7 +499,7 @@ TEST_F(AutoFillDialogControllerTest, TwoCreditCardsDeleteOne) { // Should hit our observer. ASSERT_TRUE(observer_.hit_); - // Sizes should match be different. New size should be 0. + // Sizes should be different. New size should be 1. ASSERT_NE(observer_.credit_cards_.size(), credit_cards().size()); ASSERT_EQ(observer_.credit_cards_.size(), 1UL); @@ -508,6 +508,54 @@ TEST_F(AutoFillDialogControllerTest, TwoCreditCardsDeleteOne) { ASSERT_EQ(observer_.credit_cards_[0], credit_card); } +TEST_F(AutoFillDialogControllerTest, DeleteMultiple) { + AutoFillProfile profile(ASCIIToUTF16("One"), 1); + profile.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Joe")); + profiles().push_back(&profile); + AutoFillProfile profile2(ASCIIToUTF16("Two"), 2); + profile2.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Bob")); + profiles().push_back(&profile2); + + CreditCard credit_card(ASCIIToUTF16("Visa"), 1); + credit_card.SetInfo(AutoFillType(CREDIT_CARD_NAME), ASCIIToUTF16("Joe")); + credit_cards().push_back(&credit_card); + CreditCard credit_card2(ASCIIToUTF16("Mastercard"), 2); + credit_card2.SetInfo(AutoFillType(CREDIT_CARD_NAME), ASCIIToUTF16("Bob")); + credit_cards().push_back(&credit_card2); + + LoadDialog(); + [controller_ selectAddressAtIndex:1]; + [controller_ addSelectedCreditCardAtIndex:0]; + ASSERT_FALSE([controller_ editButtonEnabled]); + [controller_ deleteSelection:nil]; + [controller_ selectAddressAtIndex:0]; + ASSERT_TRUE([controller_ editButtonEnabled]); + [controller_ save:nil]; + + // Should hit our observer. + ASSERT_TRUE(observer_.hit_); + + // Sizes should be different. New size should be 1. + ASSERT_NE(observer_.profiles_.size(), profiles().size()); + ASSERT_EQ(observer_.profiles_.size(), 1UL); + + // Sizes should be different. New size should be 1. + ASSERT_NE(observer_.credit_cards_.size(), credit_cards().size()); + ASSERT_EQ(observer_.credit_cards_.size(), 1UL); + + // First address should match. + profiles()[0]->set_unique_id(observer_.profiles_[0].unique_id()); + + // Do not compare labels. Label is a derived field. + observer_.profiles_[0].set_label(string16()); + profile.set_label(string16()); + ASSERT_EQ(observer_.profiles_[0], profile); + + // Second credit card should match. + credit_cards()[0]->set_unique_id(observer_.credit_cards_[0].unique_id()); + ASSERT_EQ(observer_.credit_cards_[0], credit_card2); +} + // Auxilliary profiles are enabled by default. TEST_F(AutoFillDialogControllerTest, AuxiliaryProfilesTrue) { LoadDialog(); |