summaryrefslogtreecommitdiffstats
path: root/chrome/browser/autofill/autofill_dialog_gtk.cc
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-14 03:27:11 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-14 03:27:11 +0000
commit548adcb9cb9343fe542f82cc35ffaa8f8279dfb6 (patch)
treeb32f0079645d72525d009e718751b58ab8b02bd5 /chrome/browser/autofill/autofill_dialog_gtk.cc
parente8c11e4801e7f4ca0c5f607d7bb489e3b1098a0c (diff)
downloadchromium_src-548adcb9cb9343fe542f82cc35ffaa8f8279dfb6.zip
chromium_src-548adcb9cb9343fe542f82cc35ffaa8f8279dfb6.tar.gz
chromium_src-548adcb9cb9343fe542f82cc35ffaa8f8279dfb6.tar.bz2
Makes the auto fill dialogs match the mocks.
BUG=44620 46634 TEST=Make sure the auto fill dialogs work correctly. Review URL: http://codereview.chromium.org/2975003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52274 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/autofill/autofill_dialog_gtk.cc')
-rw-r--r--chrome/browser/autofill/autofill_dialog_gtk.cc1239
1 files changed, 457 insertions, 782 deletions
diff --git a/chrome/browser/autofill/autofill_dialog_gtk.cc b/chrome/browser/autofill/autofill_dialog_gtk.cc
index 48a6903..ec8a1fe 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();
}