summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorjhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-24 08:32:55 +0000
committerjhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-24 08:32:55 +0000
commit2609bc107a31083c6c88e207d13eaa029d594235 (patch)
tree8331e468eb82a2a9611f388349da4f3565ee3201 /chrome/browser
parent51552aae65a96d19e1adcbf6fe760f102b53a8bf (diff)
downloadchromium_src-2609bc107a31083c6c88e207d13eaa029d594235.zip
chromium_src-2609bc107a31083c6c88e207d13eaa029d594235.tar.gz
chromium_src-2609bc107a31083c6c88e207d13eaa029d594235.tar.bz2
Add the ability to save and remove AutoFill profiles from the AutoFillDialog.
BUG=18201 TEST=PersonalDataManagerTest.SetProfiles Review URL: http://codereview.chromium.org/545175 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36978 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/autofill/autofill_dialog.cc4
-rw-r--r--chrome/browser/autofill/autofill_dialog.h15
-rw-r--r--chrome/browser/autofill/autofill_dialog_gtk.cc172
-rw-r--r--chrome/browser/autofill/autofill_manager.cc37
-rw-r--r--chrome/browser/autofill/autofill_manager.h14
-rw-r--r--chrome/browser/autofill/autofill_profile.cc39
-rw-r--r--chrome/browser/autofill/autofill_profile.h4
-rw-r--r--chrome/browser/autofill/personal_data_manager.cc150
-rw-r--r--chrome/browser/autofill/personal_data_manager.h76
-rw-r--r--chrome/browser/autofill/personal_data_manager_unittest.cc176
-rw-r--r--chrome/browser/profile.cc2
-rw-r--r--chrome/browser/webdata/web_data_service.cc49
-rw-r--r--chrome/browser/webdata/web_data_service.h41
-rw-r--r--chrome/browser/webdata/web_database.cc90
-rw-r--r--chrome/browser/webdata/web_database.h8
-rw-r--r--chrome/browser/webdata/web_database_unittest.cc36
16 files changed, 760 insertions, 153 deletions
diff --git a/chrome/browser/autofill/autofill_dialog.cc b/chrome/browser/autofill/autofill_dialog.cc
index d15cca4..f574987 100644
--- a/chrome/browser/autofill/autofill_dialog.cc
+++ b/chrome/browser/autofill/autofill_dialog.cc
@@ -8,7 +8,7 @@
// function. The last one to implement the function should remove this file.
#if defined(OS_WIN) || defined(OS_MACOSX)
void ShowAutoFillDialog(AutoFillDialogObserver* observer,
- const std::vector<AutoFillProfile>& profiles,
- const std::vector<CreditCard>& credit_cards) {
+ const std::vector<AutoFillProfile*>& profiles,
+ const std::vector<CreditCard*>& credit_cards) {
}
#endif // defined(OS_WIN) || defined(OS_MACOSX)
diff --git a/chrome/browser/autofill/autofill_dialog.h b/chrome/browser/autofill/autofill_dialog.h
index 34006b4..7a5c966 100644
--- a/chrome/browser/autofill/autofill_dialog.h
+++ b/chrome/browser/autofill/autofill_dialog.h
@@ -14,10 +14,11 @@
// the user has applied changes to the AutoFill profile data.
class AutoFillDialogObserver {
public:
- // The user has confirmed changes by clicking "Apply" or "OK".
+ // The user has confirmed changes by clicking "Apply" or "OK". Any of the
+ // parameters may be NULL.
virtual void OnAutoFillDialogApply(
- const std::vector<AutoFillProfile>& profiles,
- const std::vector<CreditCard>& credit_cards) = 0;
+ std::vector<AutoFillProfile>* profiles,
+ std::vector<CreditCard>* credit_cards) = 0;
protected:
virtual ~AutoFillDialogObserver() {}
@@ -29,8 +30,12 @@ class AutoFillDialogObserver {
// changes made to the profile information through the dialog should be
// transferred back into |profiles| and |credit_cards|. |observer| will be
// notified by OnAutoFillDialogAccept when the user has applied changes.
+//
+// The PersonalDataManager owns the contents of these vectors. The lifetime of
+// the contents is until the PersonalDataManager replaces them with new data
+// whenever the web database is updated.
void ShowAutoFillDialog(AutoFillDialogObserver* observer,
- const std::vector<AutoFillProfile>& profiles,
- const std::vector<CreditCard>& credit_cards);
+ const std::vector<AutoFillProfile*>& profiles,
+ const std::vector<CreditCard*>& credit_cards);
#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_DIALOG_H_
diff --git a/chrome/browser/autofill/autofill_dialog_gtk.cc b/chrome/browser/autofill/autofill_dialog_gtk.cc
index 6432f59..33a30a5 100644
--- a/chrome/browser/autofill/autofill_dialog_gtk.cc
+++ b/chrome/browser/autofill/autofill_dialog_gtk.cc
@@ -26,6 +26,10 @@ namespace {
// Style for dialog group titles.
const char kDialogGroupTitleMarkup[] = "<span weight='bold'>%s</span>";
+// The name of the object property used to store an entry widget pointer on
+// another widget.
+const char kButtonDataKey[] = "label-entry";
+
// How far we indent dialog widgets, in pixels.
const int kAutoFillDialogIndent = 5;
@@ -73,6 +77,23 @@ void SetWhiteBackground(GtkWidget* widget) {
gtk_widget_destroy(entry);
}
+string16 GetEntryText(GtkWidget* entry) {
+ return UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(entry)));
+}
+
+void SetEntryText(GtkWidget* entry, const string16& text) {
+ gtk_entry_set_text(GTK_ENTRY(entry), UTF16ToUTF8(text).c_str());
+}
+
+void SetButtonData(GtkWidget* widget, GtkWidget* entry) {
+ g_object_set_data(G_OBJECT(widget), kButtonDataKey, entry);
+}
+
+GtkWidget* GetButtonData(GtkWidget* widget) {
+ return static_cast<GtkWidget*>(
+ g_object_get_data(G_OBJECT(widget), kButtonDataKey));
+}
+
////////////////////////////////////////////////////////////////////////////////
// Form Table helpers.
//
@@ -191,8 +212,8 @@ GtkWidget* FormTableAddLabelEntry(
class AutoFillDialog {
public:
AutoFillDialog(AutoFillDialogObserver* observer,
- const std::vector<AutoFillProfile>& profiles,
- const std::vector<CreditCard>& credit_cards);
+ const std::vector<AutoFillProfile*>& profiles,
+ const std::vector<CreditCard*>& credit_cards);
~AutoFillDialog() {}
// Shows the AutoFill dialog.
@@ -216,6 +237,13 @@ class AutoFillDialog {
// 'clicked' signal handler. We add a new credit card.
static void OnAddCreditCardClicked(GtkButton* button, AutoFillDialog* dialog);
+ // 'clicked' signal handler. We delete the associated address.
+ static void OnDeleteAddressClicked(GtkButton* button, AutoFillDialog* dialog);
+
+ // 'clicked' signal handler. We delete the associated credit card.
+ static void OnDeleteCreditCardClicked(GtkButton* button,
+ AutoFillDialog* dialog);
+
// 'changed' signal handler. We update the title of the expander widget with
// the contents of the label entry widget.
static void OnLabelChanged(GtkEntry* label, GtkWidget* expander);
@@ -236,10 +264,14 @@ class AutoFillDialog {
// Returns a GtkExpander that is added to the appropriate vbox. Each method
// adds the necessary widgets and layout required to fill out information
- // for either an address or a credit card.
- GtkWidget* AddNewAddress();
+ // for either an address or a credit card. The expander will be expanded by
+ // default if |expand| is true.
+ GtkWidget* AddNewAddress(bool expand);
GtkWidget* AddNewCreditCard();
+ // Adds a new address filled out with information from |profile|.
+ void AddAddress(const AutoFillProfile& profile);
+
// The list of current AutoFill profiles.
std::vector<AutoFillProfile> profiles_;
@@ -268,13 +300,18 @@ class AutoFillDialog {
static AutoFillDialog* dialog = NULL;
AutoFillDialog::AutoFillDialog(AutoFillDialogObserver* observer,
- const std::vector<AutoFillProfile>& profiles,
- const std::vector<CreditCard>& credit_cards)
- : profiles_(profiles),
- credit_cards_(credit_cards),
- observer_(observer) {
+ const std::vector<AutoFillProfile*>& profiles,
+ const std::vector<CreditCard*>& credit_cards)
+ : observer_(observer) {
DCHECK(observer);
+ // Copy the profiles.
+ std::vector<AutoFillProfile*>::const_iterator profile;
+ for (profile = profiles.begin(); profile != profiles.end(); ++profile)
+ profiles_.push_back(**profile);
+
+ // TODO(jhawkins): Copy the credit cards.
+
dialog_ = gtk_dialog_new_with_buttons(
l10n_util::GetStringUTF8(IDS_AUTOFILL_DIALOG_TITLE).c_str(),
// AutoFill dialog is shared between all browser windows.
@@ -328,7 +365,9 @@ AutoFillDialog::AutoFillDialog(AutoFillDialogObserver* observer,
G_CALLBACK(OnAddAddressClicked));
gtk_box_pack_start_defaults(GTK_BOX(outer_vbox), addresses_vbox_);
- // TODO(jhawkins): Add addresses from |profiles|.
+ std::vector<AutoFillProfile>::const_iterator iter;
+ for (iter = profiles_.begin(); iter != profiles_.end(); ++iter)
+ AddAddress(*iter);
creditcards_vbox_ = InitGroup(IDS_AUTOFILL_CREDITCARDS_GROUP_NAME,
IDS_AUTOFILL_ADD_CREDITCARD_BUTTON,
@@ -352,10 +391,6 @@ void AutoFillDialog::OnDestroy(GtkWidget* widget,
MessageLoop::current()->DeleteSoon(FROM_HERE, autofill_dialog);
}
-static string16 GetEntryText(GtkWidget* entry) {
- return UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(entry)));
-}
-
static AutoFillProfile AutoFillProfileFromWidgetValues(
const AddressWidgets& widgets) {
// TODO(jhawkins): unique id?
@@ -411,7 +446,8 @@ void AutoFillDialog::OnResponse(GtkDialog* dialog, gint response_id,
}
autofill_dialog->observer_->OnAutoFillDialogApply(
- autofill_dialog->profiles_, autofill_dialog->credit_cards_);
+ &autofill_dialog->profiles_,
+ &autofill_dialog->credit_cards_);
}
if (response_id == GTK_RESPONSE_OK || response_id == GTK_RESPONSE_CANCEL) {
@@ -422,7 +458,7 @@ void AutoFillDialog::OnResponse(GtkDialog* dialog, gint response_id,
// static
void AutoFillDialog::OnAddAddressClicked(GtkButton* button,
AutoFillDialog* dialog) {
- GtkWidget* new_address = dialog->AddNewAddress();
+ GtkWidget* new_address = dialog->AddNewAddress(true);
gtk_box_pack_start(GTK_BOX(dialog->addresses_vbox_), new_address,
FALSE, FALSE, 0);
gtk_widget_show_all(new_address);
@@ -438,6 +474,50 @@ void AutoFillDialog::OnAddCreditCardClicked(GtkButton* button,
}
// static
+void AutoFillDialog::OnDeleteAddressClicked(GtkButton* button,
+ AutoFillDialog* dialog) {
+ GtkWidget* entry = GetButtonData(GTK_WIDGET(button));
+ string16 label = GetEntryText(entry);
+
+ // TODO(jhawkins): Base this on ID.
+
+ // Remove the profile.
+ for (std::vector<AutoFillProfile>::iterator iter = dialog->profiles_.begin();
+ iter != dialog->profiles_.end();
+ ++iter) {
+ if (iter->Label() == label) {
+ dialog->profiles_.erase(iter);
+ break;
+ }
+ }
+
+ // Remove the set of address widgets.
+ for (std::vector<AddressWidgets>::iterator iter =
+ dialog->address_widgets_.begin();
+ iter != dialog->address_widgets_.end();
+ ++iter) {
+ if (iter->label == entry) {
+ dialog->address_widgets_.erase(iter);
+ break;
+ }
+ }
+
+ // Get back to the expander widget.
+ GtkWidget* expander = gtk_widget_get_ancestor(GTK_WIDGET(button),
+ GTK_TYPE_EXPANDER);
+ DCHECK(expander);
+
+ // Destroying the widget will also remove it from the parent container.
+ gtk_widget_destroy(expander);
+}
+
+// static
+void AutoFillDialog::OnDeleteCreditCardClicked(GtkButton* button,
+ AutoFillDialog* dialog) {
+ // TODO(jhawkins): Remove the associated credit card.
+}
+
+// static
void AutoFillDialog::OnLabelChanged(GtkEntry* label, GtkWidget* expander) {
gtk_expander_set_label(GTK_EXPANDER(expander), gtk_entry_get_text(label));
}
@@ -492,18 +572,17 @@ GtkWidget* AutoFillDialog::InitGroupContentArea(int name_id,
gtk_container_add(GTK_CONTAINER(vbox_alignment), vbox);
gtk_container_add(GTK_CONTAINER(frame), vbox_alignment);
- // Make it expand by default.
- gtk_expander_set_expanded(GTK_EXPANDER(expander), true);
-
*content_vbox = vbox;
return expander;
}
-GtkWidget* AutoFillDialog::AddNewAddress() {
+GtkWidget* AutoFillDialog::AddNewAddress(bool expand) {
AddressWidgets widgets = {0};
GtkWidget* vbox;
GtkWidget* address = InitGroupContentArea(IDS_AUTOFILL_NEW_ADDRESS, &vbox);
+ gtk_expander_set_expanded(GTK_EXPANDER(address), expand);
+
GtkWidget* table = InitFormTable(5, 3);
gtk_box_pack_start_defaults(GTK_BOX(vbox), table);
@@ -558,6 +637,8 @@ GtkWidget* AutoFillDialog::AddNewAddress() {
GtkWidget* button = gtk_button_new_with_label(
l10n_util::GetStringUTF8(IDS_AUTOFILL_DELETE_BUTTON).c_str());
+ g_signal_connect(button, "clicked", G_CALLBACK(OnDeleteAddressClicked), this);
+ SetButtonData(button, widgets.label);
GtkWidget* alignment = gtk_alignment_new(0, 0, 0, 0);
gtk_container_add(GTK_CONTAINER(alignment), button);
gtk_box_pack_start_defaults(GTK_BOX(vbox), alignment);
@@ -637,12 +718,59 @@ GtkWidget* AutoFillDialog::AddNewCreditCard() {
return credit_card;
}
+void AutoFillDialog::AddAddress(const AutoFillProfile& profile) {
+ GtkWidget* address = AddNewAddress(false);
+ gtk_expander_set_label(GTK_EXPANDER(address),
+ UTF16ToUTF8(profile.Label()).c_str());
+
+ // We just pushed the widgets to the back of the vector.
+ const AddressWidgets& widgets = address_widgets_.back();
+ SetEntryText(widgets.label, profile.Label());
+ SetEntryText(widgets.first_name,
+ profile.GetFieldText(AutoFillType(NAME_FIRST)));
+ SetEntryText(widgets.middle_name,
+ profile.GetFieldText(AutoFillType(NAME_MIDDLE)));
+ SetEntryText(widgets.last_name,
+ profile.GetFieldText(AutoFillType(NAME_LAST)));
+ SetEntryText(widgets.email,
+ profile.GetFieldText(AutoFillType(EMAIL_ADDRESS)));
+ SetEntryText(widgets.company_name,
+ profile.GetFieldText(AutoFillType(COMPANY_NAME)));
+ SetEntryText(widgets.address_line1,
+ profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE1)));
+ SetEntryText(widgets.address_line2,
+ profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE2)));
+ SetEntryText(widgets.city,
+ profile.GetFieldText(AutoFillType(ADDRESS_HOME_CITY)));
+ SetEntryText(widgets.state,
+ profile.GetFieldText(AutoFillType(ADDRESS_HOME_STATE)));
+ SetEntryText(widgets.zipcode,
+ profile.GetFieldText(AutoFillType(ADDRESS_HOME_ZIP)));
+ SetEntryText(widgets.country,
+ profile.GetFieldText(AutoFillType(ADDRESS_HOME_COUNTRY)));
+ SetEntryText(widgets.phone1,
+ profile.GetFieldText(AutoFillType(PHONE_HOME_COUNTRY_CODE)));
+ SetEntryText(widgets.phone2,
+ profile.GetFieldText(AutoFillType(PHONE_HOME_CITY_CODE)));
+ SetEntryText(widgets.phone3,
+ profile.GetFieldText(AutoFillType(PHONE_HOME_NUMBER)));
+ SetEntryText(widgets.fax1,
+ profile.GetFieldText(AutoFillType(PHONE_FAX_COUNTRY_CODE)));
+ SetEntryText(widgets.fax2,
+ profile.GetFieldText(AutoFillType(PHONE_FAX_CITY_CODE)));
+ SetEntryText(widgets.fax3,
+ profile.GetFieldText(AutoFillType(PHONE_FAX_NUMBER)));
+
+ gtk_box_pack_start(GTK_BOX(addresses_vbox_), address, FALSE, FALSE, 0);
+ gtk_widget_show_all(address);
+}
+
///////////////////////////////////////////////////////////////////////////////
// Factory/finder method:
void ShowAutoFillDialog(AutoFillDialogObserver* observer,
- const std::vector<AutoFillProfile>& profiles,
- const std::vector<CreditCard>& credit_cards) {
+ const std::vector<AutoFillProfile*>& profiles,
+ const std::vector<CreditCard*>& credit_cards) {
if (!dialog) {
dialog = new AutoFillDialog(observer, profiles, credit_cards);
}
diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc
index 1fa94d8..2e067a9 100644
--- a/chrome/browser/autofill/autofill_manager.cc
+++ b/chrome/browser/autofill/autofill_manager.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,7 +10,6 @@
#include "chrome/browser/autofill/autofill_dialog.h"
#include "chrome/browser/autofill/autofill_infobar_delegate.h"
#include "chrome/browser/autofill/form_structure.h"
-#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
@@ -61,9 +60,24 @@ void AutoFillManager::FormFieldValuesSubmitted(
}
void AutoFillManager::OnAutoFillDialogApply(
- const std::vector<AutoFillProfile>& profiles,
- const std::vector<CreditCard>& credit_cards) {
- // TODO(jhawkins): Pass the profile data onto the PersonalDataManager.
+ std::vector<AutoFillProfile>* profiles,
+ std::vector<CreditCard>* credit_cards) {
+ // Save the personal data.
+ personal_data_->SetProfiles(profiles);
+ // TODO(jhawkins): Set the credit cards.
+
+ HandleSubmit();
+}
+
+void AutoFillManager::OnPersonalDataLoaded() {
+ // We might have been alerted that the PersonalDataManager has loaded, so
+ // remove ourselves as observer.
+ personal_data_->RemoveObserver(this);
+
+ // TODO(jhawkins): Actually send in the real credit cards from the personal
+ // data manager.
+ std::vector<CreditCard*> credit_cards;
+ ShowAutoFillDialog(this, personal_data_->profiles(), credit_cards);
}
void AutoFillManager::DeterminePossibleFieldTypes(
@@ -93,13 +107,12 @@ void AutoFillManager::OnInfoBarAccepted() {
PrefService* prefs = tab_contents_->profile()->GetPrefs();
prefs->SetBoolean(prefs::kAutoFillEnabled, true);
- // TODO(jhawkins): Actually send in the real profiles and credit cards from
- // the personal data manager.
- std::vector<AutoFillProfile> profiles;
- std::vector<CreditCard> credit_cards;
- ShowAutoFillDialog(this, profiles, credit_cards);
-
- HandleSubmit();
+ // If the personal data manager has not loaded the data yet, set ourselves as
+ // its observer so that we can listen for the OnPersonalDataLoaded signal.
+ if (!personal_data_->IsDataLoaded())
+ personal_data_->SetObserver(this);
+ else
+ OnPersonalDataLoaded();
}
void AutoFillManager::SaveFormData() {
diff --git a/chrome/browser/autofill/autofill_manager.h b/chrome/browser/autofill/autofill_manager.h
index eb53517..85905c8 100644
--- a/chrome/browser/autofill/autofill_manager.h
+++ b/chrome/browser/autofill/autofill_manager.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,6 +9,7 @@
#include "base/scoped_ptr.h"
#include "chrome/browser/autofill/autofill_dialog.h"
+#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
namespace webkit_glue {
@@ -19,14 +20,14 @@ class AutoFillInfoBarDelegate;
class AutoFillProfile;
class CreditCard;
class FormStructure;
-class PersonalDataManager;
class PrefService;
class TabContents;
// Manages saving and restoring the user's personal information entered into web
// forms.
class AutoFillManager : public RenderViewHostDelegate::AutoFill,
- AutoFillDialogObserver {
+ public AutoFillDialogObserver,
+ public PersonalDataManager::Observer {
public:
explicit AutoFillManager(TabContents* tab_contents);
virtual ~AutoFillManager();
@@ -40,8 +41,11 @@ class AutoFillManager : public RenderViewHostDelegate::AutoFill,
// AutoFillDialogObserver implementation:
virtual void OnAutoFillDialogApply(
- const std::vector<AutoFillProfile>& profiles,
- const std::vector<CreditCard>& credit_cards);
+ std::vector<AutoFillProfile>* profiles,
+ std::vector<CreditCard>* credit_cards);
+
+ // PersonalDataManager::Observer implementation:
+ virtual void OnPersonalDataLoaded();
// Uses heuristics and existing personal data to determine the possible field
// types.
diff --git a/chrome/browser/autofill/autofill_profile.cc b/chrome/browser/autofill/autofill_profile.cc
index a292a41..bfc4fef 100644
--- a/chrome/browser/autofill/autofill_profile.cc
+++ b/chrome/browser/autofill/autofill_profile.cc
@@ -144,8 +144,9 @@ bool AutoFillProfile::operator==(const AutoFillProfile& profile) const {
if (label_ != profile.label_ ||
unique_id_ != profile.unique_id_ ||
- use_billing_address_ != profile.use_billing_address_)
+ use_billing_address_ != profile.use_billing_address_) {
return false;
+ }
for (size_t index = 0; index < arraysize(types); ++index) {
if (GetFieldText(AutoFillType(types[index])) !=
@@ -183,3 +184,39 @@ Address* AutoFillProfile::GetBillingAddress() {
Address* AutoFillProfile::GetHomeAddress() {
return static_cast<Address*>(personal_info_[AutoFillType::ADDRESS_HOME]);
}
+
+// So we can compare AutoFillProfiles with EXPECT_EQ().
+std::ostream& operator<<(std::ostream& os, const AutoFillProfile& profile) {
+ return os
+ << UTF16ToASCII(profile.Label())
+ << " "
+ << profile.unique_id()
+ << " "
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_FIRST)))
+ << " "
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_MIDDLE)))
+ << " "
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_LAST)))
+ << " "
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(EMAIL_ADDRESS)))
+ << " "
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(COMPANY_NAME)))
+ << " "
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE1)))
+ << " "
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE2)))
+ << " "
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_CITY)))
+ << " "
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_STATE)))
+ << " "
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_ZIP)))
+ << " "
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_COUNTRY)))
+ << " "
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(
+ PHONE_HOME_WHOLE_NUMBER)))
+ << " "
+ << UTF16ToUTF8(profile.GetFieldText(AutoFillType(
+ PHONE_FAX_WHOLE_NUMBER)));
+}
diff --git a/chrome/browser/autofill/autofill_profile.h b/chrome/browser/autofill/autofill_profile.h
index a6ed0d3..acc7527 100644
--- a/chrome/browser/autofill/autofill_profile.h
+++ b/chrome/browser/autofill/autofill_profile.h
@@ -53,6 +53,7 @@ class AutoFillProfile : public FormGroup {
void operator=(const AutoFillProfile&);
// Used by tests.
+ // TODO(jhawkins): Move these to private and add the test as a friend.
bool operator==(const AutoFillProfile& profile) const;
void set_label(const string16& label) { label_ = label; }
void set_unique_id(int id) { unique_id_ = id; }
@@ -75,4 +76,7 @@ class AutoFillProfile : public FormGroup {
FormGroupMap personal_info_;
};
+// So we can compare AutoFillProfiles with EXPECT_EQ().
+std::ostream& operator<<(std::ostream& os, const AutoFillProfile& profile);
+
#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_PROFILE_H_
diff --git a/chrome/browser/autofill/personal_data_manager.cc b/chrome/browser/autofill/personal_data_manager.cc
index c60aa6e..e2b2150 100644
--- a/chrome/browser/autofill/personal_data_manager.cc
+++ b/chrome/browser/autofill/personal_data_manager.cc
@@ -1,12 +1,18 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/autofill/personal_data_manager.h"
+#include <algorithm>
+#include <iterator>
+
+#include "base/logging.h"
#include "chrome/browser/autofill/autofill_manager.h"
#include "chrome/browser/autofill/autofill_field.h"
#include "chrome/browser/autofill/form_structure.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/webdata/web_data_service.h"
// The minimum number of fields that must contain user data and have known types
// before autofill will attempt to import the data into a profile.
@@ -19,6 +25,45 @@ static const int kPhoneNumberLength = 7;
static const int kPhoneCityCodeLength = 3;
PersonalDataManager::~PersonalDataManager() {
+ CancelPendingQuery();
+}
+
+void PersonalDataManager::OnWebDataServiceRequestDone(
+ WebDataService::Handle h,
+ const WDTypedResult* result) {
+ // Error from the web database.
+ if (!result)
+ return;
+
+ DCHECK(pending_query_handle_);
+ DCHECK(result->GetType() == AUTOFILL_PROFILES_RESULT);
+ pending_query_handle_ = 0;
+
+ unique_ids_.clear();
+ profiles_.reset();
+ const WDResult<std::vector<AutoFillProfile*> >* r =
+ static_cast<const WDResult<std::vector<AutoFillProfile*> >*>(result);
+ std::vector<AutoFillProfile*> profiles = r->GetValue();
+ for (std::vector<AutoFillProfile*>::iterator iter = profiles.begin();
+ iter != profiles.end(); ++iter) {
+ unique_ids_.insert((*iter)->unique_id());
+ profiles_.push_back(*iter);
+ }
+
+ is_data_loaded_ = true;
+ if (observer_)
+ observer_->OnPersonalDataLoaded();
+}
+
+void PersonalDataManager::SetObserver(PersonalDataManager::Observer* observer) {
+ DCHECK(observer_ == NULL);
+ observer_ = observer;
+}
+
+void PersonalDataManager::RemoveObserver(
+ PersonalDataManager::Observer* observer) {
+ if (observer_ == observer)
+ observer_ = NULL;
}
bool PersonalDataManager::ImportFormData(
@@ -31,7 +76,7 @@ bool PersonalDataManager::ImportFormData(
int importable_fields = 0;
int importable_credit_card_fields = 0;
imported_profile_.reset(new AutoFillProfile(string16(),
- CreateNextUniqueId()));
+ CreateNextUniqueID()));
imported_credit_card_.reset(new CreditCard(string16()));
bool billing_address_info = false;
@@ -104,6 +149,63 @@ bool PersonalDataManager::ImportFormData(
return true;
}
+void PersonalDataManager::SetProfiles(std::vector<AutoFillProfile>* profiles) {
+ if (profile_->IsOffTheRecord())
+ return;
+
+ WebDataService* wds = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
+ if (!wds)
+ return;
+
+ // Remove the unique IDs of the new set of profiles from the unique ID set.
+ for (std::vector<AutoFillProfile>::iterator iter = profiles->begin();
+ iter != profiles->end(); ++iter) {
+ if (iter->unique_id() != 0)
+ unique_ids_.erase(iter->unique_id());
+ }
+
+ // Any remaining IDs are not in the new profile list and should be removed
+ // from the web database.
+ for (std::set<int>::iterator iter = unique_ids_.begin();
+ iter != unique_ids_.end(); ++iter) {
+ wds->RemoveAutoFillProfile(*iter);
+ }
+
+ // Clear the unique IDs. The set of unique IDs is updated for each profile
+ // added to |profile_| below.
+ unique_ids_.clear();
+
+ // Update the web database with the existing profiles. We need to handle
+ // these first so that |unique_ids_| is reset with the IDs of the existing
+ // profiles; otherwise, new profiles added before older profiles can take
+ // their unique ID.
+ for (std::vector<AutoFillProfile>::iterator iter = profiles->begin();
+ iter != profiles->end(); ++iter) {
+ if (iter->unique_id() != 0) {
+ unique_ids_.insert(iter->unique_id());
+ wds->UpdateAutoFillProfile(*iter);
+ }
+ }
+
+ // Add the new profiles to the web database.
+ for (std::vector<AutoFillProfile>::iterator iter = profiles->begin();
+ iter != profiles->end(); ++iter) {
+ // Profile was added by the AutoFill dialog, so we need to set the unique
+ // ID. This also means we need to add this profile to the web DB.
+ if (iter->unique_id() == 0) {
+ iter->set_unique_id(CreateNextUniqueID());
+ wds->AddAutoFillProfile(*iter);
+ }
+ }
+
+ profiles_.reset();
+ for (std::vector<AutoFillProfile>::iterator iter = profiles->begin();
+ iter != profiles->end(); ++iter) {
+ profiles_.push_back(new AutoFillProfile(*iter));
+ }
+}
+
+
void PersonalDataManager::GetPossibleFieldTypes(const string16& text,
FieldTypeSet* possible_types) {
InitializeIfNeeded();
@@ -115,8 +217,8 @@ void PersonalDataManager::GetPossibleFieldTypes(const string16& text,
return;
}
- ScopedVector<FormGroup>::const_iterator iter;
- for (iter = profiles_.begin(); iter != profiles_.end(); ++iter) {
+ for (ScopedVector<AutoFillProfile>::iterator iter = profiles_.begin();
+ iter != profiles_.end(); ++iter) {
const FormGroup* profile = *iter;
if (!profile) {
DLOG(ERROR) << "NULL information in profiles list";
@@ -125,7 +227,8 @@ void PersonalDataManager::GetPossibleFieldTypes(const string16& text,
profile->GetPossibleFieldTypes(clean_info, possible_types);
}
- for (iter = credit_cards_.begin(); iter != credit_cards_.end(); ++iter) {
+ for (ScopedVector<FormGroup>::iterator iter = credit_cards_.begin();
+ iter != credit_cards_.end(); ++iter) {
const FormGroup* credit_card = *iter;
if (!credit_card) {
DLOG(ERROR) << "NULL information in credit cards list";
@@ -143,8 +246,13 @@ bool PersonalDataManager::HasPassword() {
return !password_hash_.empty();
}
-PersonalDataManager::PersonalDataManager()
- : is_initialized_(false) {
+PersonalDataManager::PersonalDataManager(Profile* profile)
+ : profile_(profile),
+ is_initialized_(false),
+ is_data_loaded_(false),
+ pending_query_handle_(0),
+ observer_(NULL) {
+ LoadProfiles();
}
void PersonalDataManager::InitializeIfNeeded() {
@@ -155,7 +263,7 @@ void PersonalDataManager::InitializeIfNeeded() {
// TODO(jhawkins): Load data.
}
-int PersonalDataManager::CreateNextUniqueId() {
+int PersonalDataManager::CreateNextUniqueID() {
// Profile IDs MUST start at 1 to allow 0 as an error value when reading
// the ID from the WebDB (see LoadData()).
int id = 1;
@@ -190,3 +298,29 @@ void PersonalDataManager::ParsePhoneNumber(
// Treat any remaining digits as the country code.
profile->SetInfo(AutoFillType(country_code), *value);
}
+
+void PersonalDataManager::LoadProfiles() {
+ WebDataService* web_data_service =
+ profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
+ if (!web_data_service) {
+ NOTREACHED();
+ return;
+ }
+
+ CancelPendingQuery();
+
+ pending_query_handle_ = web_data_service->GetAutoFillProfiles(this);
+}
+
+void PersonalDataManager::CancelPendingQuery() {
+ if (pending_query_handle_) {
+ WebDataService* web_data_service =
+ profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
+ if (!web_data_service) {
+ NOTREACHED();
+ return;
+ }
+ web_data_service->CancelRequest(pending_query_handle_);
+ }
+ pending_query_handle_ = 0;
+}
diff --git a/chrome/browser/autofill/personal_data_manager.h b/chrome/browser/autofill/personal_data_manager.h
index c28c24b..5821a2a 100644
--- a/chrome/browser/autofill/personal_data_manager.h
+++ b/chrome/browser/autofill/personal_data_manager.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -14,17 +14,41 @@
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/autofill/field_types.h"
+#include "chrome/browser/webdata/web_data_service.h"
class AutoFillManager;
class FormStructure;
+class Profile;
// Handles loading and saving AutoFill profile information to the web database.
// This class also stores the profiles loaded from the database for use during
// AutoFill.
-class PersonalDataManager {
+class PersonalDataManager : public WebDataServiceConsumer {
public:
+ // An interface the PersonalDataManager uses to notify its clients (observers)
+ // when it has finished loading personal data from the web database. Register
+ // the observer via PersonalDataManager::SetObserver.
+ class Observer {
+ public:
+ // Notifies the observer that the PersonalDataManager has finished loading.
+ virtual void OnPersonalDataLoaded() = 0;
+
+ protected:
+ virtual ~Observer() {}
+ };
+
virtual ~PersonalDataManager();
+ // WebDataServiceConsumer implementation:
+ virtual void OnWebDataServiceRequestDone(WebDataService::Handle h,
+ const WDTypedResult* result);
+
+ // Sets the listener to be notified of PersonalDataManager events.
+ void SetObserver(PersonalDataManager::Observer* observer);
+
+ // Removes |observer| as the observer of this PersonalDataManager.
+ void RemoveObserver(PersonalDataManager::Observer* observer);
+
// If AutoFill is able to determine the field types of a significant number
// of field types that contain information in the FormStructures and the user
// has not previously been prompted, the user will be asked if he would like
@@ -33,6 +57,10 @@ class PersonalDataManager {
bool ImportFormData(const std::vector<FormStructure*>& form_structures,
AutoFillManager* autofill_manager);
+ // Sets |profiles_| to the contents of |profiles| and updates the web database
+ // by adding, updating and removing profiles.
+ void SetProfiles(std::vector<AutoFillProfile>* profiles);
+
// Gets the possible field types for the given text, determined by matching
// the text with all known personal information and returning matching types.
void GetPossibleFieldTypes(const string16& text,
@@ -41,19 +69,31 @@ class PersonalDataManager {
// Returns true if the credit card information is stored with a password.
bool HasPassword();
+ // Returns whether the personal data has been loaded from the web database.
+ bool IsDataLoaded() const { return is_data_loaded_; }
+
+ // This PersonalDataManager owns these profiles. Their lifetime is until the
+ // web database is updated with new profile information.
+ const std::vector<AutoFillProfile*>& profiles() { return profiles_.get(); }
+
private:
- // Make sure that only Profile can create an instance of PersonalDataManager.
+ // Make sure that only Profile and the PersonalDataManager tests can create an
+ // instance of PersonalDataManager.
friend class ProfileImpl;
+ friend class PersonalDataManagerTest;
+
+ explicit PersonalDataManager(Profile* profile);
- PersonalDataManager();
+ // Returns the profile of the tab contents.
+ Profile* profile();
// Initializes the object if needed. This should be called at the beginning
// of all the public functions to make sure that the object has been properly
// initialized before use.
void InitializeIfNeeded();
- // This will create and reserve a new unique id for a profile.
- int CreateNextUniqueId();
+ // This will create and reserve a new unique ID for a profile.
+ int CreateNextUniqueID();
// Parses value to extract the components of a phone number and adds them to
// profile.
@@ -65,14 +105,26 @@ class PersonalDataManager {
AutoFillFieldType city_code,
AutoFillFieldType country_code) const;
+ // Loads the saved profiles from the web database.
+ void LoadProfiles();
+
+ // Cancels a pending query to the web database.
+ void CancelPendingQuery();
+
+ // The profile hosting this PersonalDataManager.
+ Profile* profile_;
+
// True if PersonalDataManager is initialized.
bool is_initialized_;
+ // True if personal data has been loaded from the web database.
+ bool is_data_loaded_;
+
// The set of already created unique IDs, used to create a new unique ID.
std::set<int> unique_ids_;
// The loaded profiles.
- ScopedVector<FormGroup> profiles_;
+ ScopedVector<AutoFillProfile> profiles_;
// The loaded credit cards.
ScopedVector<FormGroup> credit_cards_;
@@ -86,6 +138,16 @@ class PersonalDataManager {
// The hash of the password used to store the credit card. This is empty if
// no password exists.
string16 password_hash_;
+
+ // When the manager makes a request from WebDataService, the database
+ // is queried on another thread, we record the query handle until we
+ // get called back.
+ WebDataService::Handle pending_query_handle_;
+
+ // The observer. This can be NULL.
+ Observer* observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(PersonalDataManager);
};
#endif // CHROME_BROWSER_AUTOFILL_PERSONAL_DATA_MANAGER_H_
diff --git a/chrome/browser/autofill/personal_data_manager_unittest.cc b/chrome/browser/autofill/personal_data_manager_unittest.cc
new file mode 100644
index 0000000..5bcbb08
--- /dev/null
+++ b/chrome/browser/autofill/personal_data_manager_unittest.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/autofill/autofill_profile.h"
+#include "chrome/browser/autofill/personal_data_manager.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_observer_mock.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/test/testing_profile.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+ACTION(QuitUIMessageLoop) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ MessageLoop::current()->Quit();
+}
+
+class PersonalDataLoadedObserverMock : public PersonalDataManager::Observer {
+ public:
+ PersonalDataLoadedObserverMock() {}
+ virtual ~PersonalDataLoadedObserverMock() {}
+
+ MOCK_METHOD0(OnPersonalDataLoaded, void());
+};
+
+class PersonalDataManagerTest : public testing::Test {
+ protected:
+ PersonalDataManagerTest()
+ : ui_thread_(ChromeThread::UI, &message_loop_),
+ db_thread_(ChromeThread::DB) {
+ }
+
+ virtual void SetUp() {
+ db_thread_.Start();
+
+ profile_.reset(new TestingProfile);
+ profile_->CreateWebDataService(false);
+
+ ResetPersonalDataManager();
+ }
+
+ virtual void TearDown() {
+ if (profile_.get())
+ profile_.reset(NULL);
+
+ db_thread_.Stop();
+ MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask);
+ MessageLoop::current()->Run();
+ }
+
+ void ResetPersonalDataManager() {
+ personal_data_.reset(new PersonalDataManager(profile_.get()));
+ personal_data_->SetObserver(&personal_data_observer_);
+ }
+
+ static void SetProfileInfo(AutoFillProfile* profile,
+ const char* label, const char* first_name, const char* middle_name,
+ const char* last_name, const char* email, const char* company,
+ const char* address1, const char* address2, const char* city,
+ const char* state, const char* zipcode, const char* country,
+ const char* phone, const char* fax) {
+ profile->set_label(ASCIIToUTF16(label));
+ profile->SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16(first_name));
+ profile->SetInfo(AutoFillType(NAME_MIDDLE), ASCIIToUTF16(middle_name));
+ profile->SetInfo(AutoFillType(NAME_LAST), ASCIIToUTF16(last_name));
+ profile->SetInfo(AutoFillType(EMAIL_ADDRESS), ASCIIToUTF16(email));
+ profile->SetInfo(AutoFillType(COMPANY_NAME), ASCIIToUTF16(company));
+ profile->SetInfo(AutoFillType(ADDRESS_HOME_LINE1), ASCIIToUTF16(address1));
+ profile->SetInfo(AutoFillType(ADDRESS_HOME_LINE2), ASCIIToUTF16(address2));
+ profile->SetInfo(AutoFillType(ADDRESS_HOME_CITY), ASCIIToUTF16(city));
+ profile->SetInfo(AutoFillType(ADDRESS_HOME_STATE), ASCIIToUTF16(state));
+ profile->SetInfo(AutoFillType(ADDRESS_HOME_ZIP), ASCIIToUTF16(zipcode));
+ profile->SetInfo(AutoFillType(ADDRESS_HOME_COUNTRY), ASCIIToUTF16(country));
+ profile->SetInfo(AutoFillType(PHONE_HOME_NUMBER), ASCIIToUTF16(phone));
+ profile->SetInfo(AutoFillType(PHONE_FAX_NUMBER), ASCIIToUTF16(fax));
+ }
+
+ MessageLoopForUI message_loop_;
+ ChromeThread ui_thread_;
+ ChromeThread db_thread_;
+ scoped_ptr<TestingProfile> profile_;
+ scoped_ptr<PersonalDataManager> personal_data_;
+ NotificationRegistrar registrar_;
+ NotificationObserverMock observer_;
+ PersonalDataLoadedObserverMock personal_data_observer_;
+};
+
+// TODO(jhawkins): Test SaveProfiles w/out a WebDataService in the profile.
+TEST_F(PersonalDataManagerTest, SetProfiles) {
+ AutoFillProfile profile0(string16(), 0);
+ SetProfileInfo(&profile0, "Billing", "Marion", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA",
+ "91601", "US", "12345678910", "01987654321");
+
+ AutoFillProfile profile1(string16(), 0);
+ SetProfileInfo(&profile1, "Home", "Josephine", "Alicia", "Saenz",
+ "joewayne@me.xyz", "Fox", "903 Apple Ct.", NULL, "Orlando", "FL", "32801",
+ "US", "19482937549", "13502849239");
+
+ AutoFillProfile profile2(string16(), 0);
+ SetProfileInfo(&profile2, "Work", "Josephine", "Alicia", "Saenz",
+ "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5", "Orlando", "FL",
+ "32801", "US", "19482937549", "13502849239");
+
+ // This will verify that the web database has been loaded and the notification
+ // sent out.
+ EXPECT_CALL(personal_data_observer_,
+ OnPersonalDataLoaded()).WillOnce(QuitUIMessageLoop());
+
+ // The message loop will exit when the mock observer is notified.
+ MessageLoop::current()->Run();
+
+ // Add the three test profiles to the database.
+ std::vector<AutoFillProfile> update;
+ update.push_back(profile0);
+ update.push_back(profile1);
+ personal_data_->SetProfiles(&update);
+
+ // The PersonalDataManager will update the unique IDs when saving the
+ // profiles, so we have to update the expectations.
+ profile0.set_unique_id(update[0].unique_id());
+ profile1.set_unique_id(update[1].unique_id());
+
+ const std::vector<AutoFillProfile*>& results1 = personal_data_->profiles();
+ ASSERT_EQ(2U, results1.size());
+ EXPECT_EQ(profile0, *results1.at(0));
+ EXPECT_EQ(profile1, *results1.at(1));
+
+ // Three operations in one:
+ // - Update profile0
+ // - Remove profile1
+ // - Add profile2
+ profile0.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("John"));
+ update.clear();
+ update.push_back(profile0);
+ update.push_back(profile2);
+ personal_data_->SetProfiles(&update);
+
+ // Set the expected unique ID for profile2.
+ profile2.set_unique_id(update[1].unique_id());
+
+ // AutoFillProfile IDs are re-used, so the third profile to be added will have
+ // a unique ID that matches the old unique ID of the removed profile1, even
+ // though that ID has already been used.
+ const std::vector<AutoFillProfile*>& results2 = personal_data_->profiles();
+ ASSERT_EQ(2U, results2.size());
+ EXPECT_EQ(profile0, *results2.at(0));
+ EXPECT_EQ(profile2, *results2.at(1));
+ EXPECT_EQ(profile2.unique_id(), profile1.unique_id());
+
+ // Reset the PersonalDataManager. This tests that the personal data was saved
+ // to the web database, and that we can load the profiles from the web
+ // database.
+ ResetPersonalDataManager();
+
+ // This will verify that the web database has been loaded and the notification
+ // sent out.
+ EXPECT_CALL(personal_data_observer_,
+ OnPersonalDataLoaded()).WillOnce(QuitUIMessageLoop());
+
+ // The message loop will exit when the PersonalDataLoadedObserver is notified.
+ MessageLoop::current()->Run();
+
+ // Verify that we've loaded the profiles from the web database.
+ const std::vector<AutoFillProfile*>& results3 = personal_data_->profiles();
+ ASSERT_EQ(2U, results3.size());
+ EXPECT_EQ(profile0, *results3.at(0));
+ EXPECT_EQ(profile2, *results3.at(1));
+}
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc
index 8c9e9c7..a6861e9 100644
--- a/chrome/browser/profile.cc
+++ b/chrome/browser/profile.cc
@@ -1095,7 +1095,7 @@ bool ProfileImpl::HasCreatedDownloadManager() const {
PersonalDataManager* ProfileImpl::GetPersonalDataManager() {
if (!personal_data_manager_.get()) {
- personal_data_manager_.reset(new PersonalDataManager);
+ personal_data_manager_.reset(new PersonalDataManager(this));
}
return personal_data_manager_.get();
}
diff --git a/chrome/browser/webdata/web_data_service.cc b/chrome/browser/webdata/web_data_service.cc
index 3601b8b..b630a91 100644
--- a/chrome/browser/webdata/web_data_service.cc
+++ b/chrome/browser/webdata/web_data_service.cc
@@ -160,10 +160,10 @@ void WebDataService::UpdateAutoFillProfile(const AutoFillProfile& profile) {
request));
}
-void WebDataService::RemoveAutoFillProfile(const AutoFillProfile& profile) {
- GenericRequest<AutoFillProfile>* request =
- new GenericRequest<AutoFillProfile>(
- this, GetNextRequestHandle(), NULL, profile);
+void WebDataService::RemoveAutoFillProfile(int profile_id) {
+ GenericRequest<int>* request =
+ new GenericRequest<int>(
+ this, GetNextRequestHandle(), NULL, profile_id);
RegisterRequest(request);
ScheduleTask(NewRunnableMethod(this,
&WebDataService::RemoveAutoFillProfileImpl,
@@ -183,6 +183,18 @@ WebDataService::Handle WebDataService::GetAutoFillProfileForLabel(
return request->GetHandle();
}
+WebDataService::Handle WebDataService::GetAutoFillProfiles(
+ WebDataServiceConsumer* consumer) {
+ WebDataRequest* request =
+ new WebDataRequest(this, GetNextRequestHandle(), consumer);
+ RegisterRequest(request);
+ ScheduleTask(
+ NewRunnableMethod(this,
+ &WebDataService::GetAutoFillProfilesImpl,
+ request));
+ return request->GetHandle();
+}
+
void WebDataService::RequestCompleted(Handle h) {
pending_lock_.Acquire();
RequestMap::iterator i = pending_requests_.find(h);
@@ -472,10 +484,21 @@ void WebDataService::InitializeDatabaseIfNecessary() {
return;
}
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this, &WebDataService::NotifyDatabaseLoadedOnUIThread));
+
db_ = db;
db_->BeginTransaction();
}
+void WebDataService::NotifyDatabaseLoadedOnUIThread() {
+ // Notify that the database has been initialized.
+ NotificationService::current()->Notify(NotificationType::WEB_DATABASE_LOADED,
+ NotificationService::AllSources(),
+ NotificationService::NoDetails());
+}
+
void WebDataService::ShutdownDatabase() {
should_commit_ = false;
@@ -734,11 +757,11 @@ void WebDataService::UpdateAutoFillProfileImpl(
}
void WebDataService::RemoveAutoFillProfileImpl(
- GenericRequest<AutoFillProfile>* request) {
+ GenericRequest<int>* request) {
InitializeDatabaseIfNecessary();
if (db_ && !request->IsCancelled()) {
- const AutoFillProfile& profile = request->GetArgument();
- if (!db_->RemoveAutoFillProfile(profile))
+ int profile_id = request->GetArgument();
+ if (!db_->RemoveAutoFillProfile(profile_id))
NOTREACHED();
ScheduleCommit();
}
@@ -758,6 +781,18 @@ void WebDataService::GetAutoFillProfileForLabelImpl(WebDataRequest* request,
request->RequestComplete();
}
+void WebDataService::GetAutoFillProfilesImpl(WebDataRequest* request) {
+ InitializeDatabaseIfNecessary();
+ if (db_ && !request->IsCancelled()) {
+ std::vector<AutoFillProfile*> profiles;
+ db_->GetAutoFillProfiles(&profiles);
+ request->SetResult(
+ new WDResult<std::vector<AutoFillProfile*> >(AUTOFILL_PROFILES_RESULT,
+ profiles));
+ }
+ request->RequestComplete();
+}
+
////////////////////////////////////////////////////////////////////////////////
//
// Web Apps implementation.
diff --git a/chrome/browser/webdata/web_data_service.h b/chrome/browser/webdata/web_data_service.h
index 9ab3c01..ff356e0 100644
--- a/chrome/browser/webdata/web_data_service.h
+++ b/chrome/browser/webdata/web_data_service.h
@@ -54,17 +54,18 @@ struct PasswordForm;
// Result types
//
typedef enum {
- BOOL_RESULT = 1, // WDResult<bool>
- KEYWORDS_RESULT, // WDResult<WDKeywordsResult>
- INT64_RESULT, // WDResult<int64>
- PASSWORD_RESULT, // WDResult<std::vector<PasswordForm*>>
+ BOOL_RESULT = 1, // WDResult<bool>
+ KEYWORDS_RESULT, // WDResult<WDKeywordsResult>
+ INT64_RESULT, // WDResult<int64>
+ PASSWORD_RESULT, // WDResult<std::vector<PasswordForm*>>
#if defined(OS_WIN)
- PASSWORD_IE7_RESULT, // WDResult<IE7PasswordInfo>
+ PASSWORD_IE7_RESULT, // WDResult<IE7PasswordInfo>
#endif
- WEB_APP_IMAGES, // WDResult<WDAppImagesResult>
- AUTOFILL_VALUE_RESULT, // WDResult<std::vector<string16>>
- AUTOFILL_CHANGES, // WDResult<std::vector<AutofillChange>>
- AUTOFILL_PROFILE_RESULT // WDResult<AutoFillProfile>
+ WEB_APP_IMAGES, // WDResult<WDAppImagesResult>
+ AUTOFILL_VALUE_RESULT, // WDResult<std::vector<string16>>
+ AUTOFILL_CHANGES, // WDResult<std::vector<AutofillChange>>
+ AUTOFILL_PROFILE_RESULT, // WDResult<AutoFillProfile>
+ AUTOFILL_PROFILES_RESULT // WDResult<std::vector<AutoFillProfile*>>
} WDResultType;
typedef std::vector<AutofillChange> AutofillChangeList;
@@ -85,7 +86,7 @@ struct WDKeywordsResult {
// Identifies the ID of the TemplateURL that is the default search. A value of
// 0 indicates there is no default search provider.
int64 default_search_provider_id;
- // Version of the builin keywords. A value of 0 indicates a first run.
+ // Version of the built-in keywords. A value of 0 indicates a first run.
int builtin_keyword_version;
};
@@ -414,14 +415,21 @@ class WebDataService
void UpdateAutoFillProfile(const AutoFillProfile& profile);
// Schedules a task to remove an AutoFill profile from the web database.
- void RemoveAutoFillProfile(const AutoFillProfile& profile);
+ // |profile_id| is the unique ID of the profile to remove.
+ void RemoveAutoFillProfile(int profile_id);
- // Initiates the request for an AutoFill profile with label |label. The
+ // Initiates the request for an AutoFill profile with label |label|. The
// method OnWebDataServiceRequestDone of |consumer| gets called back when the
// request is finished, with the profile included in the argument |result|.
Handle GetAutoFillProfileForLabel(const string16& label,
WebDataServiceConsumer* consumer);
+ // Initiates the request for all AutoFill profiles. The method
+ // OnWebDataServiceRequestDone of |consumer| gets called when the request is
+ // finished, with the profiles included in the argument |result|. The
+ // consumer owns the profiles.
+ Handle GetAutoFillProfiles(WebDataServiceConsumer* consumer);
+
// Testing
#ifdef UNIT_TEST
void set_failed_init(bool value) { failed_init_ = value; }
@@ -464,6 +472,9 @@ class WebDataService
// Initialize the database, if it hasn't already been initialized.
void InitializeDatabaseIfNecessary();
+ // The notification method.
+ void NotifyDatabaseLoadedOnUIThread();
+
// Commit any pending transaction and deletes the database.
void ShutdownDatabase();
@@ -516,9 +527,10 @@ class WebDataService
GenericRequest2<string16, string16>* request);
void AddAutoFillProfileImpl(GenericRequest<AutoFillProfile>* request);
void UpdateAutoFillProfileImpl(GenericRequest<AutoFillProfile>* request);
- void RemoveAutoFillProfileImpl(GenericRequest<AutoFillProfile>* request);
+ void RemoveAutoFillProfileImpl(GenericRequest<int>* request);
void GetAutoFillProfileForLabelImpl(WebDataRequest* request,
const string16& label);
+ void GetAutoFillProfilesImpl(WebDataRequest* request);
//////////////////////////////////////////////////////////////////////////////
//
@@ -591,6 +603,9 @@ class WebDataServiceConsumer {
// not be opened. The result object is destroyed after this call.
virtual void OnWebDataServiceRequestDone(WebDataService::Handle h,
const WDTypedResult* result) = 0;
+
+ protected:
+ virtual ~WebDataServiceConsumer() {}
};
#endif // CHROME_BROWSER_WEBDATA_WEB_DATA_SERVICE_H__
diff --git a/chrome/browser/webdata/web_database.cc b/chrome/browser/webdata/web_database.cc
index 58068e8..019c7d3 100644
--- a/chrome/browser/webdata/web_database.cc
+++ b/chrome/browser/webdata/web_database.cc
@@ -1227,11 +1227,45 @@ bool WebDatabase::AddAutoFillProfile(const AutoFillProfile& profile) {
return false;
}
- return true;
+ return s.Succeeded();
+}
+
+static AutoFillProfile* AutoFillProfileFromStatement(const sql::Statement& s) {
+ AutoFillProfile* profile = new AutoFillProfile(
+ ASCIIToUTF16(s.ColumnString(0)), s.ColumnInt(1));
+ profile->SetInfo(AutoFillType(NAME_FIRST),
+ ASCIIToUTF16(s.ColumnString(2)));
+ profile->SetInfo(AutoFillType(NAME_MIDDLE),
+ ASCIIToUTF16(s.ColumnString(3)));
+ profile->SetInfo(AutoFillType(NAME_LAST),
+ ASCIIToUTF16(s.ColumnString(4)));
+ profile->SetInfo(AutoFillType(EMAIL_ADDRESS),
+ ASCIIToUTF16(s.ColumnString(5)));
+ profile->SetInfo(AutoFillType(COMPANY_NAME),
+ ASCIIToUTF16(s.ColumnString(6)));
+ profile->SetInfo(AutoFillType(ADDRESS_HOME_LINE1),
+ ASCIIToUTF16(s.ColumnString(7)));
+ profile->SetInfo(AutoFillType(ADDRESS_HOME_LINE2),
+ ASCIIToUTF16(s.ColumnString(8)));
+ profile->SetInfo(AutoFillType(ADDRESS_HOME_CITY),
+ ASCIIToUTF16(s.ColumnString(9)));
+ profile->SetInfo(AutoFillType(ADDRESS_HOME_STATE),
+ ASCIIToUTF16(s.ColumnString(10)));
+ profile->SetInfo(AutoFillType(ADDRESS_HOME_ZIP),
+ ASCIIToUTF16(s.ColumnString(11)));
+ profile->SetInfo(AutoFillType(ADDRESS_HOME_COUNTRY),
+ ASCIIToUTF16(s.ColumnString(12)));
+ profile->SetInfo(AutoFillType(PHONE_HOME_NUMBER),
+ ASCIIToUTF16(s.ColumnString(13)));
+ profile->SetInfo(AutoFillType(PHONE_FAX_NUMBER),
+ ASCIIToUTF16(s.ColumnString(14)));
+
+ return profile;
}
bool WebDatabase::GetAutoFillProfileForLabel(const string16& label,
AutoFillProfile** profile) {
+ DCHECK(profile);
sql::Statement s(db_.GetUniqueStatement(
"SELECT * FROM autofill_profiles "
"WHERE label = ?"));
@@ -1244,36 +1278,26 @@ bool WebDatabase::GetAutoFillProfileForLabel(const string16& label,
if (!s.Step())
return false;
- *profile = new AutoFillProfile(label, s.ColumnInt(1));
- AutoFillProfile* profile_ptr = *profile;
- profile_ptr->SetInfo(AutoFillType(NAME_FIRST),
- ASCIIToUTF16(s.ColumnString(2)));
- profile_ptr->SetInfo(AutoFillType(NAME_MIDDLE),
- ASCIIToUTF16(s.ColumnString(3)));
- profile_ptr->SetInfo(AutoFillType(NAME_LAST),
- ASCIIToUTF16(s.ColumnString(4)));
- profile_ptr->SetInfo(AutoFillType(EMAIL_ADDRESS),
- ASCIIToUTF16(s.ColumnString(5)));
- profile_ptr->SetInfo(AutoFillType(COMPANY_NAME),
- ASCIIToUTF16(s.ColumnString(6)));
- profile_ptr->SetInfo(AutoFillType(ADDRESS_HOME_LINE1),
- ASCIIToUTF16(s.ColumnString(7)));
- profile_ptr->SetInfo(AutoFillType(ADDRESS_HOME_LINE2),
- ASCIIToUTF16(s.ColumnString(8)));
- profile_ptr->SetInfo(AutoFillType(ADDRESS_HOME_CITY),
- ASCIIToUTF16(s.ColumnString(9)));
- profile_ptr->SetInfo(AutoFillType(ADDRESS_HOME_STATE),
- ASCIIToUTF16(s.ColumnString(10)));
- profile_ptr->SetInfo(AutoFillType(ADDRESS_HOME_ZIP),
- ASCIIToUTF16(s.ColumnString(11)));
- profile_ptr->SetInfo(AutoFillType(ADDRESS_HOME_COUNTRY),
- ASCIIToUTF16(s.ColumnString(12)));
- profile_ptr->SetInfo(AutoFillType(PHONE_HOME_NUMBER),
- ASCIIToUTF16(s.ColumnString(13)));
- profile_ptr->SetInfo(AutoFillType(PHONE_FAX_NUMBER),
- ASCIIToUTF16(s.ColumnString(14)));
+ *profile = AutoFillProfileFromStatement(s);
- return true;
+ return s.Succeeded();
+}
+
+bool WebDatabase::GetAutoFillProfiles(
+ std::vector<AutoFillProfile*>* profiles) {
+ DCHECK(profiles);
+ profiles->clear();
+
+ sql::Statement s(db_.GetUniqueStatement("SELECT * FROM autofill_profiles"));
+ if (!s) {
+ NOTREACHED() << "Statement prepare failed";
+ return false;
+ }
+
+ while (s.Step())
+ profiles->push_back(AutoFillProfileFromStatement(s));
+
+ return s.Succeeded();
}
bool WebDatabase::UpdateAutoFillProfile(const AutoFillProfile& profile) {
@@ -1294,8 +1318,8 @@ bool WebDatabase::UpdateAutoFillProfile(const AutoFillProfile& profile) {
return s.Run();
}
-bool WebDatabase::RemoveAutoFillProfile(const AutoFillProfile& profile) {
- DCHECK(profile.unique_id());
+bool WebDatabase::RemoveAutoFillProfile(int profile_id) {
+ DCHECK_NE(0, profile_id);
sql::Statement s(db_.GetUniqueStatement(
"DELETE FROM autofill_profiles WHERE unique_id = ?"));
if (!s) {
@@ -1303,7 +1327,7 @@ bool WebDatabase::RemoveAutoFillProfile(const AutoFillProfile& profile) {
return false;
}
- s.BindInt(0, profile.unique_id());
+ s.BindInt(0, profile_id);
return s.Run();
}
diff --git a/chrome/browser/webdata/web_database.h b/chrome/browser/webdata/web_database.h
index 70eb235..2820beb1 100644
--- a/chrome/browser/webdata/web_database.h
+++ b/chrome/browser/webdata/web_database.h
@@ -204,13 +204,17 @@ class WebDatabase {
// Updates the database values for the specified profile.
bool UpdateAutoFillProfile(const AutoFillProfile& profile);
- // Removes a row from the autofill_profiles table.
- bool RemoveAutoFillProfile(const AutoFillProfile& profile);
+ // Removes a row from the autofill_profiles table. |profile_id| is the
+ // unique ID of the profile to remove.
+ bool RemoveAutoFillProfile(int profile_id);
// Retrieves a profile with label |label|. The caller owns |profile|.
bool GetAutoFillProfileForLabel(const string16& label,
AutoFillProfile** profile);
+ // Retrieves all profiles in the database. Caller owns the returned profiles.
+ bool GetAutoFillProfiles(std::vector<AutoFillProfile*>* profiles);
+
//////////////////////////////////////////////////////////////////////////////
//
// Web Apps
diff --git a/chrome/browser/webdata/web_database_unittest.cc b/chrome/browser/webdata/web_database_unittest.cc
index d086b1c..c0f340d 100644
--- a/chrome/browser/webdata/web_database_unittest.cc
+++ b/chrome/browser/webdata/web_database_unittest.cc
@@ -52,40 +52,6 @@ std::ostream& operator<<(std::ostream& os, const AutofillChange& change) {
return os << " " << change.key();
}
-// So we can compare AutoFillProfiles with EXPECT_EQ().
-std::ostream& operator<<(std::ostream& os, const AutoFillProfile& profile) {
- return os
- << UTF16ToASCII(profile.Label())
- << " "
- << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_FIRST)))
- << " "
- << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_MIDDLE)))
- << " "
- << UTF16ToUTF8(profile.GetFieldText(AutoFillType(NAME_LAST)))
- << " "
- << UTF16ToUTF8(profile.GetFieldText(AutoFillType(EMAIL_ADDRESS)))
- << " "
- << UTF16ToUTF8(profile.GetFieldText(AutoFillType(COMPANY_NAME)))
- << " "
- << UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE1)))
- << " "
- << UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE2)))
- << " "
- << UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_CITY)))
- << " "
- << UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_STATE)))
- << " "
- << UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_ZIP)))
- << " "
- << UTF16ToUTF8(profile.GetFieldText(AutoFillType(ADDRESS_HOME_COUNTRY)))
- << " "
- << UTF16ToUTF8(profile.GetFieldText(AutoFillType(
- PHONE_HOME_WHOLE_NUMBER)))
- << " "
- << UTF16ToUTF8(profile.GetFieldText(AutoFillType(
- PHONE_FAX_WHOLE_NUMBER)));
-}
-
class WebDatabaseTest : public testing::Test {
protected:
typedef std::vector<AutofillChange> AutofillChangeList;
@@ -963,7 +929,7 @@ TEST_F(WebDatabaseTest, AutoFillProfile) {
delete db_profile;
// Remove the 'Billing' profile.
- EXPECT_TRUE(db.RemoveAutoFillProfile(billing_profile));
+ EXPECT_TRUE(db.RemoveAutoFillProfile(billing_profile.unique_id()));
EXPECT_FALSE(db.GetAutoFillProfileForLabel(ASCIIToUTF16("Billing"),
&db_profile));
}