Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(421)

Unified Diff: chrome/browser/autofill/autofill_dialog_controller_mac.mm

Issue 3302015: AutoFill Mac dialog should be non-modal (Closed)
Patch Set: Indent. Created 10 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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();
}

Powered by Google App Engine
This is Rietveld 408576698