| Index: chrome/browser/autofill/autofill_dialog_controller_mac.mm
|
| diff --git a/chrome/browser/autofill/autofill_dialog_controller_mac.mm b/chrome/browser/autofill/autofill_dialog_controller_mac.mm
|
| index ec127baff16d7ad0d182d78e2ff5da2d6684e44f..9fac0158805fe3f60781d35857261213b2772a8d 100644
|
| --- a/chrome/browser/autofill/autofill_dialog_controller_mac.mm
|
| +++ b/chrome/browser/autofill/autofill_dialog_controller_mac.mm
|
| @@ -6,6 +6,7 @@
|
| #include "app/l10n_util.h"
|
| #include "app/resource_bundle.h"
|
| #include "base/mac_util.h"
|
| +#include "base/singleton.h"
|
| #include "base/sys_string_conversions.h"
|
| #include "chrome/browser/browser.h"
|
| #include "chrome/browser/browser_list.h"
|
| @@ -27,6 +28,10 @@
|
|
|
| namespace {
|
|
|
| +// Type for singleton object that contains the instance of the visible
|
| +// dialog.
|
| +typedef std::map<Profile*, AutoFillDialogController*> ProfileControllerMap;
|
| +
|
| // Update profile labels passed as |input|. When profile data changes as a
|
| // result of adding new profiles, edititing existing profiles, or deleting a
|
| // profile, then the list of profiles need to have their derived labels
|
| @@ -81,15 +86,24 @@ void UpdateProfileLabels(std::vector<AutoFillProfile>* input) {
|
|
|
| // Private interface.
|
| @interface AutoFillDialogController (PrivateMethods)
|
| +// Save profiles and credit card information after user modification.
|
| +- (void)save;
|
| +
|
| // 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;
|
|
|
| +// Asyncronous handler for when PersonalDataManager data changes. The
|
| +// personal data manager notifies the dialog with this method when the
|
| +// data has changed.
|
| +- (void)onPersonalDataChanged:(const std::vector<AutoFillProfile*>&)profiles
|
| + creditCards:(const std::vector<CreditCard*>&)creditCards;
|
| +
|
| // Called upon changes to AutoFill preferences that should be reflected in the
|
| // UI.
|
| -- (void)onPrefChanged:(const std::string&)prefName;
|
| +- (void)preferenceDidChange:(const std::string&)preferenceName;
|
|
|
| // Returns true if |row| is an index to a valid profile in |tableView_|, and
|
| // false otherwise.
|
| @@ -122,9 +136,6 @@ void UpdateProfileLabels(std::vector<AutoFillProfile>* input) {
|
| // |creditCards_|.
|
| - (NSInteger)rowFromCreditCardIndex:(size_t)row;
|
|
|
| -// Invokes the modal dialog.
|
| -- (void)runModalDialog;
|
| -
|
| @end
|
|
|
| namespace AutoFillDialogControllerInternal {
|
| @@ -148,6 +159,9 @@ class PersonalDataManagerObserver : public PersonalDataManager::Observer {
|
| // Notifies the observer that the PersonalDataManager has finished loading.
|
| virtual void OnPersonalDataLoaded();
|
|
|
| + // Notifies the observer that the PersonalDataManager data has changed.
|
| + virtual void OnPersonalDataChanged();
|
| +
|
| private:
|
| // Utility method to remove |this| from |personal_data_manager_| as an
|
| // observer.
|
| @@ -182,18 +196,22 @@ void PersonalDataManagerObserver::RemoveObserver() {
|
| }
|
| }
|
|
|
| -// The data is ready so display our data. Notify the dialog controller that
|
| -// the data is ready. Once done we clear the observer.
|
| +// The data has been loaded, notify the controller.
|
| void PersonalDataManagerObserver::OnPersonalDataLoaded() {
|
| - RemoveObserver();
|
| [controller_ onPersonalDataLoaded:personal_data_manager_->web_profiles()
|
| creditCards:personal_data_manager_->credit_cards()];
|
| }
|
|
|
| +// The data has changed, notify the controller.
|
| +void PersonalDataManagerObserver::OnPersonalDataChanged() {
|
| + [controller_ onPersonalDataChanged:personal_data_manager_->web_profiles()
|
| + creditCards:personal_data_manager_->credit_cards()];
|
| +}
|
| +
|
| // Bridges preference changed notifications to the dialog controller.
|
| -class PrefObserver : public NotificationObserver {
|
| +class PreferenceObserver : public NotificationObserver {
|
| public:
|
| - explicit PrefObserver(AutoFillDialogController* controller)
|
| + explicit PreferenceObserver(AutoFillDialogController* controller)
|
| : controller_(controller) {}
|
|
|
| // Overridden from NotificationObserver:
|
| @@ -203,7 +221,7 @@ class PrefObserver : public NotificationObserver {
|
| if (type == NotificationType::PREF_CHANGED) {
|
| const std::string* pref = Details<std::string>(details).ptr();
|
| if (pref) {
|
| - [controller_ onPrefChanged:*pref];
|
| + [controller_ preferenceDidChange:*pref];
|
| }
|
| }
|
| }
|
| @@ -211,34 +229,24 @@ class PrefObserver : public NotificationObserver {
|
| private:
|
| AutoFillDialogController* controller_;
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(PrefObserver);
|
| + DISALLOW_COPY_AND_ASSIGN(PreferenceObserver);
|
| };
|
|
|
| } // namespace AutoFillDialogControllerInternal
|
|
|
| @implementation AutoFillDialogController
|
|
|
| -@synthesize autoFillEnabled = autoFillEnabled_;
|
| @synthesize autoFillManaged = autoFillManaged_;
|
| @synthesize autoFillManagedAndDisabled = autoFillManagedAndDisabled_;
|
| -@synthesize auxiliaryEnabled = auxiliaryEnabled_;
|
| @synthesize itemIsSelected = itemIsSelected_;
|
| @synthesize multipleSelected = multipleSelected_;
|
|
|
| + (void)showAutoFillDialogWithObserver:(AutoFillDialogObserver*)observer
|
| - profile:(Profile*)profile
|
| - importedProfile:(AutoFillProfile*) importedProfile
|
| - importedCreditCard:(CreditCard*) importedCreditCard {
|
| + profile:(Profile*)profile {
|
| AutoFillDialogController* controller =
|
| [AutoFillDialogController controllerWithObserver:observer
|
| - profile:profile
|
| - importedProfile:importedProfile
|
| - importedCreditCard:importedCreditCard];
|
| -
|
| - // Only run modal dialog if it is not already being shown.
|
| - if (![controller isWindowLoaded]) {
|
| - [controller runModalDialog];
|
| - }
|
| + profile:profile];
|
| + [controller runModelessDialog];
|
| }
|
|
|
| - (void)awakeFromNib {
|
| @@ -250,15 +258,14 @@ class PrefObserver : public NotificationObserver {
|
| // |personalDataManager| data is loaded, we can proceed with the contents.
|
| [self onPersonalDataLoaded:personal_data_manager->web_profiles()
|
| creditCards:personal_data_manager->credit_cards()];
|
| - } else {
|
| - // |personalDataManager| data is NOT loaded, so we load it here, installing
|
| - // our observer.
|
| - personalDataManagerObserver_.reset(
|
| - new AutoFillDialogControllerInternal::PersonalDataManagerObserver(
|
| - self, personal_data_manager, profile_));
|
| - personal_data_manager->SetObserver(personalDataManagerObserver_.get());
|
| }
|
|
|
| + // Register as listener to listen to subsequent data change notifications.
|
| + personalDataManagerObserver_.reset(
|
| + new AutoFillDialogControllerInternal::PersonalDataManagerObserver(
|
| + 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];
|
| @@ -273,25 +280,13 @@ class PrefObserver : public NotificationObserver {
|
| [tableView_ setDataSource:nil];
|
| [tableView_ setDelegate:nil];
|
| [self autorelease];
|
| -}
|
|
|
| -// Called when the user clicks the save button.
|
| -- (IBAction)save:(id)sender {
|
| - // If we have an |observer_| then communicate the changes back, unless
|
| - // AutoFill has been disabled through policy in the mean time.
|
| - if (observer_ && !autoFillManagedAndDisabled_) {
|
| - prefAutoFillEnabled_.SetValueIfNotManaged(autoFillEnabled_);
|
| - profile_->GetPrefs()->SetBoolean(prefs::kAutoFillAuxiliaryProfilesEnabled,
|
| - auxiliaryEnabled_);
|
| - observer_->OnAutoFillDialogApply(&profiles_, &creditCards_);
|
| + // Remove ourself from the map.
|
| + ProfileControllerMap* map = Singleton<ProfileControllerMap>::get();
|
| + ProfileControllerMap::iterator it = map->find(profile_);
|
| + if (it != map->end()) {
|
| + map->erase(it);
|
| }
|
| - [self closeDialog];
|
| -}
|
| -
|
| -// Called when the user clicks the cancel button. All we need to do is stop
|
| -// the modal session.
|
| -- (IBAction)cancel:(id)sender {
|
| - [self closeDialog];
|
| }
|
|
|
| // Invokes the "Add" sheet for address information. If user saves then the new
|
| @@ -354,9 +349,9 @@ class PrefObserver : public NotificationObserver {
|
| if (!newAddress.IsEmpty()) {
|
| profiles_.push_back(newAddress);
|
|
|
| - // Refresh the view based on new data.
|
| - UpdateProfileLabels(&profiles_);
|
| - [tableView_ reloadData];
|
| + // Saving will save to the PDM and the table will refresh when PDM sends
|
| + // notification that the underlying model has changed.
|
| + [self save];
|
|
|
| // Update the selection to the newly added item.
|
| NSInteger row = [self rowFromProfileIndex:profiles_.size() - 1];
|
| @@ -381,8 +376,9 @@ class PrefObserver : public NotificationObserver {
|
| if (!newCreditCard.IsEmpty()) {
|
| creditCards_.push_back(newCreditCard);
|
|
|
| - // Refresh the view based on new data.
|
| - [tableView_ reloadData];
|
| + // Saving will save to the PDM and the table will refresh when PDM sends
|
| + // notification that the underlying model has changed.
|
| + [self save];
|
|
|
| // Update the selection to the newly added item.
|
| NSInteger row = [self rowFromCreditCardIndex:creditCards_.size() - 1];
|
| @@ -428,8 +424,9 @@ class PrefObserver : public NotificationObserver {
|
| [tableView_ deselectAll:self];
|
| }
|
|
|
| - UpdateProfileLabels(&profiles_);
|
| - [tableView_ reloadData];
|
| + // Saving will save to the PDM and the table will refresh when PDM sends
|
| + // notification that the underlying model has changed.
|
| + [self save];
|
| }
|
|
|
| // Edits the selected item, either address or credit card depending on the item
|
| @@ -499,8 +496,9 @@ class PrefObserver : public NotificationObserver {
|
| std::mem_fun_ref(&AutoFillProfile::IsEmpty)),
|
| profiles_.end());
|
|
|
| - UpdateProfileLabels(&profiles_);
|
| - [tableView_ reloadData];
|
| + // Saving will save to the PDM and the table will refresh when PDM sends
|
| + // notification that the underlying model has changed.
|
| + [self save];
|
| }
|
| [sheet orderOut:self];
|
| addressSheetController.reset(nil);
|
| @@ -523,7 +521,10 @@ class PrefObserver : public NotificationObserver {
|
| creditCards_.begin(), creditCards_.end(),
|
| std::mem_fun_ref(&CreditCard::IsEmpty)),
|
| creditCards_.end());
|
| - [tableView_ reloadData];
|
| +
|
| + // Saving will save to the PDM and the table will refresh when PDM sends
|
| + // notification that the underlying model has changed.
|
| + [self save];
|
| }
|
| [sheet orderOut:self];
|
| creditCardSheetController.reset(nil);
|
| @@ -538,7 +539,7 @@ class PrefObserver : public NotificationObserver {
|
|
|
| // NSTableView Delegate method.
|
| - (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row {
|
| - return ![self tableView:tableView isGroupRow:row];
|
| + return [self isProfileRow:row] || [self isCreditCardRow:row];
|
| }
|
|
|
| // NSTableView Delegate method.
|
| @@ -643,23 +644,53 @@ class PrefObserver : public NotificationObserver {
|
| return array;
|
| }
|
|
|
| +// Accessor for |autoFillEnabled| preference state. Note: a checkbox in Nib
|
| +// is bound to this via KVO.
|
| +- (BOOL)autoFillEnabled {
|
| + return autoFillEnabled_.GetValue();
|
| +}
|
| +
|
| +// Setter for |autoFillEnabled| preference state.
|
| +- (void)setAutoFillEnabled:(BOOL)value {
|
| + autoFillEnabled_.SetValueIfNotManaged(value ? true : false);
|
| +}
|
| +
|
| +// Accessor for |auxiliaryEnabled| preference state. Note: a checkbox in Nib
|
| +// is bound to this via KVO.
|
| +- (BOOL)auxiliaryEnabled {
|
| + return auxiliaryEnabled_.GetValue();
|
| +}
|
| +
|
| +// Setter for |auxiliaryEnabled| preference state.
|
| +- (void)setAuxiliaryEnabled:(BOOL)value {
|
| + if ([self autoFillEnabled])
|
| + auxiliaryEnabled_.SetValueIfNotManaged(value ? true : false);
|
| +}
|
| +
|
| @end
|
|
|
| @implementation AutoFillDialogController (ExposedForUnitTests)
|
|
|
| -+ (AutoFillDialogController*)controllerWithObserver:
|
| - (AutoFillDialogObserver*)observer
|
| - profile:(Profile*)profile
|
| - importedProfile:(AutoFillProfile*)importedProfile
|
| - importedCreditCard:(CreditCard*)importedCreditCard {
|
| ++ (AutoFillDialogController*)
|
| + controllerWithObserver:(AutoFillDialogObserver*)observer
|
| + profile:(Profile*)profile {
|
| + profile = profile->GetOriginalProfile();
|
| +
|
| + ProfileControllerMap* map = Singleton<ProfileControllerMap>::get();
|
| + DCHECK(map != NULL);
|
| + ProfileControllerMap::iterator it = map->find(profile);
|
| + if (it == map->end()) {
|
| + // We should have exactly 1 or 0 entry in the map, no more. That is,
|
| + // only one profile can have the AutoFill dialog up at a time.
|
| + DCHECK_EQ(map->size(), 0U);
|
|
|
| // Deallocation is done upon window close. See |windowWillClose:|.
|
| AutoFillDialogController* controller =
|
| - [[self alloc] initWithObserver:observer
|
| - profile:profile
|
| - importedProfile:importedProfile
|
| - importedCreditCard:importedCreditCard];
|
| - return controller;
|
| + [[self alloc] initWithObserver:observer profile:profile];
|
| + it = map->insert(std::make_pair(profile, controller)).first;
|
| + }
|
| +
|
| + return it->second;
|
| }
|
|
|
|
|
| @@ -667,9 +698,7 @@ class PrefObserver : public NotificationObserver {
|
| // |profiles| are non-retained immutable list of AutoFill profiles.
|
| // |creditCards| are non-retained immutable list of credit card info.
|
| - (id)initWithObserver:(AutoFillDialogObserver*)observer
|
| - profile:(Profile*)profile
|
| - importedProfile:(AutoFillProfile*)importedProfile
|
| - importedCreditCard:(CreditCard*)importedCreditCard {
|
| + profile:(Profile*)profile {
|
| DCHECK(profile);
|
| // Use initWithWindowNibPath: instead of initWithWindowNibName: so we
|
| // can override it in a unit test.
|
| @@ -680,22 +709,26 @@ class PrefObserver : public NotificationObserver {
|
| // Initialize member variables based on input.
|
| observer_ = observer;
|
| profile_ = profile;
|
| - importedProfile_ = importedProfile;
|
| - importedCreditCard_ = importedCreditCard;
|
|
|
| // Initialize the preference observer and watch kAutoFillEnabled.
|
| - prefObserver_.reset(
|
| - new AutoFillDialogControllerInternal::PrefObserver(self));
|
| - prefAutoFillEnabled_.Init(prefs::kAutoFillEnabled, profile_->GetPrefs(),
|
| - prefObserver_.get());
|
| + preferenceObserver_.reset(
|
| + new AutoFillDialogControllerInternal::PreferenceObserver(self));
|
| + autoFillEnabled_.Init(prefs::kAutoFillEnabled, profile_->GetPrefs(),
|
| + preferenceObserver_.get());
|
|
|
| - // Call onPrefChanged in order to initialize UI state of the checkbox and
|
| - // save button.
|
| - [self onPrefChanged:prefs::kAutoFillEnabled];
|
| + // Call |preferenceDidChange| in order to initialize UI state of the
|
| + // checkbox.
|
| + [self preferenceDidChange:prefs::kAutoFillEnabled];
|
|
|
| - // Use property here to trigger KVO binding.
|
| - [self setAuxiliaryEnabled:profile_->GetPrefs()->GetBoolean(
|
| - prefs::kAutoFillAuxiliaryProfilesEnabled)];
|
| + // Initialize the preference observer and watch
|
| + // kAutoFillAuxiliaryProfilesEnabled.
|
| + auxiliaryEnabled_.Init(prefs::kAutoFillAuxiliaryProfilesEnabled,
|
| + profile_->GetPrefs(),
|
| + preferenceObserver_.get());
|
| +
|
| + // Call |preferenceDidChange| in order to initialize UI state of the
|
| + // checkbox.
|
| + [self preferenceDidChange:prefs::kAutoFillAuxiliaryProfilesEnabled];
|
|
|
| // Do not use [NSMutableArray array] here; we need predictable destruction
|
| // which will be prevented by having a reference held by an autorelease
|
| @@ -704,10 +737,22 @@ class PrefObserver : public NotificationObserver {
|
| return self;
|
| }
|
|
|
| +// Run modeless.
|
| +- (void)runModelessDialog {
|
| + // Use stored window geometry if it exists.
|
| + if (g_browser_process && g_browser_process->local_state()) {
|
| + sizeSaver_.reset([[WindowSizeAutosaver alloc]
|
| + initWithWindow:[self window]
|
| + prefService:g_browser_process->local_state()
|
| + path:prefs::kAutoFillDialogPlacement]);
|
| + }
|
| +
|
| + [self showWindow:nil];
|
| +}
|
| +
|
| // Close the dialog.
|
| - (void)closeDialog {
|
| - [[self window] close];
|
| - [NSApp stopModal];
|
| + [[self window] performClose:self];
|
| }
|
|
|
| - (AutoFillAddressSheetController*)addressSheetController {
|
| @@ -746,55 +791,66 @@ class PrefObserver : public NotificationObserver {
|
| return [editButton_ isEnabled];
|
| }
|
|
|
| +- (std::vector<AutoFillProfile>&)profiles {
|
| + return profiles_;
|
| +}
|
| +
|
| +- (std::vector<CreditCard>&)creditCards {
|
| + return creditCards_;
|
| +}
|
| +
|
| @end
|
|
|
| @implementation AutoFillDialogController (PrivateMethods)
|
|
|
| -// Run application modal.
|
| -- (void)runModalDialog {
|
| - // Use stored window geometry if it exists.
|
| - if (g_browser_process && g_browser_process->local_state()) {
|
| - sizeSaver_.reset([[WindowSizeAutosaver alloc]
|
| - initWithWindow:[self window]
|
| - prefService:g_browser_process->local_state()
|
| - path:prefs::kAutoFillDialogPlacement]);
|
| - }
|
| +// Called when the user modifies the profiles or credit card information.
|
| +- (void)save {
|
| + // If we have an |observer_| then communicate the changes back, unless
|
| + // AutoFill has been disabled through policy in the mean time.
|
| + if (observer_ && !autoFillManagedAndDisabled_) {
|
| + // Make a working copy of profiles. |OnAutoFillDialogApply| can mutate
|
| + // |profiles_|.
|
| + std::vector<AutoFillProfile> profiles = profiles_;
|
| +
|
| + // Make a working copy of credit cards. |OnAutoFillDialogApply| can mutate
|
| + // |creditCards_|.
|
| + std::vector<CreditCard> creditCards = creditCards_;
|
|
|
| - [NSApp runModalForWindow:[self window]];
|
| + observer_->OnAutoFillDialogApply(&profiles, &creditCards);
|
| + }
|
| }
|
|
|
| - (void)onPersonalDataLoaded:(const std::vector<AutoFillProfile*>&)profiles
|
| creditCards:(const std::vector<CreditCard*>&)creditCards {
|
| - if (importedProfile_) {
|
| - profiles_.push_back(*importedProfile_);
|
| - }
|
| + [self onPersonalDataChanged:profiles creditCards:creditCards];
|
| +}
|
|
|
| - if (importedCreditCard_) {
|
| - creditCards_.push_back(*importedCreditCard_);
|
| - }
|
| +- (void)onPersonalDataChanged:(const std::vector<AutoFillProfile*>&)profiles
|
| + creditCards:(const std::vector<CreditCard*>&)creditCards {
|
| + // Make local copy of |profiles|.
|
| + profiles_.clear();
|
| + for (std::vector<AutoFillProfile*>::const_iterator iter = profiles.begin();
|
| + iter != profiles.end(); ++iter)
|
| + profiles_.push_back(**iter);
|
|
|
| - // If we're not using imported data then use the data fetch from the web db.
|
| - if (!importedProfile_ && !importedCreditCard_) {
|
| - // Make local copy of |profiles|.
|
| - for (std::vector<AutoFillProfile*>::const_iterator iter = profiles.begin();
|
| - iter != profiles.end(); ++iter)
|
| - profiles_.push_back(**iter);
|
| -
|
| - // Make local copy of |creditCards|.
|
| - for (std::vector<CreditCard*>::const_iterator iter = creditCards.begin();
|
| - iter != creditCards.end(); ++iter)
|
| - creditCards_.push_back(**iter);
|
| - }
|
| + // Make local copy of |creditCards|.
|
| + creditCards_.clear();
|
| + for (std::vector<CreditCard*>::const_iterator iter = creditCards.begin();
|
| + iter != creditCards.end(); ++iter)
|
| + creditCards_.push_back(**iter);
|
|
|
| UpdateProfileLabels(&profiles_);
|
| + [tableView_ reloadData];
|
| }
|
|
|
| -- (void)onPrefChanged:(const std::string&)prefName {
|
| - if (prefName == prefs::kAutoFillEnabled) {
|
| - [self setAutoFillEnabled:prefAutoFillEnabled_.GetValue()];
|
| - [self setAutoFillManaged:prefAutoFillEnabled_.IsManaged()];
|
| +- (void)preferenceDidChange:(const std::string&)preferenceName {
|
| + if (preferenceName == prefs::kAutoFillEnabled) {
|
| + [self setAutoFillEnabled:autoFillEnabled_.GetValue()];
|
| + [self setAutoFillManaged:autoFillEnabled_.IsManaged()];
|
| [self setAutoFillManagedAndDisabled:
|
| - prefAutoFillEnabled_.IsManaged() && !prefAutoFillEnabled_.GetValue()];
|
| + autoFillEnabled_.IsManaged() && !autoFillEnabled_.GetValue()];
|
| + } else if (preferenceName == prefs::kAutoFillAuxiliaryProfilesEnabled) {
|
| + [self setAuxiliaryEnabled:auxiliaryEnabled_.GetValue()];
|
| } else {
|
| NOTREACHED();
|
| }
|
|
|