Index: chrome/browser/autofill/autofill_dialog_gtk.cc |
diff --git a/chrome/browser/autofill/autofill_dialog_gtk.cc b/chrome/browser/autofill/autofill_dialog_gtk.cc |
index 48a6903187765a71fb858841f13287039be00dcb..ec8a1fec68520a4c7826cfe8db1ba848dd82d4e1 100644 |
--- a/chrome/browser/autofill/autofill_dialog_gtk.cc |
+++ b/chrome/browser/autofill/autofill_dialog_gtk.cc |
@@ -6,9 +6,11 @@ |
#include <gtk/gtk.h> |
+#include <algorithm> |
#include <string> |
#include <vector> |
+#include "app/gtk_signal.h" |
#include "app/l10n_util.h" |
#include "base/logging.h" |
#include "base/message_loop.h" |
@@ -22,219 +24,84 @@ |
#include "chrome/browser/browser.h" |
#include "chrome/browser/browser_list.h" |
#include "chrome/browser/gtk/gtk_chrome_link_button.h" |
+#include "chrome/browser/gtk/gtk_tree.h" |
#include "chrome/browser/gtk/gtk_util.h" |
-#include "chrome/browser/gtk/options/options_layout_gtk.h" |
+#include "chrome/browser/metrics/user_metrics.h" |
+#include "chrome/browser/pref_member.h" |
+#include "chrome/browser/pref_service.h" |
#include "chrome/browser/profile.h" |
+#include "chrome/common/notification_details.h" |
+#include "chrome/common/notification_observer.h" |
+#include "chrome/common/notification_type.h" |
#include "chrome/common/pref_names.h" |
#include "gfx/gtk_util.h" |
#include "grit/chromium_strings.h" |
#include "grit/generated_resources.h" |
#include "grit/locale_settings.h" |
-namespace { |
- |
-// 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; |
- |
-// The resource id for the 'Learn more' link button. |
-const gint kAutoFillDialogLearnMoreLink = 1; |
- |
-// All of these widgets are GtkEntrys. |
-typedef struct _AddressWidgets { |
- GtkWidget* label; |
- GtkWidget* full_name; |
- GtkWidget* email; |
- GtkWidget* company_name; |
- GtkWidget* address_line1; |
- GtkWidget* address_line2; |
- GtkWidget* city; |
- GtkWidget* state; |
- GtkWidget* zipcode; |
- GtkWidget* country; |
- GtkWidget* phone; |
- GtkWidget* fax; |
-} AddressWidgets; |
- |
-// All of these widgets are GtkEntrys except for |billing_address|, which is |
-// a GtkComboBox. |
-typedef struct _CreditCardWidgets { |
- GtkWidget* label; |
- GtkWidget* name_on_card; |
- GtkWidget* card_number; |
- GtkWidget* expiration_month; |
- GtkWidget* expiration_year; |
- GtkWidget* billing_address; |
- GtkWidget* phone; |
- string16 original_card_number; |
-} CreditCardWidgets; |
- |
-// Adds an alignment around |widget| which indents the widget by |offset|. |
-GtkWidget* IndentWidget(GtkWidget* widget, int offset) { |
- GtkWidget* alignment = gtk_alignment_new(0, 0, 0, 0); |
- gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, |
- offset, 0); |
- gtk_container_add(GTK_CONTAINER(alignment), widget); |
- return alignment; |
-} |
- |
-// Makes sure we use the gtk theme colors by loading the base color of an entry |
-// widget. |
-void SetWhiteBackground(GtkWidget* widget) { |
- GtkWidget* entry = gtk_entry_new(); |
- gtk_widget_ensure_style(entry); |
- GtkStyle* style = gtk_widget_get_style(entry); |
- gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, |
- &style->base[GTK_STATE_NORMAL]); |
- 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. |
-// |
-// The following functions can be used to create a form with labeled widgets. |
-// |
- |
-// Creates a form table with dimensions |rows| x |cols|. |
-GtkWidget* InitFormTable(int rows, int cols) { |
- // We have two table rows per form table row. |
- GtkWidget* table = gtk_table_new(rows * 2, cols, false); |
- gtk_table_set_row_spacings(GTK_TABLE(table), gtk_util::kControlSpacing); |
- gtk_table_set_col_spacings(GTK_TABLE(table), gtk_util::kFormControlSpacing); |
- |
- // Leave no space between the label and the widget. |
- for (int i = 0; i < rows; i++) |
- gtk_table_set_row_spacing(GTK_TABLE(table), i * 2, 0); |
- |
- return table; |
-} |
- |
-// Sets the label of the form widget at |row|,|col|. The label is |len| columns |
-// long. |
-void FormTableSetLabel( |
- GtkWidget* table, int row, int col, int len, int label_id) { |
- // We have two table rows per form table row. |
- row *= 2; |
- |
- std::string text; |
- if (label_id) |
- text = l10n_util::GetStringUTF8(label_id); |
- GtkWidget* label = gtk_label_new(text.c_str()); |
- gtk_misc_set_alignment(GTK_MISC(label), 0, 0); |
- gtk_table_attach(GTK_TABLE(table), label, |
- col, col + len, // Left col, right col. |
- row, row + 1, // Top row, bottom row. |
- GTK_FILL, GTK_FILL, // Options. |
- 0, 0); // Padding. |
-} |
- |
-// Sets the form widget at |row|,|col|. The widget fills up |len| columns. If |
-// |expand| is true, the widget will expand to fill all of the extra space in |
-// the table row. |
-void FormTableSetWidget(GtkWidget* table, |
- GtkWidget* widget, |
- int row, int col, |
- int len, bool expand) { |
- const GtkAttachOptions expand_option = |
- static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND); |
- GtkAttachOptions xoption = (expand) ? expand_option : GTK_FILL; |
- |
- // We have two table rows per form table row. |
- row *= 2; |
- gtk_table_attach(GTK_TABLE(table), widget, |
- col, col + len, // Left col, right col. |
- row + 1, row + 2, // Top row, bottom row. |
- xoption, GTK_FILL, // Options. |
- 0, 0); // Padding. |
-} |
- |
-// Adds a labeled entry box to the form table at |row|,|col|. The entry widget |
-// fills up |len| columns. The returned widget is owned by |table| and should |
-// not be destroyed. |
-GtkWidget* FormTableAddEntry( |
- GtkWidget* table, int row, int col, int len, int label_id) { |
- FormTableSetLabel(table, row, col, len, label_id); |
- |
- GtkWidget* entry = gtk_entry_new(); |
- FormTableSetWidget(table, entry, row, col, len, false); |
- |
- return entry; |
-} |
- |
-// Adds a labeled entry box to the form table that will expand to fill extra |
-// space in the table row. |
-GtkWidget* FormTableAddExpandedEntry( |
- GtkWidget* table, int row, int col, int len, int label_id) { |
- FormTableSetLabel(table, row, col, len, label_id); |
- |
- GtkWidget* entry = gtk_entry_new(); |
- FormTableSetWidget(table, entry, row, col, len, true); |
- |
- return entry; |
-} |
- |
-// Adds a sized entry box to the form table. The entry widget width is set to |
-// |char_len|. |
-GtkWidget* FormTableAddSizedEntry( |
- GtkWidget* table, int row, int col, int char_len, int label_id) { |
- GtkWidget* entry = FormTableAddEntry(table, row, col, 1, label_id); |
- gtk_entry_set_width_chars(GTK_ENTRY(entry), char_len); |
- return entry; |
-} |
- |
-// Like FormTableAddEntry, but connects to the 'changed' signal. |changed| is a |
-// callback to handle the 'changed' signal that is emitted when the user edits |
-// the entry. |expander| is the expander widget that will be sent to the |
-// callback as the user data. |
-GtkWidget* FormTableAddLabelEntry( |
- GtkWidget* table, int row, int col, int len, int label_id, |
- GtkWidget* expander, GCallback changed) { |
- FormTableSetLabel(table, row, col, len, label_id); |
+// Shows the editor for adding/editing an AutoFillProfile. If |
+// |auto_fill_profile| is NULL, a new AutoFillProfile should be created. |
+void ShowAutoFillProfileEditor(gfx::NativeView parent, |
+ AutoFillDialogObserver* observer, |
+ Profile* profile, |
+ AutoFillProfile* auto_fill_profile); |
- GtkWidget* entry = gtk_entry_new(); |
- g_signal_connect(entry, "changed", changed, expander); |
- FormTableSetWidget(table, entry, row, col, len, false); |
+// Shows the editor for adding/editing a CreditCard. If |credit_card| is NULL, a |
+// new CreditCard should be created. |
+void ShowAutoFillCreditCardEditor(gfx::NativeView parent, |
+ AutoFillDialogObserver* observer, |
+ Profile* profile, |
+ CreditCard* credit_card); |
- return entry; |
-} |
+namespace { |
-} // namespace |
+// The resource id for the 'About Autofill' link button. |
+const gint kAutoFillDialogAboutLink = 1; |
//////////////////////////////////////////////////////////////////////////////// |
// AutoFillDialog |
// |
// The contents of the AutoFill dialog. This dialog allows users to add, edit |
// and remove AutoFill profiles. |
-class AutoFillDialog : public PersonalDataManager::Observer { |
+class AutoFillDialog : public PersonalDataManager::Observer, |
+ public NotificationObserver { |
public: |
- AutoFillDialog(AutoFillDialogObserver* observer, |
- PersonalDataManager* personal_data_manager, |
- AutoFillProfile* imported_profile, |
- CreditCard* imported_credit_card); |
+ // Identifiers for columns in the store. |
+ enum Column { |
+ COL_TITLE = 0, |
+ COL_IS_HEADER, |
+ COL_IS_SEPARATOR, // Identifies an empty row used to reserve visual space. |
+ COL_WEIGHT, |
+ COL_WEIGHT_SET, |
+ COL_COUNT |
+ }; |
+ |
+ // Used to identify the selection. See GetSelectionType. |
+ enum SelectionType { |
+ // Nothing is selected. |
+ SELECTION_EMPTY = 0, |
+ |
+ // At least one header/separator row is selected. |
+ SELECTION_HEADER = 1 << 0, |
+ |
+ // At least one non-header/separator row is selected. |
+ SELECTION_SINGLE = 1 << 1, |
+ |
+ // Multiple non-header/separator rows are selected. |
+ SELECTION_MULTI = 1 << 2, |
+ }; |
+ |
+ AutoFillDialog(Profile* profile, AutoFillDialogObserver* observer); |
~AutoFillDialog(); |
// PersonalDataManager::Observer implementation: |
void OnPersonalDataLoaded(); |
+ void OnPersonalDataChanged(); |
+ |
+ // NotificationObserver implementation: |
+ virtual void Observe(NotificationType type, |
+ const NotificationSource& source, |
+ const NotificationDetails& details); |
// Shows the AutoFill dialog. |
void Show(); |
@@ -242,31 +109,27 @@ class AutoFillDialog : public PersonalDataManager::Observer { |
private: |
// 'destroy' signal handler. Calls DeleteSoon on the global singleton dialog |
// object. |
- static void OnDestroy(GtkWidget* widget, AutoFillDialog* autofill_dialog); |
+ CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnDestroy); |
// 'response' signal handler. Notifies the AutoFillDialogObserver that new |
// data is available if the response is GTK_RESPONSE_APPLY or GTK_RESPONSE_OK. |
// We close the dialog if the response is GTK_RESPONSE_OK or |
// GTK_RESPONSE_CANCEL. |
- static void OnResponse(GtkDialog* dialog, gint response_id, |
- AutoFillDialog* autofill_dialog); |
- |
- // 'clicked' signal handler. Adds a new address. |
- static void OnAddAddressClicked(GtkButton* button, AutoFillDialog* dialog); |
- |
- // 'clicked' signal handler. Adds a new credit card. |
- static void OnAddCreditCardClicked(GtkButton* button, AutoFillDialog* dialog); |
- |
- // 'clicked' signal handler. Deletes the associated address. |
- static void OnDeleteAddressClicked(GtkButton* button, AutoFillDialog* dialog); |
- |
- // 'clicked' signal handler. Deletes the associated credit card. |
- static void OnDeleteCreditCardClicked(GtkButton* button, |
- AutoFillDialog* dialog); |
- |
- // 'changed' signal handler. Updates the title of the expander widget with |
- // the contents of the label entry widget. |
- static void OnLabelChanged(GtkEntry* label, GtkWidget* expander); |
+ CHROMEG_CALLBACK_1(AutoFillDialog, void, OnResponse, GtkDialog*, gint); |
+ |
+ CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnAutoFillCheckToggled); |
+ CHROMEG_CALLBACK_2(AutoFillDialog, void, OnRowActivated, GtkTreeView*, |
+ GtkTreePath*, GtkTreeViewColumn*); |
+ CHROMEG_CALLBACK_0(AutoFillDialog, void, OnSelectionChanged, |
+ GtkTreeSelection*); |
+ CHROMEG_CALLBACK_1(AutoFillDialog, gboolean, OnCheckRowIsSeparator, |
+ GtkTreeModel*, GtkTreeIter*); |
+ CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnAddAddress); |
+ CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnAddCreditCard); |
+ CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnEdit); |
+ CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnRemove); |
+ CHROMEG_CALLBACK_3(AutoFillDialog, gboolean, OnSelectionFilter, |
+ GtkTreeSelection*, GtkTreeModel*, GtkTreePath*, gboolean); |
// Opens the 'Learn more' link in a new foreground tab. |
void OnLinkActivated(); |
@@ -277,36 +140,23 @@ class AutoFillDialog : public PersonalDataManager::Observer { |
// Creates the dialog UI widgets. |
void InitializeWidgets(); |
- // Initializes the group widgets and returns their container. |name_id| is |
- // the resource ID of the group label. |button_id| is the resource name of |
- // the button label. |clicked_callback| is a callback that handles the |
- // 'clicked' signal emitted when the user presses the 'Add' button. |
- GtkWidget* InitGroup(int label_id, |
- int button_id, |
- GCallback clicked_callback); |
- |
- // Initializes the expander, frame and table widgets used to hold the address |
- // and credit card forms. |name_id| is the resource id of the label of the |
- // expander widget. The content vbox widget is returned in |content_vbox|. |
- // Returns the expander widget. |
- GtkWidget* InitGroupContentArea(int name_id, GtkWidget** content_vbox); |
- |
- // 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. The expander will be expanded by |
- // default if |expand| is true. |
- GtkWidget* AddNewAddress(bool expand); |
- GtkWidget* AddNewCreditCard(bool expand); |
- |
- // Adds a new address filled out with information from |profile|. |
- void AddAddress(const AutoFillProfile& profile); |
- |
- // Adds a new credit card filled out with information from |credit_card|. |
- void AddCreditCard(const CreditCard& credit_card); |
- |
- // Returns the index of |billing_address| in the list of profiles. Returns -1 |
- // if the address is not found. |
- int FindIndexOfAddress(string16 billing_address); |
+ // Updates the state of the various widgets dependant upon the state of the |
+ // selection, loaded state and whether AutoFill is enabled. |
+ void UpdateWidgetState(); |
+ |
+ // Returns a bitmask of the selection types. |
+ int GetSelectionType(); |
+ |
+ void AddAddressToTree(const AutoFillProfile& profile, GtkTreeIter* iter); |
+ |
+ void AddCreditCardToTree(const CreditCard& credit_card, GtkTreeIter* iter); |
+ |
+ // Returns the set of selected profiles and cards. The values placed in |
+ // the specified vectors are owned by PersonalDataManager. |
+ void GetSelectedEntries(std::vector<AutoFillProfile*>* profiles, |
+ std::vector<CreditCard*>* cards); |
+ |
+ Profile* profile_; |
// Our observer. May not be NULL. |
AutoFillDialogObserver* observer_; |
@@ -315,32 +165,26 @@ class AutoFillDialog : public PersonalDataManager::Observer { |
// Unowned pointer, may not be NULL. |
PersonalDataManager* personal_data_; |
- // The imported profile. May be NULL. |
- AutoFillProfile* imported_profile_; |
- |
- // The imported credit card. May be NULL. |
- CreditCard* imported_credit_card_; |
- |
- // The list of current AutoFill profiles. |
- std::vector<AutoFillProfile> profiles_; |
+ // Number of profiles we're displaying. |
+ int profile_count_; |
- // The list of current AutoFill credit cards. |
- std::vector<CreditCard> credit_cards_; |
+ // The AutoFill dialog. |
+ GtkWidget* dialog_; |
- // The list of address widgets, used to modify the AutoFill profiles. |
- std::vector<AddressWidgets> address_widgets_; |
+ BooleanPrefMember enable_form_autofill_; |
- // The list of credit card widgets, used to modify the stored credit cards. |
- std::vector<CreditCardWidgets> credit_card_widgets_; |
+ GtkWidget* form_autofill_enable_check_; |
- // The AutoFill dialog. |
- GtkWidget* dialog_; |
+ // Displays the addresses then credit cards. |
+ GtkListStore* list_store_; |
- // The addresses group. |
- GtkWidget* addresses_vbox_; |
+ // Displays the list_store_. |
+ GtkWidget* tree_; |
- // The credit cards group. |
- GtkWidget* creditcards_vbox_; |
+ GtkWidget* add_address_button_; |
+ GtkWidget* add_credit_card_button_; |
+ GtkWidget* edit_button_; |
+ GtkWidget* remove_button_; |
DISALLOW_COPY_AND_ASSIGN(AutoFillDialog); |
}; |
@@ -348,17 +192,20 @@ class AutoFillDialog : public PersonalDataManager::Observer { |
// The singleton AutoFill dialog object. |
static AutoFillDialog* dialog = NULL; |
-AutoFillDialog::AutoFillDialog(AutoFillDialogObserver* observer, |
- PersonalDataManager* personal_data_manager, |
- AutoFillProfile* imported_profile, |
- CreditCard* imported_credit_card) |
- : observer_(observer), |
- personal_data_(personal_data_manager), |
- imported_profile_(imported_profile), |
- imported_credit_card_(imported_credit_card) { |
+AutoFillDialog::AutoFillDialog(Profile* profile, |
+ AutoFillDialogObserver* observer) |
+ : profile_(profile), |
+ observer_(observer), |
+ personal_data_(profile->GetPersonalDataManager()), |
+ profile_count_(0) { |
DCHECK(observer_); |
DCHECK(personal_data_); |
+ enable_form_autofill_.Init(prefs::kAutoFillEnabled, profile->GetPrefs(), |
+ this); |
+ |
+ personal_data_->SetObserver(this); |
+ |
InitializeWidgets(); |
LoadAutoFillData(); |
@@ -370,234 +217,151 @@ AutoFillDialog::AutoFillDialog(AutoFillDialogObserver* observer, |
AutoFillDialog::~AutoFillDialog() { |
// Removes observer if we are observing Profile load. Does nothing otherwise. |
- if (personal_data_) |
- personal_data_->RemoveObserver(this); |
+ personal_data_->RemoveObserver(this); |
} |
///////////////////////////////////////////////////////////////////////////// |
// PersonalDataManager::Observer implementation: |
void AutoFillDialog::OnPersonalDataLoaded() { |
- personal_data_->RemoveObserver(this); |
LoadAutoFillData(); |
} |
-void AutoFillDialog::Show() { |
- gtk_util::PresentWindow(dialog_, gtk_get_current_event_time()); |
+void AutoFillDialog::OnPersonalDataChanged() { |
+ LoadAutoFillData(); |
} |
-// static |
-void AutoFillDialog::OnDestroy(GtkWidget* widget, |
- AutoFillDialog* autofill_dialog) { |
- dialog = NULL; |
- MessageLoop::current()->DeleteSoon(FROM_HERE, autofill_dialog); |
+void AutoFillDialog::Observe(NotificationType type, |
+ const NotificationSource& source, |
+ const NotificationDetails& details) { |
+ DCHECK_EQ(NotificationType::PREF_CHANGED, type.value); |
+ const std::wstring* pref_name = Details<std::wstring>(details).ptr(); |
+ if (!pref_name || *pref_name == prefs::kAutoFillEnabled) { |
+ gtk_toggle_button_set_active( |
+ GTK_TOGGLE_BUTTON(form_autofill_enable_check_), |
+ enable_form_autofill_.GetValue() ? TRUE : FALSE); |
+ UpdateWidgetState(); |
+ } |
} |
-static AutoFillProfile AutoFillProfileFromWidgetValues( |
- const AddressWidgets& widgets) { |
- // TODO(jhawkins): unique id? |
- AutoFillProfile profile(GetEntryText(widgets.label), 0); |
- profile.SetInfo(AutoFillType(NAME_FULL), |
- GetEntryText(widgets.full_name)); |
- profile.SetInfo(AutoFillType(EMAIL_ADDRESS), |
- GetEntryText(widgets.email)); |
- profile.SetInfo(AutoFillType(COMPANY_NAME), |
- GetEntryText(widgets.company_name)); |
- profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE1), |
- GetEntryText(widgets.address_line1)); |
- profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE2), |
- GetEntryText(widgets.address_line2)); |
- profile.SetInfo(AutoFillType(ADDRESS_HOME_CITY), |
- GetEntryText(widgets.city)); |
- profile.SetInfo(AutoFillType(ADDRESS_HOME_STATE), |
- GetEntryText(widgets.state)); |
- profile.SetInfo(AutoFillType(ADDRESS_HOME_ZIP), |
- GetEntryText(widgets.zipcode)); |
- profile.SetInfo(AutoFillType(ADDRESS_HOME_COUNTRY), |
- GetEntryText(widgets.country)); |
- |
- string16 number, city_code, country_code; |
- PhoneNumber::ParsePhoneNumber( |
- GetEntryText(widgets.phone), &number, &city_code, &country_code); |
- profile.SetInfo(AutoFillType(PHONE_HOME_COUNTRY_CODE), country_code); |
- profile.SetInfo(AutoFillType(PHONE_HOME_CITY_CODE), city_code); |
- profile.SetInfo(AutoFillType(PHONE_HOME_NUMBER), number); |
- |
- PhoneNumber::ParsePhoneNumber( |
- GetEntryText(widgets.fax), &number, &city_code, &country_code); |
- profile.SetInfo(AutoFillType(PHONE_FAX_COUNTRY_CODE), country_code); |
- profile.SetInfo(AutoFillType(PHONE_FAX_CITY_CODE), city_code); |
- profile.SetInfo(AutoFillType(PHONE_FAX_NUMBER), number); |
- |
- return profile; |
+void AutoFillDialog::Show() { |
+ gtk_util::PresentWindow(dialog_, gtk_get_current_event_time()); |
} |
-static CreditCard CreditCardFromWidgetValues( |
- const CreditCardWidgets& widgets) { |
- // TODO(jhawkins): unique id? |
- CreditCard credit_card(GetEntryText(widgets.label), 0); |
- credit_card.SetInfo(AutoFillType(CREDIT_CARD_NAME), |
- GetEntryText(widgets.name_on_card)); |
- credit_card.SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH), |
- GetEntryText(widgets.expiration_month)); |
- credit_card.SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), |
- GetEntryText(widgets.expiration_year)); |
- |
- // If the CC number starts with an asterisk, then we know that the user has |
- // not modified the credit card number at the least, so use the original CC |
- // number in this case. |
- string16 cc_number = GetEntryText(widgets.card_number); |
- if (!cc_number.empty() && cc_number[0] == '*') |
- credit_card.SetInfo(AutoFillType(CREDIT_CARD_NUMBER), |
- widgets.original_card_number); |
- else |
- credit_card.SetInfo(AutoFillType(CREDIT_CARD_NUMBER), |
- GetEntryText(widgets.card_number)); |
- |
- std::string text = |
- gtk_combo_box_get_active_text(GTK_COMBO_BOX(widgets.billing_address)); |
- if (text != |
- l10n_util::GetStringUTF8(IDS_AUTOFILL_DIALOG_CHOOSE_EXISTING_ADDRESS)) { |
- // TODO(jhawkins): Should we validate the billing address combobox? |
- credit_card.set_billing_address(UTF8ToUTF16(text)); |
- } |
- |
- return credit_card; |
+void AutoFillDialog::OnDestroy(GtkWidget* widget) { |
+ dialog = NULL; |
+ MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
} |
-// static |
-void AutoFillDialog::OnResponse(GtkDialog* dialog, gint response_id, |
- AutoFillDialog* autofill_dialog) { |
- if (response_id == GTK_RESPONSE_APPLY || response_id == GTK_RESPONSE_OK) { |
- autofill_dialog->profiles_.clear(); |
- for (std::vector<AddressWidgets>::const_iterator iter = |
- autofill_dialog->address_widgets_.begin(); |
- iter != autofill_dialog->address_widgets_.end(); |
- ++iter) { |
- AutoFillProfile profile = AutoFillProfileFromWidgetValues(*iter); |
- autofill_dialog->profiles_.push_back(profile); |
- } |
- |
- autofill_dialog->credit_cards_.clear(); |
- for (std::vector<CreditCardWidgets>::const_iterator iter = |
- autofill_dialog->credit_card_widgets_.begin(); |
- iter != autofill_dialog->credit_card_widgets_.end(); |
- ++iter) { |
- CreditCard credit_card = CreditCardFromWidgetValues(*iter); |
- autofill_dialog->credit_cards_.push_back(credit_card); |
- } |
- |
- autofill_dialog->observer_->OnAutoFillDialogApply( |
- &autofill_dialog->profiles_, |
- &autofill_dialog->credit_cards_); |
- } |
- |
+void AutoFillDialog::OnResponse(GtkDialog* dialog, gint response_id) { |
if (response_id == GTK_RESPONSE_OK || |
response_id == GTK_RESPONSE_CANCEL || |
response_id == GTK_RESPONSE_DELETE_EVENT) { |
gtk_widget_destroy(GTK_WIDGET(dialog)); |
} |
- if (response_id == kAutoFillDialogLearnMoreLink) |
- autofill_dialog->OnLinkActivated(); |
+ if (response_id == kAutoFillDialogAboutLink) |
+ OnLinkActivated(); |
} |
-// static |
-void AutoFillDialog::OnAddAddressClicked(GtkButton* button, |
- AutoFillDialog* dialog) { |
- 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); |
+void AutoFillDialog::OnAutoFillCheckToggled(GtkWidget* widget) { |
+ bool enabled = gtk_toggle_button_get_active( |
+ GTK_TOGGLE_BUTTON(form_autofill_enable_check_)); |
+ if (enabled) { |
+ UserMetrics::RecordAction(UserMetricsAction("Options_FormAutofill_Enable"), |
+ profile_); |
+ } else { |
+ UserMetrics::RecordAction(UserMetricsAction("Options_FormAutofill_Disable"), |
+ profile_); |
+ } |
+ enable_form_autofill_.SetValue(enabled); |
+ profile_->GetPrefs()->ScheduleSavePersistentPrefs(); |
+ UpdateWidgetState(); |
} |
-// static |
-void AutoFillDialog::OnAddCreditCardClicked(GtkButton* button, |
- AutoFillDialog* dialog) { |
- GtkWidget* new_creditcard = dialog->AddNewCreditCard(true); |
- gtk_box_pack_start(GTK_BOX(dialog->creditcards_vbox_), new_creditcard, |
- FALSE, FALSE, 0); |
- gtk_widget_show_all(new_creditcard); |
+void AutoFillDialog::OnRowActivated(GtkTreeView* tree_view, |
+ GtkTreePath* path, |
+ GtkTreeViewColumn* column) { |
+ if (GetSelectionType() == SELECTION_SINGLE) |
+ OnEdit(NULL); |
} |
-// 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; |
- } |
- } |
+void AutoFillDialog::OnSelectionChanged(GtkTreeSelection* selection) { |
+ UpdateWidgetState(); |
+} |
- // 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; |
- } |
- } |
+gboolean AutoFillDialog::OnCheckRowIsSeparator(GtkTreeModel* model, |
+ GtkTreeIter* iter) { |
+ gboolean is_separator; |
+ gtk_tree_model_get(model, iter, COL_IS_SEPARATOR, &is_separator, -1); |
+ return is_separator; |
+} |
+ |
+void AutoFillDialog::OnAddAddress(GtkWidget* widget) { |
+ ShowAutoFillProfileEditor(NULL, observer_, profile_, NULL); |
+} |
+ |
+void AutoFillDialog::OnAddCreditCard(GtkWidget* widget) { |
+ ShowAutoFillCreditCardEditor(NULL, observer_, profile_, NULL); |
+} |
- // Get back to the expander widget. |
- GtkWidget* expander = gtk_widget_get_ancestor(GTK_WIDGET(button), |
- GTK_TYPE_EXPANDER); |
- DCHECK(expander); |
+void AutoFillDialog::OnEdit(GtkWidget* widget) { |
+ DCHECK_EQ(SELECTION_SINGLE, GetSelectionType()); |
- // Destroying the widget will also remove it from the parent container. |
- gtk_widget_destroy(expander); |
+ std::vector<AutoFillProfile*> profiles; |
+ std::vector<CreditCard*> cards; |
+ |
+ GetSelectedEntries(&profiles, &cards); |
+ |
+ if (profiles.size() == 1) |
+ ShowAutoFillProfileEditor(dialog_, observer_, profile_, profiles[0]); |
+ else if (cards.size() == 1) |
+ ShowAutoFillCreditCardEditor(dialog_, observer_, profile_, cards[0]); |
} |
-// static |
-void AutoFillDialog::OnDeleteCreditCardClicked(GtkButton* button, |
- AutoFillDialog* dialog) { |
- GtkWidget* entry = GetButtonData(GTK_WIDGET(button)); |
- string16 label = GetEntryText(entry); |
- |
- // TODO(jhawkins): Base this on ID. |
- |
- // Remove the credit card. |
- for (std::vector<CreditCard>::iterator iter = dialog->credit_cards_.begin(); |
- iter != dialog->credit_cards_.end(); |
- ++iter) { |
- if (iter->Label() == label) { |
- dialog->credit_cards_.erase(iter); |
- break; |
+void AutoFillDialog::OnRemove(GtkWidget* widget) { |
+ PersonalDataManager* data_manager = profile_->GetPersonalDataManager(); |
+ std::vector<AutoFillProfile*> selected_profiles; |
+ std::vector<CreditCard*> selected_cards; |
+ |
+ GetSelectedEntries(&selected_profiles, &selected_cards); |
+ |
+ std::vector<AutoFillProfile> profiles; |
+ for (std::vector<AutoFillProfile*>::const_iterator i = |
+ data_manager->profiles().begin(); |
+ i != data_manager->profiles().end(); ++i) { |
+ if (std::find(selected_profiles.begin(), selected_profiles.end(), *i) == |
+ selected_profiles.end()) { |
+ profiles.push_back(**i); |
} |
} |
- // Remove the set of credit widgets. |
- for (std::vector<CreditCardWidgets>::iterator iter = |
- dialog->credit_card_widgets_.begin(); |
- iter != dialog->credit_card_widgets_.end(); |
- ++iter) { |
- if (iter->label == entry) { |
- dialog->credit_card_widgets_.erase(iter); |
- break; |
+ std::vector<CreditCard> cards; |
+ for (std::vector<CreditCard*>::const_iterator i = |
+ data_manager->credit_cards().begin(); |
+ i != data_manager->credit_cards().end(); ++i) { |
+ if (std::find(selected_cards.begin(), selected_cards.end(), *i) == |
+ selected_cards.end()) { |
+ cards.push_back(**i); |
} |
} |
- // 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); |
+ observer_->OnAutoFillDialogApply(&profiles, &cards); |
} |
-// static |
-void AutoFillDialog::OnLabelChanged(GtkEntry* label, GtkWidget* expander) { |
- gtk_expander_set_label(GTK_EXPANDER(expander), gtk_entry_get_text(label)); |
+gboolean AutoFillDialog::OnSelectionFilter(GtkTreeSelection* selection, |
+ GtkTreeModel* model, |
+ GtkTreePath* path, |
+ gboolean path_currently_selected) { |
+ GtkTreeIter iter; |
+ if (!gtk_tree_model_get_iter(model, &iter, path)) { |
+ NOTREACHED(); |
+ return TRUE; |
+ } |
+ gboolean is_header; |
+ gboolean is_separator; |
+ gtk_tree_model_get(model, &iter, COL_IS_HEADER, &is_header, |
+ COL_IS_SEPARATOR, &is_separator, -1); |
+ return !is_header && !is_separator; |
} |
void AutoFillDialog::OnLinkActivated() { |
@@ -608,43 +372,72 @@ void AutoFillDialog::OnLinkActivated() { |
void AutoFillDialog::LoadAutoFillData() { |
if (!personal_data_->IsDataLoaded()) { |
- personal_data_->SetObserver(this); |
+ UpdateWidgetState(); |
return; |
} |
- if (imported_profile_) { |
- profiles_.push_back(*imported_profile_); |
- AddAddress(*imported_profile_); |
- } else { |
- for (std::vector<AutoFillProfile*>::const_iterator iter = |
- personal_data_->profiles().begin(); |
- iter != personal_data_->profiles().end(); ++iter) { |
- // The profile list is terminated by a NULL entry; |
- if (!*iter) |
- break; |
- |
- AutoFillProfile* profile = *iter; |
- profiles_.push_back(*profile); |
- AddAddress(*profile); |
- } |
+ // Rebuild the underyling store. |
+ gtk_list_store_clear(list_store_); |
+ |
+ GtkTreeIter iter; |
+ // Address title. |
+ gtk_list_store_append(list_store_, &iter); |
+ gtk_list_store_set( |
+ list_store_, &iter, |
+ COL_WEIGHT, PANGO_WEIGHT_BOLD, |
+ COL_WEIGHT_SET, TRUE, |
+ COL_TITLE, |
+ l10n_util::GetStringUTF8(IDS_AUTOFILL_ADDRESSES_GROUP_NAME).c_str(), |
+ COL_IS_HEADER, TRUE, |
+ -1); |
+ // Address separator. |
+ gtk_list_store_append(list_store_, &iter); |
+ gtk_list_store_set( |
+ list_store_, &iter, |
+ COL_IS_SEPARATOR, TRUE, |
+ -1); |
+ |
+ // The addresses. |
+ profile_count_ = 0; |
+ for (std::vector<AutoFillProfile*>::const_iterator i = |
+ personal_data_->profiles().begin(); |
+ i != personal_data_->profiles().end(); ++i) { |
+ AddAddressToTree(*(*i), &iter); |
+ profile_count_++; |
} |
- if (imported_credit_card_) { |
- credit_cards_.push_back(*imported_credit_card_); |
- AddCreditCard(*imported_credit_card_); |
- } else { |
- for (std::vector<CreditCard*>::const_iterator iter = |
- personal_data_->credit_cards().begin(); |
- iter != personal_data_->credit_cards().end(); ++iter) { |
- // The credit card list is terminated by a NULL entry; |
- if (!*iter) |
- break; |
- |
- CreditCard* credit_card = *iter; |
- credit_cards_.push_back(*credit_card); |
- AddCreditCard(*credit_card); |
- } |
+ // Blank row between addresses and credit cards. |
+ gtk_list_store_append(list_store_, &iter); |
+ gtk_list_store_set( |
+ list_store_, &iter, |
+ COL_IS_HEADER, TRUE, |
+ -1); |
+ |
+ // Credit card title. |
+ gtk_list_store_append(list_store_, &iter); |
+ gtk_list_store_set( |
+ list_store_, &iter, |
+ COL_WEIGHT, PANGO_WEIGHT_BOLD, |
+ COL_WEIGHT_SET, TRUE, |
+ COL_TITLE, |
+ l10n_util::GetStringUTF8(IDS_AUTOFILL_CREDITCARDS_GROUP_NAME).c_str(), |
+ COL_IS_HEADER, TRUE, |
+ -1); |
+ // Credit card separator. |
+ gtk_list_store_append(list_store_, &iter); |
+ gtk_list_store_set( |
+ list_store_, &iter, |
+ COL_IS_SEPARATOR, TRUE, |
+ -1); |
+ |
+ // The credit cards. |
+ for (std::vector<CreditCard*>::const_iterator i = |
+ personal_data_->credit_cards().begin(); |
+ i != personal_data_->credit_cards().end(); ++i) { |
+ AddCreditCardToTree(*(*i), &iter); |
} |
+ |
+ UpdateWidgetState(); |
} |
void AutoFillDialog::InitializeWidgets() { |
@@ -654,54 +447,97 @@ void AutoFillDialog::InitializeWidgets() { |
NULL, |
// Non-modal. |
GTK_DIALOG_NO_SEPARATOR, |
- GTK_STOCK_APPLY, |
- GTK_RESPONSE_APPLY, |
- GTK_STOCK_CANCEL, |
- GTK_RESPONSE_CANCEL, |
GTK_STOCK_OK, |
GTK_RESPONSE_OK, |
NULL); |
- gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox), |
- gtk_util::kContentAreaSpacing); |
- g_signal_connect(dialog_, "response", G_CALLBACK(OnResponse), this); |
- g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroy), this); |
+ GtkBox* vbox = GTK_BOX(GTK_DIALOG(dialog_)->vbox); |
+ gtk_box_set_spacing(vbox, gtk_util::kControlSpacing); |
+ g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this); |
+ g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroyThunk), this); |
+ |
+ form_autofill_enable_check_ = gtk_check_button_new_with_label( |
+ l10n_util::GetStringUTF8(IDS_OPTIONS_AUTOFILL_ENABLE).c_str()); |
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(form_autofill_enable_check_), |
+ enable_form_autofill_.GetValue()); |
+ g_signal_connect(G_OBJECT(form_autofill_enable_check_), "toggled", |
+ G_CALLBACK(OnAutoFillCheckToggledThunk), this); |
+ gtk_box_pack_start(vbox, form_autofill_enable_check_, FALSE, FALSE, 0); |
// Allow the contents to be scrolled. |
GtkWidget* scrolled_window = gtk_scrolled_window_new(NULL, NULL); |
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), |
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); |
- gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog_)->vbox), scrolled_window); |
- |
- // We create an event box so that we can color the frame background white. |
- GtkWidget* frame_event_box = gtk_event_box_new(); |
- SetWhiteBackground(frame_event_box); |
- gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), |
- frame_event_box); |
- |
- // The frame outline of the content area. |
- GtkWidget* frame = gtk_frame_new(NULL); |
- gtk_container_add(GTK_CONTAINER(frame_event_box), frame); |
- |
- // The content vbox. |
- GtkWidget* outer_vbox = gtk_vbox_new(false, 0); |
- gtk_box_set_spacing(GTK_BOX(outer_vbox), gtk_util::kContentAreaSpacing); |
- gtk_container_add(GTK_CONTAINER(frame), outer_vbox); |
- |
- addresses_vbox_ = InitGroup(IDS_AUTOFILL_ADDRESSES_GROUP_NAME, |
- IDS_AUTOFILL_ADD_ADDRESS_BUTTON, |
- G_CALLBACK(OnAddAddressClicked)); |
- gtk_box_pack_start_defaults(GTK_BOX(outer_vbox), addresses_vbox_); |
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), |
+ GTK_SHADOW_ETCHED_IN); |
+ |
+ list_store_ = gtk_list_store_new(COL_COUNT, |
+ G_TYPE_STRING, |
+ G_TYPE_BOOLEAN, |
+ G_TYPE_BOOLEAN, |
+ G_TYPE_INT, |
+ G_TYPE_BOOLEAN); |
+ tree_ = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store_)); |
+ g_object_unref(list_store_); |
+ gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_), FALSE); |
+ gtk_tree_view_set_row_separator_func(GTK_TREE_VIEW(tree_), |
+ OnCheckRowIsSeparatorThunk, this, NULL); |
+ g_signal_connect(tree_, "row-activated", G_CALLBACK(OnRowActivatedThunk), |
+ this); |
+ gtk_container_add(GTK_CONTAINER(scrolled_window), tree_); |
+ |
+ GtkWidget* h_box1 = gtk_hbox_new(FALSE, gtk_util::kControlSpacing); |
+ gtk_box_pack_start(vbox, h_box1, TRUE, TRUE, 0); |
+ gtk_box_pack_start(GTK_BOX(h_box1), scrolled_window, TRUE, TRUE, 0); |
+ |
+ GtkWidget* controls_box = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); |
+ gtk_box_pack_start(GTK_BOX(h_box1), controls_box, FALSE, FALSE, 0); |
+ |
+ add_address_button_ = gtk_button_new_with_label( |
+ l10n_util::GetStringUTF8(IDS_AUTOFILL_ADD_ADDRESS_BUTTON).c_str()); |
+ g_signal_connect(add_address_button_, "clicked", |
+ G_CALLBACK(OnAddAddressThunk), this); |
+ gtk_box_pack_start(GTK_BOX(controls_box), add_address_button_, FALSE, FALSE, |
+ 0); |
+ |
+ add_credit_card_button_ = gtk_button_new_with_label( |
+ l10n_util::GetStringUTF8(IDS_AUTOFILL_ADD_CREDITCARD_BUTTON).c_str()); |
+ g_signal_connect(add_credit_card_button_, "clicked", |
+ G_CALLBACK(OnAddCreditCardThunk), this); |
+ gtk_box_pack_start(GTK_BOX(controls_box), add_credit_card_button_, FALSE, |
+ FALSE, 0); |
+ |
+ edit_button_ = gtk_button_new_with_label( |
+ l10n_util::GetStringUTF8(IDS_AUTOFILL_EDIT_BUTTON).c_str()); |
+ g_signal_connect(edit_button_, "clicked", G_CALLBACK(OnEditThunk), this); |
+ gtk_box_pack_start(GTK_BOX(controls_box), edit_button_, FALSE, FALSE, 0); |
+ |
+ remove_button_ = gtk_button_new_with_label( |
+ l10n_util::GetStringUTF8(IDS_AUTOFILL_DELETE_BUTTON).c_str()); |
+ g_signal_connect(remove_button_, "clicked", G_CALLBACK(OnRemoveThunk), this); |
+ gtk_box_pack_start(GTK_BOX(controls_box), remove_button_, FALSE, FALSE, 0); |
+ |
+ GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes( |
+ "", |
+ gtk_cell_renderer_text_new(), |
+ "text", COL_TITLE, |
+ "weight", COL_WEIGHT, |
+ "weight-set", COL_WEIGHT_SET, |
+ NULL); |
+ gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), column); |
- creditcards_vbox_ = InitGroup(IDS_AUTOFILL_CREDITCARDS_GROUP_NAME, |
- IDS_AUTOFILL_ADD_CREDITCARD_BUTTON, |
- G_CALLBACK(OnAddCreditCardClicked)); |
- gtk_box_pack_start_defaults(GTK_BOX(outer_vbox), creditcards_vbox_); |
+ GtkTreeSelection* selection = |
+ gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_)); |
+ gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); |
+ gtk_tree_selection_set_select_function(selection, OnSelectionFilterThunk, |
+ this, NULL); |
+ g_signal_connect(selection, "changed", G_CALLBACK(OnSelectionChangedThunk), |
+ this); |
GtkWidget* link = gtk_chrome_link_button_new( |
- l10n_util::GetStringUTF8(IDS_AUTOFILL_LEARN_MORE).c_str()); |
+ l10n_util::GetStringUTF8(IDS_AUTOFILL_HELP_LABEL).c_str()); |
gtk_dialog_add_action_widget(GTK_DIALOG(dialog_), link, |
- kAutoFillDialogLearnMoreLink); |
+ kAutoFillDialogAboutLink); |
// Setting the link widget to secondary positions the button on the left side |
// of the action area (vice versa for RTL layout). |
@@ -709,270 +545,113 @@ void AutoFillDialog::InitializeWidgets() { |
GTK_BUTTON_BOX(GTK_DIALOG(dialog_)->action_area), link, TRUE); |
} |
-GtkWidget* AutoFillDialog::InitGroup(int name_id, |
- int button_id, |
- GCallback clicked_callback) { |
- GtkWidget* vbox = gtk_vbox_new(false, gtk_util::kControlSpacing); |
- |
- // Group label. |
- GtkWidget* label = gtk_util::CreateBoldLabel( |
- l10n_util::GetStringUTF8(name_id)); |
- gtk_box_pack_start(GTK_BOX(vbox), |
- IndentWidget(label, kAutoFillDialogIndent), |
- FALSE, FALSE, 0); |
- |
- // Separator. |
- GtkWidget* separator = gtk_hseparator_new(); |
- gtk_box_pack_start(GTK_BOX(vbox), separator, FALSE, FALSE, 0); |
- |
- // Add profile button. |
- GtkWidget* button = gtk_button_new_with_label( |
- l10n_util::GetStringUTF8(button_id).c_str()); |
- g_signal_connect(button, "clicked", clicked_callback, this); |
- gtk_box_pack_end_defaults(GTK_BOX(vbox), |
- IndentWidget(button, kAutoFillDialogIndent)); |
- |
- return vbox; |
-} |
- |
-GtkWidget* AutoFillDialog::InitGroupContentArea(int name_id, |
- GtkWidget** content_vbox) { |
- GtkWidget* expander = gtk_expander_new( |
- l10n_util::GetStringUTF8(name_id).c_str()); |
- |
- GtkWidget* frame = gtk_frame_new(NULL); |
- gtk_container_add(GTK_CONTAINER(expander), frame); |
- |
- GtkWidget* vbox = gtk_vbox_new(false, 0); |
- gtk_box_set_spacing(GTK_BOX(vbox), gtk_util::kControlSpacing); |
- GtkWidget* vbox_alignment = gtk_alignment_new(0, 0, 0, 0); |
- gtk_alignment_set_padding(GTK_ALIGNMENT(vbox_alignment), |
- gtk_util::kControlSpacing, |
- gtk_util::kControlSpacing, |
- gtk_util::kGroupIndent, |
- 0); |
- gtk_container_add(GTK_CONTAINER(vbox_alignment), vbox); |
- gtk_container_add(GTK_CONTAINER(frame), vbox_alignment); |
- |
- *content_vbox = vbox; |
- return expander; |
-} |
- |
-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); |
- |
- widgets.label = FormTableAddLabelEntry(table, 0, 0, 1, |
- IDS_AUTOFILL_DIALOG_LABEL, |
- address, G_CALLBACK(OnLabelChanged)); |
- widgets.full_name = FormTableAddEntry(table, 1, 0, 1, |
- IDS_AUTOFILL_DIALOG_FULL_NAME); |
- widgets.email = FormTableAddEntry(table, 2, 0, 1, |
- IDS_AUTOFILL_DIALOG_EMAIL); |
- widgets.company_name = FormTableAddEntry(table, 2, 1, 1, |
- IDS_AUTOFILL_DIALOG_COMPANY_NAME); |
- widgets.address_line1 = FormTableAddEntry(table, 3, 0, 2, |
- IDS_AUTOFILL_DIALOG_ADDRESS_LINE_1); |
- widgets.address_line2 = FormTableAddEntry(table, 4, 0, 2, |
- IDS_AUTOFILL_DIALOG_ADDRESS_LINE_2); |
- |
- GtkWidget* address_table = InitFormTable(1, 4); |
- gtk_box_pack_start_defaults(GTK_BOX(vbox), address_table); |
- |
- widgets.city = FormTableAddEntry(address_table, 0, 0, 1, |
- IDS_AUTOFILL_DIALOG_CITY); |
- widgets.state = FormTableAddEntry(address_table, 0, 1, 1, |
- IDS_AUTOFILL_DIALOG_STATE); |
- widgets.zipcode = FormTableAddSizedEntry(address_table, 0, 2, 7, |
- IDS_AUTOFILL_DIALOG_ZIP_CODE); |
- widgets.country = FormTableAddSizedEntry(address_table, 0, 3, 10, |
- IDS_AUTOFILL_DIALOG_COUNTRY); |
- |
- GtkWidget* phone_table = InitFormTable(1, 2); |
- gtk_box_pack_start_defaults(GTK_BOX(vbox), phone_table); |
- |
- widgets.phone = |
- FormTableAddEntry(phone_table, 0, 0, 1, IDS_AUTOFILL_DIALOG_PHONE); |
- widgets.fax = |
- FormTableAddEntry(phone_table, 0, 1, 1, IDS_AUTOFILL_DIALOG_FAX); |
- |
- 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); |
- |
- address_widgets_.push_back(widgets); |
- return address; |
+void AutoFillDialog::UpdateWidgetState() { |
+ if (!personal_data_->IsDataLoaded() || !enable_form_autofill_.GetValue()) { |
+ gtk_widget_set_sensitive(add_address_button_, FALSE); |
+ gtk_widget_set_sensitive(add_credit_card_button_, FALSE); |
+ gtk_widget_set_sensitive(edit_button_, FALSE); |
+ gtk_widget_set_sensitive(remove_button_, FALSE); |
+ gtk_widget_set_sensitive(tree_, FALSE); |
+ } else { |
+ gtk_widget_set_sensitive(add_address_button_, TRUE); |
+ gtk_widget_set_sensitive(add_credit_card_button_, TRUE); |
+ int selection_type = GetSelectionType(); |
+ gtk_widget_set_sensitive(edit_button_, selection_type == SELECTION_SINGLE); |
+ // Enable the remove button if at least one non-header row is selected. |
+ gtk_widget_set_sensitive(remove_button_, |
+ (selection_type & SELECTION_SINGLE) != 0); |
+ gtk_widget_set_sensitive(tree_, TRUE); |
+ } |
} |
-GtkWidget* AutoFillDialog::AddNewCreditCard(bool expand) { |
- CreditCardWidgets widgets = {0}; |
- GtkWidget* vbox; |
- GtkWidget* credit_card = InitGroupContentArea(IDS_AUTOFILL_NEW_CREDITCARD, |
- &vbox); |
- |
- gtk_expander_set_expanded(GTK_EXPANDER(credit_card), expand); |
- |
- GtkWidget* label_table = InitFormTable(1, 2); |
- gtk_box_pack_start_defaults(GTK_BOX(vbox), label_table); |
- |
- widgets.label = FormTableAddLabelEntry(label_table, 0, 0, 1, |
- IDS_AUTOFILL_DIALOG_LABEL, credit_card, |
- G_CALLBACK(OnLabelChanged)); |
- |
- GtkWidget* name_cc_table = InitFormTable(2, 6); |
- gtk_box_pack_start_defaults(GTK_BOX(vbox), name_cc_table); |
- |
- widgets.name_on_card = FormTableAddExpandedEntry( |
- name_cc_table, 0, 0, 3, IDS_AUTOFILL_DIALOG_NAME_ON_CARD); |
- widgets.card_number = FormTableAddExpandedEntry( |
- name_cc_table, 1, 0, 3, IDS_AUTOFILL_DIALOG_CREDIT_CARD_NUMBER); |
- widgets.expiration_month = FormTableAddSizedEntry(name_cc_table, 1, 3, 2, 0); |
- widgets.expiration_year = FormTableAddSizedEntry(name_cc_table, 1, 4, 4, 0); |
- |
- FormTableSetLabel(name_cc_table, 1, 3, 2, |
- IDS_AUTOFILL_DIALOG_EXPIRATION_DATE); |
- |
- gtk_table_set_col_spacing(GTK_TABLE(name_cc_table), 3, 2); |
- |
- GtkWidget* addresses_table = InitFormTable(2, 5); |
- gtk_box_pack_start_defaults(GTK_BOX(vbox), addresses_table); |
- |
- FormTableSetLabel(addresses_table, 0, 0, 3, |
- IDS_AUTOFILL_DIALOG_BILLING_ADDRESS); |
- |
- GtkWidget* billing = gtk_combo_box_new_text(); |
- widgets.billing_address = billing; |
- std::string combo_text = l10n_util::GetStringUTF8( |
- IDS_AUTOFILL_DIALOG_CHOOSE_EXISTING_ADDRESS); |
- gtk_combo_box_append_text(GTK_COMBO_BOX(billing), combo_text.c_str()); |
- gtk_combo_box_set_active(GTK_COMBO_BOX(billing), 0); |
- FormTableSetWidget(addresses_table, billing, 0, 0, 2, false); |
- |
- for (std::vector<AddressWidgets>::const_iterator iter = |
- address_widgets_.begin(); |
- iter != address_widgets_.end(); ++iter) { |
- // TODO(jhawkins): Validate the label and DCHECK on !empty(). |
- std::string text = gtk_entry_get_text(GTK_ENTRY(iter->label)); |
- if (!text.empty()) |
- gtk_combo_box_append_text(GTK_COMBO_BOX(widgets.billing_address), |
- text.c_str()); |
+static void RowIteratorFunction(GtkTreeModel* model, |
+ GtkTreePath* path, |
+ GtkTreeIter* iter, |
+ gpointer data) { |
+ int* type = reinterpret_cast<int*>(data); |
+ bool is_header = false; |
+ GValue value = { 0 }; |
+ gtk_tree_model_get_value(model, iter, AutoFillDialog::COL_IS_HEADER, &value); |
+ is_header = g_value_get_boolean(&value); |
+ g_value_unset(&value); |
+ |
+ if (!is_header) { |
+ // Is it a separator? |
+ GValue value = { 0 }; |
+ gtk_tree_model_get_value(model, iter, AutoFillDialog::COL_IS_SEPARATOR, |
+ &value); |
+ is_header = g_value_get_boolean(&value); |
+ g_value_unset(&value); |
} |
- GtkWidget* phone_table = InitFormTable(1, 1); |
- gtk_box_pack_start_defaults(GTK_BOX(vbox), phone_table); |
- |
- widgets.phone = |
- FormTableAddEntry(phone_table, 0, 0, 1, IDS_AUTOFILL_DIALOG_PHONE); |
- |
- GtkWidget* button = gtk_button_new_with_label( |
- l10n_util::GetStringUTF8(IDS_AUTOFILL_DELETE_BUTTON).c_str()); |
- g_signal_connect(button, "clicked", |
- G_CALLBACK(OnDeleteCreditCardClicked), 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); |
- |
- credit_card_widgets_.push_back(widgets); |
- 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.full_name, |
- profile.GetFieldText(AutoFillType(NAME_FULL))); |
- 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.phone, |
- profile.GetFieldText(AutoFillType(PHONE_HOME_WHOLE_NUMBER))); |
- SetEntryText(widgets.fax, |
- profile.GetFieldText(AutoFillType(PHONE_FAX_WHOLE_NUMBER))); |
- |
- gtk_box_pack_start(GTK_BOX(addresses_vbox_), address, FALSE, FALSE, 0); |
- gtk_widget_show_all(address); |
+ if (is_header) { |
+ *type |= AutoFillDialog::SELECTION_HEADER; |
+ } else { |
+ if ((*type & AutoFillDialog::SELECTION_SINGLE) == 0) |
+ *type |= AutoFillDialog::SELECTION_SINGLE; |
+ else |
+ *type |= AutoFillDialog::SELECTION_MULTI; |
+ } |
} |
-void AutoFillDialog::AddCreditCard(const CreditCard& credit_card) { |
- GtkWidget* credit_card_widget = AddNewCreditCard(false); |
- gtk_expander_set_label(GTK_EXPANDER(credit_card_widget), |
- UTF16ToUTF8(credit_card.Label()).c_str()); |
- |
- // We just pushed the widgets to the back of the vector. |
- const CreditCardWidgets& widgets = credit_card_widgets_.back(); |
- SetEntryText(widgets.label, credit_card.Label()); |
- SetEntryText(widgets.name_on_card, |
- credit_card.GetFieldText(AutoFillType(CREDIT_CARD_NAME))); |
- // Set obfuscated number if not empty. |
- credit_card_widgets_.back().original_card_number = |
- credit_card.GetFieldText(AutoFillType(CREDIT_CARD_NUMBER)); |
- string16 credit_card_number; |
- if (!widgets.original_card_number.empty()) |
- credit_card_number = credit_card.ObfuscatedNumber(); |
- SetEntryText(widgets.card_number, credit_card_number); |
- SetEntryText(widgets.expiration_month, |
- credit_card.GetFieldText(AutoFillType(CREDIT_CARD_EXP_MONTH))); |
- SetEntryText( |
- widgets.expiration_year, |
- credit_card.GetFieldText(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR))); |
- |
- // Two cases to consider: |
- // address not found - This means the address is not set and |
- // FindIndexOfAddress returns -1. -1 + 1 = 0, meaning the first item will |
- // be selected, "Choose existing address". |
- // |
- // address is found - The index returned needs to be offset by one in order |
- // to compensate for the first entry, "Choose existing address". |
- int index = FindIndexOfAddress(credit_card.billing_address()) + 1; |
- gtk_combo_box_set_active(GTK_COMBO_BOX(widgets.billing_address), index); |
- |
- gtk_box_pack_start(GTK_BOX(creditcards_vbox_), credit_card_widget, |
- FALSE, FALSE, 0); |
- gtk_widget_show_all(credit_card_widget); |
-} |
+int AutoFillDialog::GetSelectionType() { |
+ int state = SELECTION_EMPTY; |
+ gtk_tree_selection_selected_foreach( |
+ gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_)), RowIteratorFunction, |
+ &state); |
+ return state; |
+} |
+ |
+void AutoFillDialog::AddAddressToTree(const AutoFillProfile& profile, |
+ GtkTreeIter* iter) { |
+ gtk_list_store_append(list_store_, iter); |
+ gtk_list_store_set( |
+ list_store_, iter, |
+ COL_WEIGHT, PANGO_WEIGHT_NORMAL, |
+ COL_WEIGHT_SET, TRUE, |
+ COL_TITLE, UTF16ToUTF8(profile.PreviewSummary()).c_str(), |
+ -1); |
+} |
+ |
+void AutoFillDialog::AddCreditCardToTree(const CreditCard& credit_card, |
+ GtkTreeIter* iter) { |
+ gtk_list_store_append(list_store_, iter); |
+ gtk_list_store_set( |
+ list_store_, iter, |
+ COL_WEIGHT, PANGO_WEIGHT_NORMAL, |
+ COL_WEIGHT_SET, TRUE, |
+ COL_TITLE, UTF16ToUTF8(credit_card.PreviewSummary()).c_str(), |
+ -1); |
+} |
+ |
+void AutoFillDialog::GetSelectedEntries( |
+ std::vector<AutoFillProfile*>* profiles, |
+ std::vector<CreditCard*>* cards) { |
+ std::set<int> selection; |
+ gtk_tree::GetSelectedIndices( |
+ gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_)), &selection); |
+ |
+ for (std::set<int>::const_iterator i = selection.begin(); |
+ i != selection.end(); ++i) { |
+ // 2 is the number of header rows. |
+ int index = *i - 2; |
+ if (index >= 0 && |
+ index < static_cast<int>(personal_data_->profiles().size())) { |
+ profiles->push_back(personal_data_->profiles()[index]); |
+ continue; |
+ } |
-int AutoFillDialog::FindIndexOfAddress(string16 billing_address) { |
- int index = 0; |
- for (std::vector<AddressWidgets>::const_iterator iter = |
- address_widgets_.begin(); |
- iter != address_widgets_.end(); ++iter, ++index) { |
- std::string text = gtk_entry_get_text(GTK_ENTRY(iter->label)); |
- if (UTF8ToUTF16(text) == billing_address) |
- return index; |
+ // Empty row, header and separator are next. |
+ index -= profile_count_ + 3; |
+ if (index >= 0 && index < |
+ static_cast<int>(personal_data_->credit_cards().size())) { |
+ cards->push_back(personal_data_->credit_cards()[index]); |
+ } |
} |
- |
- return -1; |
} |
+} // namespace |
+ |
/////////////////////////////////////////////////////////////////////////////// |
// Factory/finder method: |
@@ -981,11 +660,7 @@ void ShowAutoFillDialog(gfx::NativeView parent, |
Profile* profile) { |
DCHECK(profile); |
- if (!dialog) { |
- dialog = new AutoFillDialog(observer, |
- profile->GetPersonalDataManager(), |
- NULL, |
- NULL); |
- } |
+ if (!dialog) |
+ dialog = new AutoFillDialog(profile, observer); |
dialog->Show(); |
} |