OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/autofill/autofill_dialog.h" | 5 #include "chrome/browser/autofill/autofill_dialog.h" |
6 | 6 |
7 #include <gtk/gtk.h> | 7 #include <gtk/gtk.h> |
8 | 8 |
| 9 #include <algorithm> |
9 #include <string> | 10 #include <string> |
10 #include <vector> | 11 #include <vector> |
11 | 12 |
| 13 #include "app/gtk_signal.h" |
12 #include "app/l10n_util.h" | 14 #include "app/l10n_util.h" |
13 #include "base/logging.h" | 15 #include "base/logging.h" |
14 #include "base/message_loop.h" | 16 #include "base/message_loop.h" |
15 #include "base/utf_string_conversions.h" | 17 #include "base/utf_string_conversions.h" |
16 #include "chrome/browser/autofill/autofill_manager.h" | 18 #include "chrome/browser/autofill/autofill_manager.h" |
17 #include "chrome/browser/autofill/autofill_profile.h" | 19 #include "chrome/browser/autofill/autofill_profile.h" |
18 #include "chrome/browser/autofill/credit_card.h" | 20 #include "chrome/browser/autofill/credit_card.h" |
19 #include "chrome/browser/autofill/form_group.h" | 21 #include "chrome/browser/autofill/form_group.h" |
20 #include "chrome/browser/autofill/personal_data_manager.h" | 22 #include "chrome/browser/autofill/personal_data_manager.h" |
21 #include "chrome/browser/autofill/phone_number.h" | 23 #include "chrome/browser/autofill/phone_number.h" |
22 #include "chrome/browser/browser.h" | 24 #include "chrome/browser/browser.h" |
23 #include "chrome/browser/browser_list.h" | 25 #include "chrome/browser/browser_list.h" |
24 #include "chrome/browser/gtk/gtk_chrome_link_button.h" | 26 #include "chrome/browser/gtk/gtk_chrome_link_button.h" |
| 27 #include "chrome/browser/gtk/gtk_tree.h" |
25 #include "chrome/browser/gtk/gtk_util.h" | 28 #include "chrome/browser/gtk/gtk_util.h" |
26 #include "chrome/browser/gtk/options/options_layout_gtk.h" | 29 #include "chrome/browser/metrics/user_metrics.h" |
| 30 #include "chrome/browser/pref_member.h" |
| 31 #include "chrome/browser/pref_service.h" |
27 #include "chrome/browser/profile.h" | 32 #include "chrome/browser/profile.h" |
| 33 #include "chrome/common/notification_details.h" |
| 34 #include "chrome/common/notification_observer.h" |
| 35 #include "chrome/common/notification_type.h" |
28 #include "chrome/common/pref_names.h" | 36 #include "chrome/common/pref_names.h" |
29 #include "gfx/gtk_util.h" | 37 #include "gfx/gtk_util.h" |
30 #include "grit/chromium_strings.h" | 38 #include "grit/chromium_strings.h" |
31 #include "grit/generated_resources.h" | 39 #include "grit/generated_resources.h" |
32 #include "grit/locale_settings.h" | 40 #include "grit/locale_settings.h" |
33 | 41 |
| 42 // Shows the editor for adding/editing an AutoFillProfile. If |
| 43 // |auto_fill_profile| is NULL, a new AutoFillProfile should be created. |
| 44 void ShowAutoFillProfileEditor(gfx::NativeView parent, |
| 45 AutoFillDialogObserver* observer, |
| 46 Profile* profile, |
| 47 AutoFillProfile* auto_fill_profile); |
| 48 |
| 49 // Shows the editor for adding/editing a CreditCard. If |credit_card| is NULL, a |
| 50 // new CreditCard should be created. |
| 51 void ShowAutoFillCreditCardEditor(gfx::NativeView parent, |
| 52 AutoFillDialogObserver* observer, |
| 53 Profile* profile, |
| 54 CreditCard* credit_card); |
| 55 |
34 namespace { | 56 namespace { |
35 | 57 |
36 // The name of the object property used to store an entry widget pointer on | 58 // The resource id for the 'About Autofill' link button. |
37 // another widget. | 59 const gint kAutoFillDialogAboutLink = 1; |
38 const char kButtonDataKey[] = "label-entry"; | |
39 | |
40 // How far we indent dialog widgets, in pixels. | |
41 const int kAutoFillDialogIndent = 5; | |
42 | |
43 // The resource id for the 'Learn more' link button. | |
44 const gint kAutoFillDialogLearnMoreLink = 1; | |
45 | |
46 // All of these widgets are GtkEntrys. | |
47 typedef struct _AddressWidgets { | |
48 GtkWidget* label; | |
49 GtkWidget* full_name; | |
50 GtkWidget* email; | |
51 GtkWidget* company_name; | |
52 GtkWidget* address_line1; | |
53 GtkWidget* address_line2; | |
54 GtkWidget* city; | |
55 GtkWidget* state; | |
56 GtkWidget* zipcode; | |
57 GtkWidget* country; | |
58 GtkWidget* phone; | |
59 GtkWidget* fax; | |
60 } AddressWidgets; | |
61 | |
62 // All of these widgets are GtkEntrys except for |billing_address|, which is | |
63 // a GtkComboBox. | |
64 typedef struct _CreditCardWidgets { | |
65 GtkWidget* label; | |
66 GtkWidget* name_on_card; | |
67 GtkWidget* card_number; | |
68 GtkWidget* expiration_month; | |
69 GtkWidget* expiration_year; | |
70 GtkWidget* billing_address; | |
71 GtkWidget* phone; | |
72 string16 original_card_number; | |
73 } CreditCardWidgets; | |
74 | |
75 // Adds an alignment around |widget| which indents the widget by |offset|. | |
76 GtkWidget* IndentWidget(GtkWidget* widget, int offset) { | |
77 GtkWidget* alignment = gtk_alignment_new(0, 0, 0, 0); | |
78 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, | |
79 offset, 0); | |
80 gtk_container_add(GTK_CONTAINER(alignment), widget); | |
81 return alignment; | |
82 } | |
83 | |
84 // Makes sure we use the gtk theme colors by loading the base color of an entry | |
85 // widget. | |
86 void SetWhiteBackground(GtkWidget* widget) { | |
87 GtkWidget* entry = gtk_entry_new(); | |
88 gtk_widget_ensure_style(entry); | |
89 GtkStyle* style = gtk_widget_get_style(entry); | |
90 gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, | |
91 &style->base[GTK_STATE_NORMAL]); | |
92 gtk_widget_destroy(entry); | |
93 } | |
94 | |
95 string16 GetEntryText(GtkWidget* entry) { | |
96 return UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(entry))); | |
97 } | |
98 | |
99 void SetEntryText(GtkWidget* entry, const string16& text) { | |
100 gtk_entry_set_text(GTK_ENTRY(entry), UTF16ToUTF8(text).c_str()); | |
101 } | |
102 | |
103 void SetButtonData(GtkWidget* widget, GtkWidget* entry) { | |
104 g_object_set_data(G_OBJECT(widget), kButtonDataKey, entry); | |
105 } | |
106 | |
107 GtkWidget* GetButtonData(GtkWidget* widget) { | |
108 return static_cast<GtkWidget*>( | |
109 g_object_get_data(G_OBJECT(widget), kButtonDataKey)); | |
110 } | |
111 | |
112 //////////////////////////////////////////////////////////////////////////////// | |
113 // Form Table helpers. | |
114 // | |
115 // The following functions can be used to create a form with labeled widgets. | |
116 // | |
117 | |
118 // Creates a form table with dimensions |rows| x |cols|. | |
119 GtkWidget* InitFormTable(int rows, int cols) { | |
120 // We have two table rows per form table row. | |
121 GtkWidget* table = gtk_table_new(rows * 2, cols, false); | |
122 gtk_table_set_row_spacings(GTK_TABLE(table), gtk_util::kControlSpacing); | |
123 gtk_table_set_col_spacings(GTK_TABLE(table), gtk_util::kFormControlSpacing); | |
124 | |
125 // Leave no space between the label and the widget. | |
126 for (int i = 0; i < rows; i++) | |
127 gtk_table_set_row_spacing(GTK_TABLE(table), i * 2, 0); | |
128 | |
129 return table; | |
130 } | |
131 | |
132 // Sets the label of the form widget at |row|,|col|. The label is |len| columns | |
133 // long. | |
134 void FormTableSetLabel( | |
135 GtkWidget* table, int row, int col, int len, int label_id) { | |
136 // We have two table rows per form table row. | |
137 row *= 2; | |
138 | |
139 std::string text; | |
140 if (label_id) | |
141 text = l10n_util::GetStringUTF8(label_id); | |
142 GtkWidget* label = gtk_label_new(text.c_str()); | |
143 gtk_misc_set_alignment(GTK_MISC(label), 0, 0); | |
144 gtk_table_attach(GTK_TABLE(table), label, | |
145 col, col + len, // Left col, right col. | |
146 row, row + 1, // Top row, bottom row. | |
147 GTK_FILL, GTK_FILL, // Options. | |
148 0, 0); // Padding. | |
149 } | |
150 | |
151 // Sets the form widget at |row|,|col|. The widget fills up |len| columns. If | |
152 // |expand| is true, the widget will expand to fill all of the extra space in | |
153 // the table row. | |
154 void FormTableSetWidget(GtkWidget* table, | |
155 GtkWidget* widget, | |
156 int row, int col, | |
157 int len, bool expand) { | |
158 const GtkAttachOptions expand_option = | |
159 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND); | |
160 GtkAttachOptions xoption = (expand) ? expand_option : GTK_FILL; | |
161 | |
162 // We have two table rows per form table row. | |
163 row *= 2; | |
164 gtk_table_attach(GTK_TABLE(table), widget, | |
165 col, col + len, // Left col, right col. | |
166 row + 1, row + 2, // Top row, bottom row. | |
167 xoption, GTK_FILL, // Options. | |
168 0, 0); // Padding. | |
169 } | |
170 | |
171 // Adds a labeled entry box to the form table at |row|,|col|. The entry widget | |
172 // fills up |len| columns. The returned widget is owned by |table| and should | |
173 // not be destroyed. | |
174 GtkWidget* FormTableAddEntry( | |
175 GtkWidget* table, int row, int col, int len, int label_id) { | |
176 FormTableSetLabel(table, row, col, len, label_id); | |
177 | |
178 GtkWidget* entry = gtk_entry_new(); | |
179 FormTableSetWidget(table, entry, row, col, len, false); | |
180 | |
181 return entry; | |
182 } | |
183 | |
184 // Adds a labeled entry box to the form table that will expand to fill extra | |
185 // space in the table row. | |
186 GtkWidget* FormTableAddExpandedEntry( | |
187 GtkWidget* table, int row, int col, int len, int label_id) { | |
188 FormTableSetLabel(table, row, col, len, label_id); | |
189 | |
190 GtkWidget* entry = gtk_entry_new(); | |
191 FormTableSetWidget(table, entry, row, col, len, true); | |
192 | |
193 return entry; | |
194 } | |
195 | |
196 // Adds a sized entry box to the form table. The entry widget width is set to | |
197 // |char_len|. | |
198 GtkWidget* FormTableAddSizedEntry( | |
199 GtkWidget* table, int row, int col, int char_len, int label_id) { | |
200 GtkWidget* entry = FormTableAddEntry(table, row, col, 1, label_id); | |
201 gtk_entry_set_width_chars(GTK_ENTRY(entry), char_len); | |
202 return entry; | |
203 } | |
204 | |
205 // Like FormTableAddEntry, but connects to the 'changed' signal. |changed| is a | |
206 // callback to handle the 'changed' signal that is emitted when the user edits | |
207 // the entry. |expander| is the expander widget that will be sent to the | |
208 // callback as the user data. | |
209 GtkWidget* FormTableAddLabelEntry( | |
210 GtkWidget* table, int row, int col, int len, int label_id, | |
211 GtkWidget* expander, GCallback changed) { | |
212 FormTableSetLabel(table, row, col, len, label_id); | |
213 | |
214 GtkWidget* entry = gtk_entry_new(); | |
215 g_signal_connect(entry, "changed", changed, expander); | |
216 FormTableSetWidget(table, entry, row, col, len, false); | |
217 | |
218 return entry; | |
219 } | |
220 | |
221 } // namespace | |
222 | 60 |
223 //////////////////////////////////////////////////////////////////////////////// | 61 //////////////////////////////////////////////////////////////////////////////// |
224 // AutoFillDialog | 62 // AutoFillDialog |
225 // | 63 // |
226 // The contents of the AutoFill dialog. This dialog allows users to add, edit | 64 // The contents of the AutoFill dialog. This dialog allows users to add, edit |
227 // and remove AutoFill profiles. | 65 // and remove AutoFill profiles. |
228 class AutoFillDialog : public PersonalDataManager::Observer { | 66 class AutoFillDialog : public PersonalDataManager::Observer, |
| 67 public NotificationObserver { |
229 public: | 68 public: |
230 AutoFillDialog(AutoFillDialogObserver* observer, | 69 // Identifiers for columns in the store. |
231 PersonalDataManager* personal_data_manager, | 70 enum Column { |
232 AutoFillProfile* imported_profile, | 71 COL_TITLE = 0, |
233 CreditCard* imported_credit_card); | 72 COL_IS_HEADER, |
| 73 COL_IS_SEPARATOR, // Identifies an empty row used to reserve visual space. |
| 74 COL_WEIGHT, |
| 75 COL_WEIGHT_SET, |
| 76 COL_COUNT |
| 77 }; |
| 78 |
| 79 // Used to identify the selection. See GetSelectionType. |
| 80 enum SelectionType { |
| 81 // Nothing is selected. |
| 82 SELECTION_EMPTY = 0, |
| 83 |
| 84 // At least one header/separator row is selected. |
| 85 SELECTION_HEADER = 1 << 0, |
| 86 |
| 87 // At least one non-header/separator row is selected. |
| 88 SELECTION_SINGLE = 1 << 1, |
| 89 |
| 90 // Multiple non-header/separator rows are selected. |
| 91 SELECTION_MULTI = 1 << 2, |
| 92 }; |
| 93 |
| 94 AutoFillDialog(Profile* profile, AutoFillDialogObserver* observer); |
234 ~AutoFillDialog(); | 95 ~AutoFillDialog(); |
235 | 96 |
236 // PersonalDataManager::Observer implementation: | 97 // PersonalDataManager::Observer implementation: |
237 void OnPersonalDataLoaded(); | 98 void OnPersonalDataLoaded(); |
| 99 void OnPersonalDataChanged(); |
| 100 |
| 101 // NotificationObserver implementation: |
| 102 virtual void Observe(NotificationType type, |
| 103 const NotificationSource& source, |
| 104 const NotificationDetails& details); |
238 | 105 |
239 // Shows the AutoFill dialog. | 106 // Shows the AutoFill dialog. |
240 void Show(); | 107 void Show(); |
241 | 108 |
242 private: | 109 private: |
243 // 'destroy' signal handler. Calls DeleteSoon on the global singleton dialog | 110 // 'destroy' signal handler. Calls DeleteSoon on the global singleton dialog |
244 // object. | 111 // object. |
245 static void OnDestroy(GtkWidget* widget, AutoFillDialog* autofill_dialog); | 112 CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnDestroy); |
246 | 113 |
247 // 'response' signal handler. Notifies the AutoFillDialogObserver that new | 114 // 'response' signal handler. Notifies the AutoFillDialogObserver that new |
248 // data is available if the response is GTK_RESPONSE_APPLY or GTK_RESPONSE_OK. | 115 // data is available if the response is GTK_RESPONSE_APPLY or GTK_RESPONSE_OK. |
249 // We close the dialog if the response is GTK_RESPONSE_OK or | 116 // We close the dialog if the response is GTK_RESPONSE_OK or |
250 // GTK_RESPONSE_CANCEL. | 117 // GTK_RESPONSE_CANCEL. |
251 static void OnResponse(GtkDialog* dialog, gint response_id, | 118 CHROMEG_CALLBACK_1(AutoFillDialog, void, OnResponse, GtkDialog*, gint); |
252 AutoFillDialog* autofill_dialog); | |
253 | 119 |
254 // 'clicked' signal handler. Adds a new address. | 120 CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnAutoFillCheckToggled); |
255 static void OnAddAddressClicked(GtkButton* button, AutoFillDialog* dialog); | 121 CHROMEG_CALLBACK_2(AutoFillDialog, void, OnRowActivated, GtkTreeView*, |
256 | 122 GtkTreePath*, GtkTreeViewColumn*); |
257 // 'clicked' signal handler. Adds a new credit card. | 123 CHROMEG_CALLBACK_0(AutoFillDialog, void, OnSelectionChanged, |
258 static void OnAddCreditCardClicked(GtkButton* button, AutoFillDialog* dialog); | 124 GtkTreeSelection*); |
259 | 125 CHROMEG_CALLBACK_1(AutoFillDialog, gboolean, OnCheckRowIsSeparator, |
260 // 'clicked' signal handler. Deletes the associated address. | 126 GtkTreeModel*, GtkTreeIter*); |
261 static void OnDeleteAddressClicked(GtkButton* button, AutoFillDialog* dialog); | 127 CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnAddAddress); |
262 | 128 CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnAddCreditCard); |
263 // 'clicked' signal handler. Deletes the associated credit card. | 129 CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnEdit); |
264 static void OnDeleteCreditCardClicked(GtkButton* button, | 130 CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnRemove); |
265 AutoFillDialog* dialog); | 131 CHROMEG_CALLBACK_3(AutoFillDialog, gboolean, OnSelectionFilter, |
266 | 132 GtkTreeSelection*, GtkTreeModel*, GtkTreePath*, gboolean); |
267 // 'changed' signal handler. Updates the title of the expander widget with | |
268 // the contents of the label entry widget. | |
269 static void OnLabelChanged(GtkEntry* label, GtkWidget* expander); | |
270 | 133 |
271 // Opens the 'Learn more' link in a new foreground tab. | 134 // Opens the 'Learn more' link in a new foreground tab. |
272 void OnLinkActivated(); | 135 void OnLinkActivated(); |
273 | 136 |
274 // Loads AutoFill profiles and credit cards using the PersonalDataManager. | 137 // Loads AutoFill profiles and credit cards using the PersonalDataManager. |
275 void LoadAutoFillData(); | 138 void LoadAutoFillData(); |
276 | 139 |
277 // Creates the dialog UI widgets. | 140 // Creates the dialog UI widgets. |
278 void InitializeWidgets(); | 141 void InitializeWidgets(); |
279 | 142 |
280 // Initializes the group widgets and returns their container. |name_id| is | 143 // Updates the state of the various widgets dependant upon the state of the |
281 // the resource ID of the group label. |button_id| is the resource name of | 144 // selection, loaded state and whether AutoFill is enabled. |
282 // the button label. |clicked_callback| is a callback that handles the | 145 void UpdateWidgetState(); |
283 // 'clicked' signal emitted when the user presses the 'Add' button. | |
284 GtkWidget* InitGroup(int label_id, | |
285 int button_id, | |
286 GCallback clicked_callback); | |
287 | 146 |
288 // Initializes the expander, frame and table widgets used to hold the address | 147 // Returns a bitmask of the selection types. |
289 // and credit card forms. |name_id| is the resource id of the label of the | 148 int GetSelectionType(); |
290 // expander widget. The content vbox widget is returned in |content_vbox|. | |
291 // Returns the expander widget. | |
292 GtkWidget* InitGroupContentArea(int name_id, GtkWidget** content_vbox); | |
293 | 149 |
294 // Returns a GtkExpander that is added to the appropriate vbox. Each method | 150 void AddAddressToTree(const AutoFillProfile& profile, GtkTreeIter* iter); |
295 // adds the necessary widgets and layout required to fill out information | |
296 // for either an address or a credit card. The expander will be expanded by | |
297 // default if |expand| is true. | |
298 GtkWidget* AddNewAddress(bool expand); | |
299 GtkWidget* AddNewCreditCard(bool expand); | |
300 | 151 |
301 // Adds a new address filled out with information from |profile|. | 152 void AddCreditCardToTree(const CreditCard& credit_card, GtkTreeIter* iter); |
302 void AddAddress(const AutoFillProfile& profile); | |
303 | 153 |
304 // Adds a new credit card filled out with information from |credit_card|. | 154 // Returns the set of selected profiles and cards. The values placed in |
305 void AddCreditCard(const CreditCard& credit_card); | 155 // the specified vectors are owned by PersonalDataManager. |
| 156 void GetSelectedEntries(std::vector<AutoFillProfile*>* profiles, |
| 157 std::vector<CreditCard*>* cards); |
306 | 158 |
307 // Returns the index of |billing_address| in the list of profiles. Returns -1 | 159 Profile* profile_; |
308 // if the address is not found. | |
309 int FindIndexOfAddress(string16 billing_address); | |
310 | 160 |
311 // Our observer. May not be NULL. | 161 // Our observer. May not be NULL. |
312 AutoFillDialogObserver* observer_; | 162 AutoFillDialogObserver* observer_; |
313 | 163 |
314 // The personal data manager, used to load AutoFill profiles and credit cards. | 164 // The personal data manager, used to load AutoFill profiles and credit cards. |
315 // Unowned pointer, may not be NULL. | 165 // Unowned pointer, may not be NULL. |
316 PersonalDataManager* personal_data_; | 166 PersonalDataManager* personal_data_; |
317 | 167 |
318 // The imported profile. May be NULL. | 168 // Number of profiles we're displaying. |
319 AutoFillProfile* imported_profile_; | 169 int profile_count_; |
320 | |
321 // The imported credit card. May be NULL. | |
322 CreditCard* imported_credit_card_; | |
323 | |
324 // The list of current AutoFill profiles. | |
325 std::vector<AutoFillProfile> profiles_; | |
326 | |
327 // The list of current AutoFill credit cards. | |
328 std::vector<CreditCard> credit_cards_; | |
329 | |
330 // The list of address widgets, used to modify the AutoFill profiles. | |
331 std::vector<AddressWidgets> address_widgets_; | |
332 | |
333 // The list of credit card widgets, used to modify the stored credit cards. | |
334 std::vector<CreditCardWidgets> credit_card_widgets_; | |
335 | 170 |
336 // The AutoFill dialog. | 171 // The AutoFill dialog. |
337 GtkWidget* dialog_; | 172 GtkWidget* dialog_; |
338 | 173 |
339 // The addresses group. | 174 BooleanPrefMember enable_form_autofill_; |
340 GtkWidget* addresses_vbox_; | |
341 | 175 |
342 // The credit cards group. | 176 GtkWidget* form_autofill_enable_check_; |
343 GtkWidget* creditcards_vbox_; | 177 |
| 178 // Displays the addresses then credit cards. |
| 179 GtkListStore* list_store_; |
| 180 |
| 181 // Displays the list_store_. |
| 182 GtkWidget* tree_; |
| 183 |
| 184 GtkWidget* add_address_button_; |
| 185 GtkWidget* add_credit_card_button_; |
| 186 GtkWidget* edit_button_; |
| 187 GtkWidget* remove_button_; |
344 | 188 |
345 DISALLOW_COPY_AND_ASSIGN(AutoFillDialog); | 189 DISALLOW_COPY_AND_ASSIGN(AutoFillDialog); |
346 }; | 190 }; |
347 | 191 |
348 // The singleton AutoFill dialog object. | 192 // The singleton AutoFill dialog object. |
349 static AutoFillDialog* dialog = NULL; | 193 static AutoFillDialog* dialog = NULL; |
350 | 194 |
351 AutoFillDialog::AutoFillDialog(AutoFillDialogObserver* observer, | 195 AutoFillDialog::AutoFillDialog(Profile* profile, |
352 PersonalDataManager* personal_data_manager, | 196 AutoFillDialogObserver* observer) |
353 AutoFillProfile* imported_profile, | 197 : profile_(profile), |
354 CreditCard* imported_credit_card) | 198 observer_(observer), |
355 : observer_(observer), | 199 personal_data_(profile->GetPersonalDataManager()), |
356 personal_data_(personal_data_manager), | 200 profile_count_(0) { |
357 imported_profile_(imported_profile), | |
358 imported_credit_card_(imported_credit_card) { | |
359 DCHECK(observer_); | 201 DCHECK(observer_); |
360 DCHECK(personal_data_); | 202 DCHECK(personal_data_); |
361 | 203 |
| 204 enable_form_autofill_.Init(prefs::kAutoFillEnabled, profile->GetPrefs(), |
| 205 this); |
| 206 |
| 207 personal_data_->SetObserver(this); |
| 208 |
362 InitializeWidgets(); | 209 InitializeWidgets(); |
363 LoadAutoFillData(); | 210 LoadAutoFillData(); |
364 | 211 |
365 gtk_util::ShowDialogWithLocalizedSize(dialog_, | 212 gtk_util::ShowDialogWithLocalizedSize(dialog_, |
366 IDS_AUTOFILL_DIALOG_WIDTH_CHARS, | 213 IDS_AUTOFILL_DIALOG_WIDTH_CHARS, |
367 IDS_AUTOFILL_DIALOG_HEIGHT_LINES, | 214 IDS_AUTOFILL_DIALOG_HEIGHT_LINES, |
368 true); | 215 true); |
369 } | 216 } |
370 | 217 |
371 AutoFillDialog::~AutoFillDialog() { | 218 AutoFillDialog::~AutoFillDialog() { |
372 // Removes observer if we are observing Profile load. Does nothing otherwise. | 219 // Removes observer if we are observing Profile load. Does nothing otherwise. |
373 if (personal_data_) | 220 personal_data_->RemoveObserver(this); |
374 personal_data_->RemoveObserver(this); | |
375 } | 221 } |
376 | 222 |
377 ///////////////////////////////////////////////////////////////////////////// | 223 ///////////////////////////////////////////////////////////////////////////// |
378 // PersonalDataManager::Observer implementation: | 224 // PersonalDataManager::Observer implementation: |
379 void AutoFillDialog::OnPersonalDataLoaded() { | 225 void AutoFillDialog::OnPersonalDataLoaded() { |
380 personal_data_->RemoveObserver(this); | |
381 LoadAutoFillData(); | 226 LoadAutoFillData(); |
382 } | 227 } |
383 | 228 |
| 229 void AutoFillDialog::OnPersonalDataChanged() { |
| 230 LoadAutoFillData(); |
| 231 } |
| 232 |
| 233 void AutoFillDialog::Observe(NotificationType type, |
| 234 const NotificationSource& source, |
| 235 const NotificationDetails& details) { |
| 236 DCHECK_EQ(NotificationType::PREF_CHANGED, type.value); |
| 237 const std::wstring* pref_name = Details<std::wstring>(details).ptr(); |
| 238 if (!pref_name || *pref_name == prefs::kAutoFillEnabled) { |
| 239 gtk_toggle_button_set_active( |
| 240 GTK_TOGGLE_BUTTON(form_autofill_enable_check_), |
| 241 enable_form_autofill_.GetValue() ? TRUE : FALSE); |
| 242 UpdateWidgetState(); |
| 243 } |
| 244 } |
| 245 |
384 void AutoFillDialog::Show() { | 246 void AutoFillDialog::Show() { |
385 gtk_util::PresentWindow(dialog_, gtk_get_current_event_time()); | 247 gtk_util::PresentWindow(dialog_, gtk_get_current_event_time()); |
386 } | 248 } |
387 | 249 |
388 // static | 250 void AutoFillDialog::OnDestroy(GtkWidget* widget) { |
389 void AutoFillDialog::OnDestroy(GtkWidget* widget, | |
390 AutoFillDialog* autofill_dialog) { | |
391 dialog = NULL; | 251 dialog = NULL; |
392 MessageLoop::current()->DeleteSoon(FROM_HERE, autofill_dialog); | 252 MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
393 } | 253 } |
394 | 254 |
395 static AutoFillProfile AutoFillProfileFromWidgetValues( | 255 void AutoFillDialog::OnResponse(GtkDialog* dialog, gint response_id) { |
396 const AddressWidgets& widgets) { | |
397 // TODO(jhawkins): unique id? | |
398 AutoFillProfile profile(GetEntryText(widgets.label), 0); | |
399 profile.SetInfo(AutoFillType(NAME_FULL), | |
400 GetEntryText(widgets.full_name)); | |
401 profile.SetInfo(AutoFillType(EMAIL_ADDRESS), | |
402 GetEntryText(widgets.email)); | |
403 profile.SetInfo(AutoFillType(COMPANY_NAME), | |
404 GetEntryText(widgets.company_name)); | |
405 profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE1), | |
406 GetEntryText(widgets.address_line1)); | |
407 profile.SetInfo(AutoFillType(ADDRESS_HOME_LINE2), | |
408 GetEntryText(widgets.address_line2)); | |
409 profile.SetInfo(AutoFillType(ADDRESS_HOME_CITY), | |
410 GetEntryText(widgets.city)); | |
411 profile.SetInfo(AutoFillType(ADDRESS_HOME_STATE), | |
412 GetEntryText(widgets.state)); | |
413 profile.SetInfo(AutoFillType(ADDRESS_HOME_ZIP), | |
414 GetEntryText(widgets.zipcode)); | |
415 profile.SetInfo(AutoFillType(ADDRESS_HOME_COUNTRY), | |
416 GetEntryText(widgets.country)); | |
417 | |
418 string16 number, city_code, country_code; | |
419 PhoneNumber::ParsePhoneNumber( | |
420 GetEntryText(widgets.phone), &number, &city_code, &country_code); | |
421 profile.SetInfo(AutoFillType(PHONE_HOME_COUNTRY_CODE), country_code); | |
422 profile.SetInfo(AutoFillType(PHONE_HOME_CITY_CODE), city_code); | |
423 profile.SetInfo(AutoFillType(PHONE_HOME_NUMBER), number); | |
424 | |
425 PhoneNumber::ParsePhoneNumber( | |
426 GetEntryText(widgets.fax), &number, &city_code, &country_code); | |
427 profile.SetInfo(AutoFillType(PHONE_FAX_COUNTRY_CODE), country_code); | |
428 profile.SetInfo(AutoFillType(PHONE_FAX_CITY_CODE), city_code); | |
429 profile.SetInfo(AutoFillType(PHONE_FAX_NUMBER), number); | |
430 | |
431 return profile; | |
432 } | |
433 | |
434 static CreditCard CreditCardFromWidgetValues( | |
435 const CreditCardWidgets& widgets) { | |
436 // TODO(jhawkins): unique id? | |
437 CreditCard credit_card(GetEntryText(widgets.label), 0); | |
438 credit_card.SetInfo(AutoFillType(CREDIT_CARD_NAME), | |
439 GetEntryText(widgets.name_on_card)); | |
440 credit_card.SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH), | |
441 GetEntryText(widgets.expiration_month)); | |
442 credit_card.SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), | |
443 GetEntryText(widgets.expiration_year)); | |
444 | |
445 // If the CC number starts with an asterisk, then we know that the user has | |
446 // not modified the credit card number at the least, so use the original CC | |
447 // number in this case. | |
448 string16 cc_number = GetEntryText(widgets.card_number); | |
449 if (!cc_number.empty() && cc_number[0] == '*') | |
450 credit_card.SetInfo(AutoFillType(CREDIT_CARD_NUMBER), | |
451 widgets.original_card_number); | |
452 else | |
453 credit_card.SetInfo(AutoFillType(CREDIT_CARD_NUMBER), | |
454 GetEntryText(widgets.card_number)); | |
455 | |
456 std::string text = | |
457 gtk_combo_box_get_active_text(GTK_COMBO_BOX(widgets.billing_address)); | |
458 if (text != | |
459 l10n_util::GetStringUTF8(IDS_AUTOFILL_DIALOG_CHOOSE_EXISTING_ADDRESS)) { | |
460 // TODO(jhawkins): Should we validate the billing address combobox? | |
461 credit_card.set_billing_address(UTF8ToUTF16(text)); | |
462 } | |
463 | |
464 return credit_card; | |
465 } | |
466 | |
467 // static | |
468 void AutoFillDialog::OnResponse(GtkDialog* dialog, gint response_id, | |
469 AutoFillDialog* autofill_dialog) { | |
470 if (response_id == GTK_RESPONSE_APPLY || response_id == GTK_RESPONSE_OK) { | |
471 autofill_dialog->profiles_.clear(); | |
472 for (std::vector<AddressWidgets>::const_iterator iter = | |
473 autofill_dialog->address_widgets_.begin(); | |
474 iter != autofill_dialog->address_widgets_.end(); | |
475 ++iter) { | |
476 AutoFillProfile profile = AutoFillProfileFromWidgetValues(*iter); | |
477 autofill_dialog->profiles_.push_back(profile); | |
478 } | |
479 | |
480 autofill_dialog->credit_cards_.clear(); | |
481 for (std::vector<CreditCardWidgets>::const_iterator iter = | |
482 autofill_dialog->credit_card_widgets_.begin(); | |
483 iter != autofill_dialog->credit_card_widgets_.end(); | |
484 ++iter) { | |
485 CreditCard credit_card = CreditCardFromWidgetValues(*iter); | |
486 autofill_dialog->credit_cards_.push_back(credit_card); | |
487 } | |
488 | |
489 autofill_dialog->observer_->OnAutoFillDialogApply( | |
490 &autofill_dialog->profiles_, | |
491 &autofill_dialog->credit_cards_); | |
492 } | |
493 | |
494 if (response_id == GTK_RESPONSE_OK || | 256 if (response_id == GTK_RESPONSE_OK || |
495 response_id == GTK_RESPONSE_CANCEL || | 257 response_id == GTK_RESPONSE_CANCEL || |
496 response_id == GTK_RESPONSE_DELETE_EVENT) { | 258 response_id == GTK_RESPONSE_DELETE_EVENT) { |
497 gtk_widget_destroy(GTK_WIDGET(dialog)); | 259 gtk_widget_destroy(GTK_WIDGET(dialog)); |
498 } | 260 } |
499 | 261 |
500 if (response_id == kAutoFillDialogLearnMoreLink) | 262 if (response_id == kAutoFillDialogAboutLink) |
501 autofill_dialog->OnLinkActivated(); | 263 OnLinkActivated(); |
502 } | 264 } |
503 | 265 |
504 // static | 266 void AutoFillDialog::OnAutoFillCheckToggled(GtkWidget* widget) { |
505 void AutoFillDialog::OnAddAddressClicked(GtkButton* button, | 267 bool enabled = gtk_toggle_button_get_active( |
506 AutoFillDialog* dialog) { | 268 GTK_TOGGLE_BUTTON(form_autofill_enable_check_)); |
507 GtkWidget* new_address = dialog->AddNewAddress(true); | 269 if (enabled) { |
508 gtk_box_pack_start(GTK_BOX(dialog->addresses_vbox_), new_address, | 270 UserMetrics::RecordAction(UserMetricsAction("Options_FormAutofill_Enable"), |
509 FALSE, FALSE, 0); | 271 profile_); |
510 gtk_widget_show_all(new_address); | 272 } else { |
| 273 UserMetrics::RecordAction(UserMetricsAction("Options_FormAutofill_Disable"), |
| 274 profile_); |
| 275 } |
| 276 enable_form_autofill_.SetValue(enabled); |
| 277 profile_->GetPrefs()->ScheduleSavePersistentPrefs(); |
| 278 UpdateWidgetState(); |
511 } | 279 } |
512 | 280 |
513 // static | 281 void AutoFillDialog::OnRowActivated(GtkTreeView* tree_view, |
514 void AutoFillDialog::OnAddCreditCardClicked(GtkButton* button, | 282 GtkTreePath* path, |
515 AutoFillDialog* dialog) { | 283 GtkTreeViewColumn* column) { |
516 GtkWidget* new_creditcard = dialog->AddNewCreditCard(true); | 284 if (GetSelectionType() == SELECTION_SINGLE) |
517 gtk_box_pack_start(GTK_BOX(dialog->creditcards_vbox_), new_creditcard, | 285 OnEdit(NULL); |
518 FALSE, FALSE, 0); | |
519 gtk_widget_show_all(new_creditcard); | |
520 } | 286 } |
521 | 287 |
522 // static | 288 void AutoFillDialog::OnSelectionChanged(GtkTreeSelection* selection) { |
523 void AutoFillDialog::OnDeleteAddressClicked(GtkButton* button, | 289 UpdateWidgetState(); |
524 AutoFillDialog* dialog) { | 290 } |
525 GtkWidget* entry = GetButtonData(GTK_WIDGET(button)); | |
526 string16 label = GetEntryText(entry); | |
527 | 291 |
528 // TODO(jhawkins): Base this on ID. | 292 gboolean AutoFillDialog::OnCheckRowIsSeparator(GtkTreeModel* model, |
| 293 GtkTreeIter* iter) { |
| 294 gboolean is_separator; |
| 295 gtk_tree_model_get(model, iter, COL_IS_SEPARATOR, &is_separator, -1); |
| 296 return is_separator; |
| 297 } |
529 | 298 |
530 // Remove the profile. | 299 void AutoFillDialog::OnAddAddress(GtkWidget* widget) { |
531 for (std::vector<AutoFillProfile>::iterator iter = dialog->profiles_.begin(); | 300 ShowAutoFillProfileEditor(NULL, observer_, profile_, NULL); |
532 iter != dialog->profiles_.end(); | 301 } |
533 ++iter) { | 302 |
534 if (iter->Label() == label) { | 303 void AutoFillDialog::OnAddCreditCard(GtkWidget* widget) { |
535 dialog->profiles_.erase(iter); | 304 ShowAutoFillCreditCardEditor(NULL, observer_, profile_, NULL); |
536 break; | 305 } |
| 306 |
| 307 void AutoFillDialog::OnEdit(GtkWidget* widget) { |
| 308 DCHECK_EQ(SELECTION_SINGLE, GetSelectionType()); |
| 309 |
| 310 std::vector<AutoFillProfile*> profiles; |
| 311 std::vector<CreditCard*> cards; |
| 312 |
| 313 GetSelectedEntries(&profiles, &cards); |
| 314 |
| 315 if (profiles.size() == 1) |
| 316 ShowAutoFillProfileEditor(dialog_, observer_, profile_, profiles[0]); |
| 317 else if (cards.size() == 1) |
| 318 ShowAutoFillCreditCardEditor(dialog_, observer_, profile_, cards[0]); |
| 319 } |
| 320 |
| 321 void AutoFillDialog::OnRemove(GtkWidget* widget) { |
| 322 PersonalDataManager* data_manager = profile_->GetPersonalDataManager(); |
| 323 std::vector<AutoFillProfile*> selected_profiles; |
| 324 std::vector<CreditCard*> selected_cards; |
| 325 |
| 326 GetSelectedEntries(&selected_profiles, &selected_cards); |
| 327 |
| 328 std::vector<AutoFillProfile> profiles; |
| 329 for (std::vector<AutoFillProfile*>::const_iterator i = |
| 330 data_manager->profiles().begin(); |
| 331 i != data_manager->profiles().end(); ++i) { |
| 332 if (std::find(selected_profiles.begin(), selected_profiles.end(), *i) == |
| 333 selected_profiles.end()) { |
| 334 profiles.push_back(**i); |
537 } | 335 } |
538 } | 336 } |
539 | 337 |
540 // Remove the set of address widgets. | 338 std::vector<CreditCard> cards; |
541 for (std::vector<AddressWidgets>::iterator iter = | 339 for (std::vector<CreditCard*>::const_iterator i = |
542 dialog->address_widgets_.begin(); | 340 data_manager->credit_cards().begin(); |
543 iter != dialog->address_widgets_.end(); | 341 i != data_manager->credit_cards().end(); ++i) { |
544 ++iter) { | 342 if (std::find(selected_cards.begin(), selected_cards.end(), *i) == |
545 if (iter->label == entry) { | 343 selected_cards.end()) { |
546 dialog->address_widgets_.erase(iter); | 344 cards.push_back(**i); |
547 break; | |
548 } | 345 } |
549 } | 346 } |
550 | 347 |
551 // Get back to the expander widget. | 348 observer_->OnAutoFillDialogApply(&profiles, &cards); |
552 GtkWidget* expander = gtk_widget_get_ancestor(GTK_WIDGET(button), | |
553 GTK_TYPE_EXPANDER); | |
554 DCHECK(expander); | |
555 | |
556 // Destroying the widget will also remove it from the parent container. | |
557 gtk_widget_destroy(expander); | |
558 } | 349 } |
559 | 350 |
560 // static | 351 gboolean AutoFillDialog::OnSelectionFilter(GtkTreeSelection* selection, |
561 void AutoFillDialog::OnDeleteCreditCardClicked(GtkButton* button, | 352 GtkTreeModel* model, |
562 AutoFillDialog* dialog) { | 353 GtkTreePath* path, |
563 GtkWidget* entry = GetButtonData(GTK_WIDGET(button)); | 354 gboolean path_currently_selected) { |
564 string16 label = GetEntryText(entry); | 355 GtkTreeIter iter; |
565 | 356 if (!gtk_tree_model_get_iter(model, &iter, path)) { |
566 // TODO(jhawkins): Base this on ID. | 357 NOTREACHED(); |
567 | 358 return TRUE; |
568 // Remove the credit card. | |
569 for (std::vector<CreditCard>::iterator iter = dialog->credit_cards_.begin(); | |
570 iter != dialog->credit_cards_.end(); | |
571 ++iter) { | |
572 if (iter->Label() == label) { | |
573 dialog->credit_cards_.erase(iter); | |
574 break; | |
575 } | |
576 } | 359 } |
577 | 360 gboolean is_header; |
578 // Remove the set of credit widgets. | 361 gboolean is_separator; |
579 for (std::vector<CreditCardWidgets>::iterator iter = | 362 gtk_tree_model_get(model, &iter, COL_IS_HEADER, &is_header, |
580 dialog->credit_card_widgets_.begin(); | 363 COL_IS_SEPARATOR, &is_separator, -1); |
581 iter != dialog->credit_card_widgets_.end(); | 364 return !is_header && !is_separator; |
582 ++iter) { | |
583 if (iter->label == entry) { | |
584 dialog->credit_card_widgets_.erase(iter); | |
585 break; | |
586 } | |
587 } | |
588 | |
589 // Get back to the expander widget. | |
590 GtkWidget* expander = gtk_widget_get_ancestor(GTK_WIDGET(button), | |
591 GTK_TYPE_EXPANDER); | |
592 DCHECK(expander); | |
593 | |
594 // Destroying the widget will also remove it from the parent container. | |
595 gtk_widget_destroy(expander); | |
596 } | |
597 | |
598 // static | |
599 void AutoFillDialog::OnLabelChanged(GtkEntry* label, GtkWidget* expander) { | |
600 gtk_expander_set_label(GTK_EXPANDER(expander), gtk_entry_get_text(label)); | |
601 } | 365 } |
602 | 366 |
603 void AutoFillDialog::OnLinkActivated() { | 367 void AutoFillDialog::OnLinkActivated() { |
604 Browser* browser = BrowserList::GetLastActive(); | 368 Browser* browser = BrowserList::GetLastActive(); |
605 browser->OpenURL(GURL(kAutoFillLearnMoreUrl), GURL(), NEW_FOREGROUND_TAB, | 369 browser->OpenURL(GURL(kAutoFillLearnMoreUrl), GURL(), NEW_FOREGROUND_TAB, |
606 PageTransition::TYPED); | 370 PageTransition::TYPED); |
607 } | 371 } |
608 | 372 |
609 void AutoFillDialog::LoadAutoFillData() { | 373 void AutoFillDialog::LoadAutoFillData() { |
610 if (!personal_data_->IsDataLoaded()) { | 374 if (!personal_data_->IsDataLoaded()) { |
611 personal_data_->SetObserver(this); | 375 UpdateWidgetState(); |
612 return; | 376 return; |
613 } | 377 } |
614 | 378 |
615 if (imported_profile_) { | 379 // Rebuild the underyling store. |
616 profiles_.push_back(*imported_profile_); | 380 gtk_list_store_clear(list_store_); |
617 AddAddress(*imported_profile_); | |
618 } else { | |
619 for (std::vector<AutoFillProfile*>::const_iterator iter = | |
620 personal_data_->profiles().begin(); | |
621 iter != personal_data_->profiles().end(); ++iter) { | |
622 // The profile list is terminated by a NULL entry; | |
623 if (!*iter) | |
624 break; | |
625 | 381 |
626 AutoFillProfile* profile = *iter; | 382 GtkTreeIter iter; |
627 profiles_.push_back(*profile); | 383 // Address title. |
628 AddAddress(*profile); | 384 gtk_list_store_append(list_store_, &iter); |
629 } | 385 gtk_list_store_set( |
| 386 list_store_, &iter, |
| 387 COL_WEIGHT, PANGO_WEIGHT_BOLD, |
| 388 COL_WEIGHT_SET, TRUE, |
| 389 COL_TITLE, |
| 390 l10n_util::GetStringUTF8(IDS_AUTOFILL_ADDRESSES_GROUP_NAME).c_str(), |
| 391 COL_IS_HEADER, TRUE, |
| 392 -1); |
| 393 // Address separator. |
| 394 gtk_list_store_append(list_store_, &iter); |
| 395 gtk_list_store_set( |
| 396 list_store_, &iter, |
| 397 COL_IS_SEPARATOR, TRUE, |
| 398 -1); |
| 399 |
| 400 // The addresses. |
| 401 profile_count_ = 0; |
| 402 for (std::vector<AutoFillProfile*>::const_iterator i = |
| 403 personal_data_->profiles().begin(); |
| 404 i != personal_data_->profiles().end(); ++i) { |
| 405 AddAddressToTree(*(*i), &iter); |
| 406 profile_count_++; |
630 } | 407 } |
631 | 408 |
632 if (imported_credit_card_) { | 409 // Blank row between addresses and credit cards. |
633 credit_cards_.push_back(*imported_credit_card_); | 410 gtk_list_store_append(list_store_, &iter); |
634 AddCreditCard(*imported_credit_card_); | 411 gtk_list_store_set( |
635 } else { | 412 list_store_, &iter, |
636 for (std::vector<CreditCard*>::const_iterator iter = | 413 COL_IS_HEADER, TRUE, |
637 personal_data_->credit_cards().begin(); | 414 -1); |
638 iter != personal_data_->credit_cards().end(); ++iter) { | |
639 // The credit card list is terminated by a NULL entry; | |
640 if (!*iter) | |
641 break; | |
642 | 415 |
643 CreditCard* credit_card = *iter; | 416 // Credit card title. |
644 credit_cards_.push_back(*credit_card); | 417 gtk_list_store_append(list_store_, &iter); |
645 AddCreditCard(*credit_card); | 418 gtk_list_store_set( |
646 } | 419 list_store_, &iter, |
| 420 COL_WEIGHT, PANGO_WEIGHT_BOLD, |
| 421 COL_WEIGHT_SET, TRUE, |
| 422 COL_TITLE, |
| 423 l10n_util::GetStringUTF8(IDS_AUTOFILL_CREDITCARDS_GROUP_NAME).c_str(), |
| 424 COL_IS_HEADER, TRUE, |
| 425 -1); |
| 426 // Credit card separator. |
| 427 gtk_list_store_append(list_store_, &iter); |
| 428 gtk_list_store_set( |
| 429 list_store_, &iter, |
| 430 COL_IS_SEPARATOR, TRUE, |
| 431 -1); |
| 432 |
| 433 // The credit cards. |
| 434 for (std::vector<CreditCard*>::const_iterator i = |
| 435 personal_data_->credit_cards().begin(); |
| 436 i != personal_data_->credit_cards().end(); ++i) { |
| 437 AddCreditCardToTree(*(*i), &iter); |
647 } | 438 } |
| 439 |
| 440 UpdateWidgetState(); |
648 } | 441 } |
649 | 442 |
650 void AutoFillDialog::InitializeWidgets() { | 443 void AutoFillDialog::InitializeWidgets() { |
651 dialog_ = gtk_dialog_new_with_buttons( | 444 dialog_ = gtk_dialog_new_with_buttons( |
652 l10n_util::GetStringUTF8(IDS_AUTOFILL_OPTIONS).c_str(), | 445 l10n_util::GetStringUTF8(IDS_AUTOFILL_OPTIONS).c_str(), |
653 // AutoFill dialog is shared between all browser windows. | 446 // AutoFill dialog is shared between all browser windows. |
654 NULL, | 447 NULL, |
655 // Non-modal. | 448 // Non-modal. |
656 GTK_DIALOG_NO_SEPARATOR, | 449 GTK_DIALOG_NO_SEPARATOR, |
657 GTK_STOCK_APPLY, | |
658 GTK_RESPONSE_APPLY, | |
659 GTK_STOCK_CANCEL, | |
660 GTK_RESPONSE_CANCEL, | |
661 GTK_STOCK_OK, | 450 GTK_STOCK_OK, |
662 GTK_RESPONSE_OK, | 451 GTK_RESPONSE_OK, |
663 NULL); | 452 NULL); |
664 | 453 |
665 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox), | 454 GtkBox* vbox = GTK_BOX(GTK_DIALOG(dialog_)->vbox); |
666 gtk_util::kContentAreaSpacing); | 455 gtk_box_set_spacing(vbox, gtk_util::kControlSpacing); |
667 g_signal_connect(dialog_, "response", G_CALLBACK(OnResponse), this); | 456 g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this); |
668 g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroy), this); | 457 g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroyThunk), this); |
| 458 |
| 459 form_autofill_enable_check_ = gtk_check_button_new_with_label( |
| 460 l10n_util::GetStringUTF8(IDS_OPTIONS_AUTOFILL_ENABLE).c_str()); |
| 461 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(form_autofill_enable_check_), |
| 462 enable_form_autofill_.GetValue()); |
| 463 g_signal_connect(G_OBJECT(form_autofill_enable_check_), "toggled", |
| 464 G_CALLBACK(OnAutoFillCheckToggledThunk), this); |
| 465 gtk_box_pack_start(vbox, form_autofill_enable_check_, FALSE, FALSE, 0); |
669 | 466 |
670 // Allow the contents to be scrolled. | 467 // Allow the contents to be scrolled. |
671 GtkWidget* scrolled_window = gtk_scrolled_window_new(NULL, NULL); | 468 GtkWidget* scrolled_window = gtk_scrolled_window_new(NULL, NULL); |
672 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), | 469 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), |
673 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | 470 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); |
674 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog_)->vbox), scrolled_window); | 471 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), |
| 472 GTK_SHADOW_ETCHED_IN); |
675 | 473 |
676 // We create an event box so that we can color the frame background white. | 474 list_store_ = gtk_list_store_new(COL_COUNT, |
677 GtkWidget* frame_event_box = gtk_event_box_new(); | 475 G_TYPE_STRING, |
678 SetWhiteBackground(frame_event_box); | 476 G_TYPE_BOOLEAN, |
679 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), | 477 G_TYPE_BOOLEAN, |
680 frame_event_box); | 478 G_TYPE_INT, |
| 479 G_TYPE_BOOLEAN); |
| 480 tree_ = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store_)); |
| 481 g_object_unref(list_store_); |
| 482 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_), FALSE); |
| 483 gtk_tree_view_set_row_separator_func(GTK_TREE_VIEW(tree_), |
| 484 OnCheckRowIsSeparatorThunk, this, NULL); |
| 485 g_signal_connect(tree_, "row-activated", G_CALLBACK(OnRowActivatedThunk), |
| 486 this); |
| 487 gtk_container_add(GTK_CONTAINER(scrolled_window), tree_); |
681 | 488 |
682 // The frame outline of the content area. | 489 GtkWidget* h_box1 = gtk_hbox_new(FALSE, gtk_util::kControlSpacing); |
683 GtkWidget* frame = gtk_frame_new(NULL); | 490 gtk_box_pack_start(vbox, h_box1, TRUE, TRUE, 0); |
684 gtk_container_add(GTK_CONTAINER(frame_event_box), frame); | 491 gtk_box_pack_start(GTK_BOX(h_box1), scrolled_window, TRUE, TRUE, 0); |
685 | 492 |
686 // The content vbox. | 493 GtkWidget* controls_box = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); |
687 GtkWidget* outer_vbox = gtk_vbox_new(false, 0); | 494 gtk_box_pack_start(GTK_BOX(h_box1), controls_box, FALSE, FALSE, 0); |
688 gtk_box_set_spacing(GTK_BOX(outer_vbox), gtk_util::kContentAreaSpacing); | |
689 gtk_container_add(GTK_CONTAINER(frame), outer_vbox); | |
690 | 495 |
691 addresses_vbox_ = InitGroup(IDS_AUTOFILL_ADDRESSES_GROUP_NAME, | 496 add_address_button_ = gtk_button_new_with_label( |
692 IDS_AUTOFILL_ADD_ADDRESS_BUTTON, | 497 l10n_util::GetStringUTF8(IDS_AUTOFILL_ADD_ADDRESS_BUTTON).c_str()); |
693 G_CALLBACK(OnAddAddressClicked)); | 498 g_signal_connect(add_address_button_, "clicked", |
694 gtk_box_pack_start_defaults(GTK_BOX(outer_vbox), addresses_vbox_); | 499 G_CALLBACK(OnAddAddressThunk), this); |
| 500 gtk_box_pack_start(GTK_BOX(controls_box), add_address_button_, FALSE, FALSE, |
| 501 0); |
695 | 502 |
696 creditcards_vbox_ = InitGroup(IDS_AUTOFILL_CREDITCARDS_GROUP_NAME, | 503 add_credit_card_button_ = gtk_button_new_with_label( |
697 IDS_AUTOFILL_ADD_CREDITCARD_BUTTON, | 504 l10n_util::GetStringUTF8(IDS_AUTOFILL_ADD_CREDITCARD_BUTTON).c_str()); |
698 G_CALLBACK(OnAddCreditCardClicked)); | 505 g_signal_connect(add_credit_card_button_, "clicked", |
699 gtk_box_pack_start_defaults(GTK_BOX(outer_vbox), creditcards_vbox_); | 506 G_CALLBACK(OnAddCreditCardThunk), this); |
| 507 gtk_box_pack_start(GTK_BOX(controls_box), add_credit_card_button_, FALSE, |
| 508 FALSE, 0); |
| 509 |
| 510 edit_button_ = gtk_button_new_with_label( |
| 511 l10n_util::GetStringUTF8(IDS_AUTOFILL_EDIT_BUTTON).c_str()); |
| 512 g_signal_connect(edit_button_, "clicked", G_CALLBACK(OnEditThunk), this); |
| 513 gtk_box_pack_start(GTK_BOX(controls_box), edit_button_, FALSE, FALSE, 0); |
| 514 |
| 515 remove_button_ = gtk_button_new_with_label( |
| 516 l10n_util::GetStringUTF8(IDS_AUTOFILL_DELETE_BUTTON).c_str()); |
| 517 g_signal_connect(remove_button_, "clicked", G_CALLBACK(OnRemoveThunk), this); |
| 518 gtk_box_pack_start(GTK_BOX(controls_box), remove_button_, FALSE, FALSE, 0); |
| 519 |
| 520 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes( |
| 521 "", |
| 522 gtk_cell_renderer_text_new(), |
| 523 "text", COL_TITLE, |
| 524 "weight", COL_WEIGHT, |
| 525 "weight-set", COL_WEIGHT_SET, |
| 526 NULL); |
| 527 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), column); |
| 528 |
| 529 GtkTreeSelection* selection = |
| 530 gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_)); |
| 531 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); |
| 532 gtk_tree_selection_set_select_function(selection, OnSelectionFilterThunk, |
| 533 this, NULL); |
| 534 g_signal_connect(selection, "changed", G_CALLBACK(OnSelectionChangedThunk), |
| 535 this); |
700 | 536 |
701 GtkWidget* link = gtk_chrome_link_button_new( | 537 GtkWidget* link = gtk_chrome_link_button_new( |
702 l10n_util::GetStringUTF8(IDS_AUTOFILL_LEARN_MORE).c_str()); | 538 l10n_util::GetStringUTF8(IDS_AUTOFILL_HELP_LABEL).c_str()); |
703 gtk_dialog_add_action_widget(GTK_DIALOG(dialog_), link, | 539 gtk_dialog_add_action_widget(GTK_DIALOG(dialog_), link, |
704 kAutoFillDialogLearnMoreLink); | 540 kAutoFillDialogAboutLink); |
705 | 541 |
706 // Setting the link widget to secondary positions the button on the left side | 542 // Setting the link widget to secondary positions the button on the left side |
707 // of the action area (vice versa for RTL layout). | 543 // of the action area (vice versa for RTL layout). |
708 gtk_button_box_set_child_secondary( | 544 gtk_button_box_set_child_secondary( |
709 GTK_BUTTON_BOX(GTK_DIALOG(dialog_)->action_area), link, TRUE); | 545 GTK_BUTTON_BOX(GTK_DIALOG(dialog_)->action_area), link, TRUE); |
710 } | 546 } |
711 | 547 |
712 GtkWidget* AutoFillDialog::InitGroup(int name_id, | 548 void AutoFillDialog::UpdateWidgetState() { |
713 int button_id, | 549 if (!personal_data_->IsDataLoaded() || !enable_form_autofill_.GetValue()) { |
714 GCallback clicked_callback) { | 550 gtk_widget_set_sensitive(add_address_button_, FALSE); |
715 GtkWidget* vbox = gtk_vbox_new(false, gtk_util::kControlSpacing); | 551 gtk_widget_set_sensitive(add_credit_card_button_, FALSE); |
716 | 552 gtk_widget_set_sensitive(edit_button_, FALSE); |
717 // Group label. | 553 gtk_widget_set_sensitive(remove_button_, FALSE); |
718 GtkWidget* label = gtk_util::CreateBoldLabel( | 554 gtk_widget_set_sensitive(tree_, FALSE); |
719 l10n_util::GetStringUTF8(name_id)); | 555 } else { |
720 gtk_box_pack_start(GTK_BOX(vbox), | 556 gtk_widget_set_sensitive(add_address_button_, TRUE); |
721 IndentWidget(label, kAutoFillDialogIndent), | 557 gtk_widget_set_sensitive(add_credit_card_button_, TRUE); |
722 FALSE, FALSE, 0); | 558 int selection_type = GetSelectionType(); |
723 | 559 gtk_widget_set_sensitive(edit_button_, selection_type == SELECTION_SINGLE); |
724 // Separator. | 560 // Enable the remove button if at least one non-header row is selected. |
725 GtkWidget* separator = gtk_hseparator_new(); | 561 gtk_widget_set_sensitive(remove_button_, |
726 gtk_box_pack_start(GTK_BOX(vbox), separator, FALSE, FALSE, 0); | 562 (selection_type & SELECTION_SINGLE) != 0); |
727 | 563 gtk_widget_set_sensitive(tree_, TRUE); |
728 // Add profile button. | 564 } |
729 GtkWidget* button = gtk_button_new_with_label( | |
730 l10n_util::GetStringUTF8(button_id).c_str()); | |
731 g_signal_connect(button, "clicked", clicked_callback, this); | |
732 gtk_box_pack_end_defaults(GTK_BOX(vbox), | |
733 IndentWidget(button, kAutoFillDialogIndent)); | |
734 | |
735 return vbox; | |
736 } | 565 } |
737 | 566 |
738 GtkWidget* AutoFillDialog::InitGroupContentArea(int name_id, | 567 static void RowIteratorFunction(GtkTreeModel* model, |
739 GtkWidget** content_vbox) { | 568 GtkTreePath* path, |
740 GtkWidget* expander = gtk_expander_new( | 569 GtkTreeIter* iter, |
741 l10n_util::GetStringUTF8(name_id).c_str()); | 570 gpointer data) { |
| 571 int* type = reinterpret_cast<int*>(data); |
| 572 bool is_header = false; |
| 573 GValue value = { 0 }; |
| 574 gtk_tree_model_get_value(model, iter, AutoFillDialog::COL_IS_HEADER, &value); |
| 575 is_header = g_value_get_boolean(&value); |
| 576 g_value_unset(&value); |
742 | 577 |
743 GtkWidget* frame = gtk_frame_new(NULL); | 578 if (!is_header) { |
744 gtk_container_add(GTK_CONTAINER(expander), frame); | 579 // Is it a separator? |
| 580 GValue value = { 0 }; |
| 581 gtk_tree_model_get_value(model, iter, AutoFillDialog::COL_IS_SEPARATOR, |
| 582 &value); |
| 583 is_header = g_value_get_boolean(&value); |
| 584 g_value_unset(&value); |
| 585 } |
745 | 586 |
746 GtkWidget* vbox = gtk_vbox_new(false, 0); | 587 if (is_header) { |
747 gtk_box_set_spacing(GTK_BOX(vbox), gtk_util::kControlSpacing); | 588 *type |= AutoFillDialog::SELECTION_HEADER; |
748 GtkWidget* vbox_alignment = gtk_alignment_new(0, 0, 0, 0); | 589 } else { |
749 gtk_alignment_set_padding(GTK_ALIGNMENT(vbox_alignment), | 590 if ((*type & AutoFillDialog::SELECTION_SINGLE) == 0) |
750 gtk_util::kControlSpacing, | 591 *type |= AutoFillDialog::SELECTION_SINGLE; |
751 gtk_util::kControlSpacing, | 592 else |
752 gtk_util::kGroupIndent, | 593 *type |= AutoFillDialog::SELECTION_MULTI; |
753 0); | 594 } |
754 gtk_container_add(GTK_CONTAINER(vbox_alignment), vbox); | |
755 gtk_container_add(GTK_CONTAINER(frame), vbox_alignment); | |
756 | |
757 *content_vbox = vbox; | |
758 return expander; | |
759 } | 595 } |
760 | 596 |
761 GtkWidget* AutoFillDialog::AddNewAddress(bool expand) { | 597 int AutoFillDialog::GetSelectionType() { |
762 AddressWidgets widgets = {0}; | 598 int state = SELECTION_EMPTY; |
763 GtkWidget* vbox; | 599 gtk_tree_selection_selected_foreach( |
764 GtkWidget* address = InitGroupContentArea(IDS_AUTOFILL_NEW_ADDRESS, &vbox); | 600 gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_)), RowIteratorFunction, |
765 | 601 &state); |
766 gtk_expander_set_expanded(GTK_EXPANDER(address), expand); | 602 return state; |
767 | |
768 GtkWidget* table = InitFormTable(5, 3); | |
769 gtk_box_pack_start_defaults(GTK_BOX(vbox), table); | |
770 | |
771 widgets.label = FormTableAddLabelEntry(table, 0, 0, 1, | |
772 IDS_AUTOFILL_DIALOG_LABEL, | |
773 address, G_CALLBACK(OnLabelChanged)); | |
774 widgets.full_name = FormTableAddEntry(table, 1, 0, 1, | |
775 IDS_AUTOFILL_DIALOG_FULL_NAME); | |
776 widgets.email = FormTableAddEntry(table, 2, 0, 1, | |
777 IDS_AUTOFILL_DIALOG_EMAIL); | |
778 widgets.company_name = FormTableAddEntry(table, 2, 1, 1, | |
779 IDS_AUTOFILL_DIALOG_COMPANY_NAME); | |
780 widgets.address_line1 = FormTableAddEntry(table, 3, 0, 2, | |
781 IDS_AUTOFILL_DIALOG_ADDRESS_LINE_1); | |
782 widgets.address_line2 = FormTableAddEntry(table, 4, 0, 2, | |
783 IDS_AUTOFILL_DIALOG_ADDRESS_LINE_2); | |
784 | |
785 GtkWidget* address_table = InitFormTable(1, 4); | |
786 gtk_box_pack_start_defaults(GTK_BOX(vbox), address_table); | |
787 | |
788 widgets.city = FormTableAddEntry(address_table, 0, 0, 1, | |
789 IDS_AUTOFILL_DIALOG_CITY); | |
790 widgets.state = FormTableAddEntry(address_table, 0, 1, 1, | |
791 IDS_AUTOFILL_DIALOG_STATE); | |
792 widgets.zipcode = FormTableAddSizedEntry(address_table, 0, 2, 7, | |
793 IDS_AUTOFILL_DIALOG_ZIP_CODE); | |
794 widgets.country = FormTableAddSizedEntry(address_table, 0, 3, 10, | |
795 IDS_AUTOFILL_DIALOG_COUNTRY); | |
796 | |
797 GtkWidget* phone_table = InitFormTable(1, 2); | |
798 gtk_box_pack_start_defaults(GTK_BOX(vbox), phone_table); | |
799 | |
800 widgets.phone = | |
801 FormTableAddEntry(phone_table, 0, 0, 1, IDS_AUTOFILL_DIALOG_PHONE); | |
802 widgets.fax = | |
803 FormTableAddEntry(phone_table, 0, 1, 1, IDS_AUTOFILL_DIALOG_FAX); | |
804 | |
805 GtkWidget* button = gtk_button_new_with_label( | |
806 l10n_util::GetStringUTF8(IDS_AUTOFILL_DELETE_BUTTON).c_str()); | |
807 g_signal_connect(button, "clicked", G_CALLBACK(OnDeleteAddressClicked), this); | |
808 SetButtonData(button, widgets.label); | |
809 GtkWidget* alignment = gtk_alignment_new(0, 0, 0, 0); | |
810 gtk_container_add(GTK_CONTAINER(alignment), button); | |
811 gtk_box_pack_start_defaults(GTK_BOX(vbox), alignment); | |
812 | |
813 address_widgets_.push_back(widgets); | |
814 return address; | |
815 } | 603 } |
816 | 604 |
817 GtkWidget* AutoFillDialog::AddNewCreditCard(bool expand) { | 605 void AutoFillDialog::AddAddressToTree(const AutoFillProfile& profile, |
818 CreditCardWidgets widgets = {0}; | 606 GtkTreeIter* iter) { |
819 GtkWidget* vbox; | 607 gtk_list_store_append(list_store_, iter); |
820 GtkWidget* credit_card = InitGroupContentArea(IDS_AUTOFILL_NEW_CREDITCARD, | 608 gtk_list_store_set( |
821 &vbox); | 609 list_store_, iter, |
822 | 610 COL_WEIGHT, PANGO_WEIGHT_NORMAL, |
823 gtk_expander_set_expanded(GTK_EXPANDER(credit_card), expand); | 611 COL_WEIGHT_SET, TRUE, |
824 | 612 COL_TITLE, UTF16ToUTF8(profile.PreviewSummary()).c_str(), |
825 GtkWidget* label_table = InitFormTable(1, 2); | 613 -1); |
826 gtk_box_pack_start_defaults(GTK_BOX(vbox), label_table); | |
827 | |
828 widgets.label = FormTableAddLabelEntry(label_table, 0, 0, 1, | |
829 IDS_AUTOFILL_DIALOG_LABEL, credit_card, | |
830 G_CALLBACK(OnLabelChanged)); | |
831 | |
832 GtkWidget* name_cc_table = InitFormTable(2, 6); | |
833 gtk_box_pack_start_defaults(GTK_BOX(vbox), name_cc_table); | |
834 | |
835 widgets.name_on_card = FormTableAddExpandedEntry( | |
836 name_cc_table, 0, 0, 3, IDS_AUTOFILL_DIALOG_NAME_ON_CARD); | |
837 widgets.card_number = FormTableAddExpandedEntry( | |
838 name_cc_table, 1, 0, 3, IDS_AUTOFILL_DIALOG_CREDIT_CARD_NUMBER); | |
839 widgets.expiration_month = FormTableAddSizedEntry(name_cc_table, 1, 3, 2, 0); | |
840 widgets.expiration_year = FormTableAddSizedEntry(name_cc_table, 1, 4, 4, 0); | |
841 | |
842 FormTableSetLabel(name_cc_table, 1, 3, 2, | |
843 IDS_AUTOFILL_DIALOG_EXPIRATION_DATE); | |
844 | |
845 gtk_table_set_col_spacing(GTK_TABLE(name_cc_table), 3, 2); | |
846 | |
847 GtkWidget* addresses_table = InitFormTable(2, 5); | |
848 gtk_box_pack_start_defaults(GTK_BOX(vbox), addresses_table); | |
849 | |
850 FormTableSetLabel(addresses_table, 0, 0, 3, | |
851 IDS_AUTOFILL_DIALOG_BILLING_ADDRESS); | |
852 | |
853 GtkWidget* billing = gtk_combo_box_new_text(); | |
854 widgets.billing_address = billing; | |
855 std::string combo_text = l10n_util::GetStringUTF8( | |
856 IDS_AUTOFILL_DIALOG_CHOOSE_EXISTING_ADDRESS); | |
857 gtk_combo_box_append_text(GTK_COMBO_BOX(billing), combo_text.c_str()); | |
858 gtk_combo_box_set_active(GTK_COMBO_BOX(billing), 0); | |
859 FormTableSetWidget(addresses_table, billing, 0, 0, 2, false); | |
860 | |
861 for (std::vector<AddressWidgets>::const_iterator iter = | |
862 address_widgets_.begin(); | |
863 iter != address_widgets_.end(); ++iter) { | |
864 // TODO(jhawkins): Validate the label and DCHECK on !empty(). | |
865 std::string text = gtk_entry_get_text(GTK_ENTRY(iter->label)); | |
866 if (!text.empty()) | |
867 gtk_combo_box_append_text(GTK_COMBO_BOX(widgets.billing_address), | |
868 text.c_str()); | |
869 } | |
870 | |
871 GtkWidget* phone_table = InitFormTable(1, 1); | |
872 gtk_box_pack_start_defaults(GTK_BOX(vbox), phone_table); | |
873 | |
874 widgets.phone = | |
875 FormTableAddEntry(phone_table, 0, 0, 1, IDS_AUTOFILL_DIALOG_PHONE); | |
876 | |
877 GtkWidget* button = gtk_button_new_with_label( | |
878 l10n_util::GetStringUTF8(IDS_AUTOFILL_DELETE_BUTTON).c_str()); | |
879 g_signal_connect(button, "clicked", | |
880 G_CALLBACK(OnDeleteCreditCardClicked), this); | |
881 SetButtonData(button, widgets.label); | |
882 GtkWidget* alignment = gtk_alignment_new(0, 0, 0, 0); | |
883 gtk_container_add(GTK_CONTAINER(alignment), button); | |
884 gtk_box_pack_start_defaults(GTK_BOX(vbox), alignment); | |
885 | |
886 credit_card_widgets_.push_back(widgets); | |
887 return credit_card; | |
888 } | 614 } |
889 | 615 |
890 void AutoFillDialog::AddAddress(const AutoFillProfile& profile) { | 616 void AutoFillDialog::AddCreditCardToTree(const CreditCard& credit_card, |
891 GtkWidget* address = AddNewAddress(false); | 617 GtkTreeIter* iter) { |
892 gtk_expander_set_label(GTK_EXPANDER(address), | 618 gtk_list_store_append(list_store_, iter); |
893 UTF16ToUTF8(profile.Label()).c_str()); | 619 gtk_list_store_set( |
894 | 620 list_store_, iter, |
895 // We just pushed the widgets to the back of the vector. | 621 COL_WEIGHT, PANGO_WEIGHT_NORMAL, |
896 const AddressWidgets& widgets = address_widgets_.back(); | 622 COL_WEIGHT_SET, TRUE, |
897 SetEntryText(widgets.label, profile.Label()); | 623 COL_TITLE, UTF16ToUTF8(credit_card.PreviewSummary()).c_str(), |
898 SetEntryText(widgets.full_name, | 624 -1); |
899 profile.GetFieldText(AutoFillType(NAME_FULL))); | |
900 SetEntryText(widgets.email, | |
901 profile.GetFieldText(AutoFillType(EMAIL_ADDRESS))); | |
902 SetEntryText(widgets.company_name, | |
903 profile.GetFieldText(AutoFillType(COMPANY_NAME))); | |
904 SetEntryText(widgets.address_line1, | |
905 profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE1))); | |
906 SetEntryText(widgets.address_line2, | |
907 profile.GetFieldText(AutoFillType(ADDRESS_HOME_LINE2))); | |
908 SetEntryText(widgets.city, | |
909 profile.GetFieldText(AutoFillType(ADDRESS_HOME_CITY))); | |
910 SetEntryText(widgets.state, | |
911 profile.GetFieldText(AutoFillType(ADDRESS_HOME_STATE))); | |
912 SetEntryText(widgets.zipcode, | |
913 profile.GetFieldText(AutoFillType(ADDRESS_HOME_ZIP))); | |
914 SetEntryText(widgets.country, | |
915 profile.GetFieldText(AutoFillType(ADDRESS_HOME_COUNTRY))); | |
916 SetEntryText(widgets.phone, | |
917 profile.GetFieldText(AutoFillType(PHONE_HOME_WHOLE_NUMBER))); | |
918 SetEntryText(widgets.fax, | |
919 profile.GetFieldText(AutoFillType(PHONE_FAX_WHOLE_NUMBER))); | |
920 | |
921 gtk_box_pack_start(GTK_BOX(addresses_vbox_), address, FALSE, FALSE, 0); | |
922 gtk_widget_show_all(address); | |
923 } | 625 } |
924 | 626 |
925 void AutoFillDialog::AddCreditCard(const CreditCard& credit_card) { | 627 void AutoFillDialog::GetSelectedEntries( |
926 GtkWidget* credit_card_widget = AddNewCreditCard(false); | 628 std::vector<AutoFillProfile*>* profiles, |
927 gtk_expander_set_label(GTK_EXPANDER(credit_card_widget), | 629 std::vector<CreditCard*>* cards) { |
928 UTF16ToUTF8(credit_card.Label()).c_str()); | 630 std::set<int> selection; |
| 631 gtk_tree::GetSelectedIndices( |
| 632 gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_)), &selection); |
929 | 633 |
930 // We just pushed the widgets to the back of the vector. | 634 for (std::set<int>::const_iterator i = selection.begin(); |
931 const CreditCardWidgets& widgets = credit_card_widgets_.back(); | 635 i != selection.end(); ++i) { |
932 SetEntryText(widgets.label, credit_card.Label()); | 636 // 2 is the number of header rows. |
933 SetEntryText(widgets.name_on_card, | 637 int index = *i - 2; |
934 credit_card.GetFieldText(AutoFillType(CREDIT_CARD_NAME))); | 638 if (index >= 0 && |
935 // Set obfuscated number if not empty. | 639 index < static_cast<int>(personal_data_->profiles().size())) { |
936 credit_card_widgets_.back().original_card_number = | 640 profiles->push_back(personal_data_->profiles()[index]); |
937 credit_card.GetFieldText(AutoFillType(CREDIT_CARD_NUMBER)); | 641 continue; |
938 string16 credit_card_number; | 642 } |
939 if (!widgets.original_card_number.empty()) | |
940 credit_card_number = credit_card.ObfuscatedNumber(); | |
941 SetEntryText(widgets.card_number, credit_card_number); | |
942 SetEntryText(widgets.expiration_month, | |
943 credit_card.GetFieldText(AutoFillType(CREDIT_CARD_EXP_MONTH))); | |
944 SetEntryText( | |
945 widgets.expiration_year, | |
946 credit_card.GetFieldText(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR))); | |
947 | 643 |
948 // Two cases to consider: | 644 // Empty row, header and separator are next. |
949 // address not found - This means the address is not set and | 645 index -= profile_count_ + 3; |
950 // FindIndexOfAddress returns -1. -1 + 1 = 0, meaning the first item will | 646 if (index >= 0 && index < |
951 // be selected, "Choose existing address". | 647 static_cast<int>(personal_data_->credit_cards().size())) { |
952 // | 648 cards->push_back(personal_data_->credit_cards()[index]); |
953 // address is found - The index returned needs to be offset by one in order | 649 } |
954 // to compensate for the first entry, "Choose existing address". | 650 } |
955 int index = FindIndexOfAddress(credit_card.billing_address()) + 1; | |
956 gtk_combo_box_set_active(GTK_COMBO_BOX(widgets.billing_address), index); | |
957 | |
958 gtk_box_pack_start(GTK_BOX(creditcards_vbox_), credit_card_widget, | |
959 FALSE, FALSE, 0); | |
960 gtk_widget_show_all(credit_card_widget); | |
961 } | 651 } |
962 | 652 |
963 int AutoFillDialog::FindIndexOfAddress(string16 billing_address) { | 653 } // namespace |
964 int index = 0; | |
965 for (std::vector<AddressWidgets>::const_iterator iter = | |
966 address_widgets_.begin(); | |
967 iter != address_widgets_.end(); ++iter, ++index) { | |
968 std::string text = gtk_entry_get_text(GTK_ENTRY(iter->label)); | |
969 if (UTF8ToUTF16(text) == billing_address) | |
970 return index; | |
971 } | |
972 | |
973 return -1; | |
974 } | |
975 | 654 |
976 /////////////////////////////////////////////////////////////////////////////// | 655 /////////////////////////////////////////////////////////////////////////////// |
977 // Factory/finder method: | 656 // Factory/finder method: |
978 | 657 |
979 void ShowAutoFillDialog(gfx::NativeView parent, | 658 void ShowAutoFillDialog(gfx::NativeView parent, |
980 AutoFillDialogObserver* observer, | 659 AutoFillDialogObserver* observer, |
981 Profile* profile) { | 660 Profile* profile) { |
982 DCHECK(profile); | 661 DCHECK(profile); |
983 | 662 |
984 if (!dialog) { | 663 if (!dialog) |
985 dialog = new AutoFillDialog(observer, | 664 dialog = new AutoFillDialog(profile, observer); |
986 profile->GetPersonalDataManager(), | |
987 NULL, | |
988 NULL); | |
989 } | |
990 dialog->Show(); | 665 dialog->Show(); |
991 } | 666 } |
OLD | NEW |