diff options
Diffstat (limited to 'chrome/browser/autofill/autofill_dialog_gtk.cc')
-rw-r--r-- | chrome/browser/autofill/autofill_dialog_gtk.cc | 666 |
1 files changed, 666 insertions, 0 deletions
diff --git a/chrome/browser/autofill/autofill_dialog_gtk.cc b/chrome/browser/autofill/autofill_dialog_gtk.cc new file mode 100644 index 0000000..ec8a1fe --- /dev/null +++ b/chrome/browser/autofill/autofill_dialog_gtk.cc @@ -0,0 +1,666 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/autofill/autofill_dialog.h" + +#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" +#include "base/utf_string_conversions.h" +#include "chrome/browser/autofill/autofill_manager.h" +#include "chrome/browser/autofill/autofill_profile.h" +#include "chrome/browser/autofill/credit_card.h" +#include "chrome/browser/autofill/form_group.h" +#include "chrome/browser/autofill/personal_data_manager.h" +#include "chrome/browser/autofill/phone_number.h" +#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/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" + +// 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); + +// 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); + +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, + public NotificationObserver { + public: + // 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(); + + private: + // 'destroy' signal handler. Calls DeleteSoon on the global singleton dialog + // object. + 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. + 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(); + + // Loads AutoFill profiles and credit cards using the PersonalDataManager. + void LoadAutoFillData(); + + // Creates the dialog UI widgets. + void InitializeWidgets(); + + // 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_; + + // The personal data manager, used to load AutoFill profiles and credit cards. + // Unowned pointer, may not be NULL. + PersonalDataManager* personal_data_; + + // Number of profiles we're displaying. + int profile_count_; + + // The AutoFill dialog. + GtkWidget* dialog_; + + BooleanPrefMember enable_form_autofill_; + + GtkWidget* form_autofill_enable_check_; + + // Displays the addresses then credit cards. + GtkListStore* list_store_; + + // Displays the list_store_. + GtkWidget* tree_; + + GtkWidget* add_address_button_; + GtkWidget* add_credit_card_button_; + GtkWidget* edit_button_; + GtkWidget* remove_button_; + + DISALLOW_COPY_AND_ASSIGN(AutoFillDialog); +}; + +// The singleton AutoFill dialog object. +static AutoFillDialog* dialog = NULL; + +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(); + + gtk_util::ShowDialogWithLocalizedSize(dialog_, + IDS_AUTOFILL_DIALOG_WIDTH_CHARS, + IDS_AUTOFILL_DIALOG_HEIGHT_LINES, + true); +} + +AutoFillDialog::~AutoFillDialog() { + // Removes observer if we are observing Profile load. Does nothing otherwise. + personal_data_->RemoveObserver(this); +} + +///////////////////////////////////////////////////////////////////////////// +// PersonalDataManager::Observer implementation: +void AutoFillDialog::OnPersonalDataLoaded() { + LoadAutoFillData(); +} + +void AutoFillDialog::OnPersonalDataChanged() { + LoadAutoFillData(); +} + +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(); + } +} + +void AutoFillDialog::Show() { + gtk_util::PresentWindow(dialog_, gtk_get_current_event_time()); +} + +void AutoFillDialog::OnDestroy(GtkWidget* widget) { + dialog = NULL; + MessageLoop::current()->DeleteSoon(FROM_HERE, this); +} + +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 == kAutoFillDialogAboutLink) + OnLinkActivated(); +} + +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(); +} + +void AutoFillDialog::OnRowActivated(GtkTreeView* tree_view, + GtkTreePath* path, + GtkTreeViewColumn* column) { + if (GetSelectionType() == SELECTION_SINGLE) + OnEdit(NULL); +} + +void AutoFillDialog::OnSelectionChanged(GtkTreeSelection* selection) { + UpdateWidgetState(); +} + +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); +} + +void AutoFillDialog::OnEdit(GtkWidget* widget) { + DCHECK_EQ(SELECTION_SINGLE, GetSelectionType()); + + 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]); +} + +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); + } + } + + 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); + } + } + + observer_->OnAutoFillDialogApply(&profiles, &cards); +} + +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() { + Browser* browser = BrowserList::GetLastActive(); + browser->OpenURL(GURL(kAutoFillLearnMoreUrl), GURL(), NEW_FOREGROUND_TAB, + PageTransition::TYPED); +} + +void AutoFillDialog::LoadAutoFillData() { + if (!personal_data_->IsDataLoaded()) { + UpdateWidgetState(); + return; + } + + // 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_++; + } + + // 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() { + dialog_ = gtk_dialog_new_with_buttons( + l10n_util::GetStringUTF8(IDS_AUTOFILL_OPTIONS).c_str(), + // AutoFill dialog is shared between all browser windows. + NULL, + // Non-modal. + GTK_DIALOG_NO_SEPARATOR, + GTK_STOCK_OK, + GTK_RESPONSE_OK, + NULL); + + 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_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); + + 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_HELP_LABEL).c_str()); + gtk_dialog_add_action_widget(GTK_DIALOG(dialog_), link, + kAutoFillDialogAboutLink); + + // Setting the link widget to secondary positions the button on the left side + // of the action area (vice versa for RTL layout). + gtk_button_box_set_child_secondary( + GTK_BUTTON_BOX(GTK_DIALOG(dialog_)->action_area), link, TRUE); +} + +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); + } +} + +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); + } + + if (is_header) { + *type |= AutoFillDialog::SELECTION_HEADER; + } else { + if ((*type & AutoFillDialog::SELECTION_SINGLE) == 0) + *type |= AutoFillDialog::SELECTION_SINGLE; + else + *type |= AutoFillDialog::SELECTION_MULTI; + } +} + +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; + } + + // 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]); + } + } +} + +} // namespace + +/////////////////////////////////////////////////////////////////////////////// +// Factory/finder method: + +void ShowAutoFillDialog(gfx::NativeView parent, + AutoFillDialogObserver* observer, + Profile* profile) { + DCHECK(profile); + + if (!dialog) + dialog = new AutoFillDialog(profile, observer); + dialog->Show(); +} |