Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(173)

Side by Side Diff: chrome/browser/autofill/auto_fill_editor_gtk.cc

Issue 2975003: Makes the auto fill dialogs match the mocks. (Closed)
Patch Set: Moves function declarations out of autofill_dialog.h Created 10 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | chrome/browser/autofill/autofill_dialog.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/autofill/autofill_dialog.h"
6
7 #include <gtk/gtk.h>
8
9 #include "app/gtk_signal.h"
10 #include "app/l10n_util.h"
11 #include "app/resource_bundle.h"
12 #include "base/message_loop.h"
13 #include "base/string_util.h"
14 #include "base/task.h"
15 #include "base/time.h"
16 #include "base/utf_string_conversions.h"
17 #include "chrome/browser/autofill/personal_data_manager.h"
18 #include "chrome/browser/autofill/phone_number.h"
19 #include "chrome/browser/gtk/gtk_util.h"
20 #include "chrome/browser/profile.h"
21 #include "grit/app_resources.h"
22 #include "grit/generated_resources.h"
23 #include "grit/locale_settings.h"
24 #include "grit/theme_resources.h"
25
26 namespace {
27
28 // Creates a label whose text is set from the resource id |label_id|.
29 GtkWidget* CreateLabel(int label_id) {
30 GtkWidget* label = gtk_label_new(l10n_util::GetStringUTF8(label_id).c_str());
31 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
32 return label;
33 }
34
35 // Sets the text of |entry| to the value of the field |type| from |profile|.
36 void SetEntryText(GtkWidget* entry, FormGroup* profile, _FieldType type) {
37 gtk_entry_set_text(
38 GTK_ENTRY(entry),
39 UTF16ToUTF8(profile->GetFieldText(AutoFillType(type))).c_str());
40 }
41
42 // Returns the current value of |entry|.
43 string16 GetEntryText(GtkWidget* entry) {
44 return UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(entry)));
45 }
46
47 // Sets |form|'s field of type |type| to the text in |entry|.
48 void SetFormValue(GtkWidget* entry, FormGroup* form, _FieldType type) {
49 form->SetInfo(AutoFillType(type), GetEntryText(entry));
50 }
51
52 // Sets the number of characters to display in |combobox| to |width|.
53 void SetComboBoxCellRendererCharWidth(GtkWidget* combobox, int width) {
54 GList* cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(combobox));
55 DCHECK(g_list_length(cells) > 0);
56 GtkCellRendererText* renderer =
57 GTK_CELL_RENDERER_TEXT(g_list_first(cells)->data);
58 g_object_set(G_OBJECT(renderer), "width-chars", width, NULL);
59 g_list_free(cells);
60 }
61
62 // TableBuilder ----------------------------------------------------------------
63
64 // A convenience used in populating a GtkTable. To use it create a TableBuilder
65 // and repeatedly invoke AddWidget. TableBuilder keeps track of the current
66 // row/col. You can increment the row explicitly by invoking |increment_row|.
67 class TableBuilder {
68 public:
69 TableBuilder(int row_count, int col_count);
70 ~TableBuilder();
71
72 GtkWidget* table() { return table_; }
73
74 void increment_row() {
75 row_++;
76 col_ = 0;
77 }
78
79 GtkWidget* AddWidget(GtkWidget* widget, int col_span);
80
81 void set_x_padding(int x) { x_padding_ = x; }
82 void set_y_padding(int y) { y_padding_ = y; }
83
84 void reset_padding() {
85 x_padding_ = y_padding_ = gtk_util::kControlSpacing / 2;
86 }
87
88 private:
89 GtkWidget* table_;
90
91 // Number of rows/columns.
92 const int row_count_;
93 const int col_count_;
94
95 // Current row/column.
96 int row_;
97 int col_;
98
99 // Padding.
100 int x_padding_;
101 int y_padding_;
102
103 DISALLOW_COPY_AND_ASSIGN(TableBuilder);
104 };
105
106 TableBuilder::TableBuilder(int row_count, int col_count)
107 : table_(gtk_table_new(row_count, col_count, FALSE)),
108 row_count_(row_count),
109 col_count_(col_count),
110 row_(0),
111 col_(0),
112 x_padding_(gtk_util::kControlSpacing / 2),
113 y_padding_(gtk_util::kControlSpacing / 2) {
114 }
115
116 TableBuilder::~TableBuilder() {
117 DCHECK_EQ(row_count_, row_);
118 }
119
120 GtkWidget* TableBuilder::AddWidget(GtkWidget* widget, int col_span) {
121 gtk_table_attach(
122 GTK_TABLE(table_),
123 widget,
124 col_, col_ + col_span,
125 row_, row_ + 1,
126 // The next line makes the widget expand to take up any extra horizontal
127 // space.
128 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND),
129 GTK_FILL,
130 x_padding_, y_padding_);
131 col_ += col_span;
132 if (col_ == col_count_) {
133 row_++;
134 col_ = 0;
135 }
136 return widget;
137 }
138
139 // AutoFillProfileEditor -------------------------------------------------------
140
141 // Class responsible for editing or creating an AutoFillProfile.
142 class AutoFillProfileEditor {
143 public:
144 AutoFillProfileEditor(AutoFillDialogObserver* observer,
145 Profile* profile,
146 AutoFillProfile* auto_fill_profile);
147
148 private:
149 friend class DeleteTask<AutoFillProfileEditor>;
150
151 ~AutoFillProfileEditor() {}
152
153 void Init();
154
155 // Sets the values of the various widgets to |profile|.
156 void SetWidgetValues(AutoFillProfile* profile);
157
158 // Notifies the observer of the new changes. This either updates the current
159 // AutoFillProfile or creates a new one.
160 void ApplyEdits();
161
162 // Sets the various form fields in |profile| to match the values in the
163 // widgets.
164 void SetProfileValuesFromWidgets(AutoFillProfile* profile);
165
166 // Updates the image displayed by |image| depending upon whether the text in
167 // |entry| is a valid phone number.
168 void UpdatePhoneImage(GtkWidget* entry, GtkWidget* image);
169
170 // Sets the size request for the widget to match the size of the good/bad
171 // images. We must do this as the image of the phone widgets is set to null
172 // when not empty.
173 void SetPhoneSizeRequest(GtkWidget* widget);
174
175 CHROMEGTK_CALLBACK_0(AutoFillProfileEditor, void, OnDestroy);
176 CHROMEG_CALLBACK_1(AutoFillProfileEditor, void, OnResponse, GtkDialog*, gint);
177 CHROMEG_CALLBACK_0(AutoFillProfileEditor, void, OnPhoneChanged, GtkEditable*);
178 CHROMEG_CALLBACK_0(AutoFillProfileEditor, void, OnFaxChanged, GtkEditable*);
179
180 // Are we creating a new profile?
181 const bool is_new_;
182
183 // If is_new_ is false this is the unique id of the profile the user is
184 // editing.
185 const int profile_id_;
186
187 AutoFillDialogObserver* observer_;
188
189 Profile* profile_;
190
191 GtkWidget* dialog_;
192 GtkWidget* full_name_;
193 GtkWidget* company_;
194 GtkWidget* address_1_;
195 GtkWidget* address_2_;
196 GtkWidget* city_;
197 GtkWidget* state_;
198 GtkWidget* zip_;
199 GtkWidget* country_;
200 GtkWidget* phone_;
201 GtkWidget* phone_image_;
202 GtkWidget* fax_;
203 GtkWidget* fax_image_;
204 GtkWidget* email_;
205
206 DISALLOW_COPY_AND_ASSIGN(AutoFillProfileEditor);
207 };
208
209 AutoFillProfileEditor::AutoFillProfileEditor(
210 AutoFillDialogObserver* observer,
211 Profile* profile,
212 AutoFillProfile* auto_fill_profile)
213 : is_new_(!auto_fill_profile ? true : false),
214 profile_id_(auto_fill_profile ? auto_fill_profile->unique_id() : 0),
215 observer_(observer),
216 profile_(profile) {
217 Init();
218
219 if (auto_fill_profile)
220 SetWidgetValues(auto_fill_profile);
221
222 gtk_util::ShowDialogWithLocalizedSize(
223 dialog_,
224 IDS_AUTOFILL_DIALOG_EDIT_ADDRESS_WIDTH_CHARS,
225 IDS_AUTOFILL_DIALOG_EDIT_ADDRESS_HEIGHT_LINES,
226 true);
227 gtk_util::PresentWindow(dialog_, gtk_get_current_event_time());
228 }
229
230 void AutoFillProfileEditor::Init() {
231 TableBuilder main_table_builder(15, 2);
232
233 main_table_builder.AddWidget(CreateLabel(IDS_AUTOFILL_DIALOG_FULL_NAME), 2);
234 full_name_ = main_table_builder.AddWidget(gtk_entry_new(), 1);
235 main_table_builder.increment_row();
236
237 main_table_builder.AddWidget(CreateLabel(IDS_AUTOFILL_DIALOG_COMPANY_NAME),
238 2);
239 company_ = main_table_builder.AddWidget(gtk_entry_new(), 1);
240 main_table_builder.increment_row();
241
242 main_table_builder.AddWidget(CreateLabel(IDS_AUTOFILL_DIALOG_ADDRESS_LINE_1),
243 2);
244 address_1_ = main_table_builder.AddWidget(gtk_entry_new(), 1);
245 main_table_builder.increment_row();
246
247 main_table_builder.AddWidget(CreateLabel(IDS_AUTOFILL_DIALOG_ADDRESS_LINE_2),
248 2);
249 address_2_ = main_table_builder.AddWidget(gtk_entry_new(), 1);
250 main_table_builder.increment_row();
251
252 TableBuilder city_state_builder(2, 3);
253 city_state_builder.AddWidget(CreateLabel(IDS_AUTOFILL_DIALOG_CITY), 1);
254 city_state_builder.AddWidget(CreateLabel(IDS_AUTOFILL_DIALOG_STATE), 1);
255 city_state_builder.AddWidget(CreateLabel(IDS_AUTOFILL_DIALOG_ZIP_CODE), 1);
256
257 city_ = city_state_builder.AddWidget(gtk_entry_new(), 1);
258 state_ = city_state_builder.AddWidget(gtk_entry_new(), 1);
259 zip_ = city_state_builder.AddWidget(gtk_entry_new(), 1);
260
261 main_table_builder.set_x_padding(0);
262 main_table_builder.set_y_padding(0);
263 main_table_builder.AddWidget(city_state_builder.table(), 2);
264 main_table_builder.reset_padding();
265
266 main_table_builder.AddWidget(CreateLabel(IDS_AUTOFILL_DIALOG_COUNTRY), 2);
267 country_ = main_table_builder.AddWidget(gtk_entry_new(), 1);
268 main_table_builder.increment_row();
269
270 main_table_builder.AddWidget(CreateLabel(IDS_AUTOFILL_DIALOG_PHONE), 1);
271 main_table_builder.AddWidget(CreateLabel(IDS_AUTOFILL_DIALOG_FAX), 1);
272
273 GtkWidget* phone_box =
274 main_table_builder.AddWidget(gtk_hbox_new(FALSE, 0), 1);
275 gtk_box_set_spacing(GTK_BOX(phone_box), gtk_util::kControlSpacing);
276 phone_ = gtk_entry_new();
277 g_signal_connect(phone_, "changed", G_CALLBACK(OnPhoneChangedThunk), this);
278 gtk_box_pack_start(GTK_BOX(phone_box), phone_, TRUE, TRUE, 0);
279 phone_image_ = gtk_image_new_from_pixbuf(NULL);
280 SetPhoneSizeRequest(phone_image_);
281 gtk_box_pack_start(GTK_BOX(phone_box), phone_image_, FALSE, FALSE, 0);
282
283 GtkWidget* fax_box =
284 main_table_builder.AddWidget(gtk_hbox_new(FALSE, 0), 1);
285 gtk_box_set_spacing(GTK_BOX(fax_box), gtk_util::kControlSpacing);
286 fax_ = gtk_entry_new();
287 g_signal_connect(fax_, "changed", G_CALLBACK(OnFaxChangedThunk), this);
288 gtk_box_pack_start(GTK_BOX(fax_box), fax_, TRUE, TRUE, 0);
289 fax_image_ = gtk_image_new_from_pixbuf(NULL);
290 SetPhoneSizeRequest(fax_image_);
291 gtk_box_pack_start(GTK_BOX(fax_box), fax_image_, FALSE, FALSE, 0);
292
293 main_table_builder.AddWidget(CreateLabel(IDS_AUTOFILL_DIALOG_EMAIL), 2);
294 email_ = main_table_builder.AddWidget(gtk_entry_new(), 1);
295 main_table_builder.increment_row();
296
297 int caption_id = is_new_ ? IDS_AUTOFILL_ADD_ADDRESS_CAPTION :
298 IDS_AUTOFILL_EDIT_ADDRESS_CAPTION;
299 dialog_ = gtk_dialog_new_with_buttons(
300 l10n_util::GetStringUTF8(caption_id).c_str(),
301 NULL,
302 static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
303 GTK_STOCK_APPLY,
304 GTK_RESPONSE_APPLY,
305 GTK_STOCK_CANCEL,
306 GTK_RESPONSE_CANCEL,
307 NULL);
308
309 g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this);
310 g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroyThunk), this);
311
312 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox),
313 main_table_builder.table(), TRUE, TRUE, 0);
314 }
315
316 void AutoFillProfileEditor::SetWidgetValues(AutoFillProfile* profile) {
317 SetEntryText(full_name_, profile, NAME_FULL);
318 SetEntryText(company_, profile, COMPANY_NAME);
319 SetEntryText(address_1_, profile, ADDRESS_HOME_LINE1);
320 SetEntryText(address_2_, profile, ADDRESS_HOME_LINE2);
321 SetEntryText(city_, profile, ADDRESS_HOME_CITY);
322 SetEntryText(state_, profile, ADDRESS_HOME_STATE);
323 SetEntryText(zip_, profile, ADDRESS_HOME_ZIP);
324 SetEntryText(country_, profile, ADDRESS_HOME_COUNTRY);
325 SetEntryText(phone_, profile, PHONE_HOME_WHOLE_NUMBER);
326 SetEntryText(fax_, profile, PHONE_FAX_WHOLE_NUMBER);
327 SetEntryText(email_, profile, EMAIL_ADDRESS);
328
329 UpdatePhoneImage(phone_, phone_image_);
330 UpdatePhoneImage(fax_, fax_image_);
331 }
332
333 void AutoFillProfileEditor::ApplyEdits() {
334 // Build the current set of profiles.
335 std::vector<AutoFillProfile> profiles;
336 PersonalDataManager* data_manager = profile_->GetPersonalDataManager();
337 for (std::vector<AutoFillProfile*>::const_iterator i =
338 data_manager->profiles().begin();
339 i != data_manager->profiles().end(); ++i) {
340 profiles.push_back(**i);
341 }
342 AutoFillProfile* profile = NULL;
343
344 if (!is_new_) {
345 // The user is editing an existing profile, find it.
346 for (std::vector<AutoFillProfile>::iterator i = profiles.begin();
347 i != profiles.end(); ++i) {
348 if (i->unique_id() == profile_id_) {
349 profile = &(*i);
350 break;
351 }
352 }
353 DCHECK(profile); // We should have found a profile, if not we'll end up
354 // creating one below.
355 }
356
357 if (!profile) {
358 profiles.push_back(AutoFillProfile());
359 profile = &profiles.back();
360 }
361
362 // Update the values in the profile.
363 SetProfileValuesFromWidgets(profile);
364
365 // And apply the edits.
366 observer_->OnAutoFillDialogApply(&profiles, NULL);
367 }
368
369 void AutoFillProfileEditor::SetProfileValuesFromWidgets(
370 AutoFillProfile* profile) {
371 SetFormValue(full_name_, profile, NAME_FULL);
372 SetFormValue(company_, profile, COMPANY_NAME);
373 SetFormValue(address_1_, profile, ADDRESS_HOME_LINE1);
374 SetFormValue(address_2_, profile, ADDRESS_HOME_LINE2);
375 SetFormValue(city_, profile, ADDRESS_HOME_CITY);
376 SetFormValue(state_, profile, ADDRESS_HOME_STATE);
377 SetFormValue(zip_, profile, ADDRESS_HOME_ZIP);
378 SetFormValue(country_, profile, ADDRESS_HOME_COUNTRY);
379 SetFormValue(email_, profile, EMAIL_ADDRESS);
380
381 string16 number, city_code, country_code;
382 PhoneNumber::ParsePhoneNumber(
383 GetEntryText(phone_), &number, &city_code, &country_code);
384 profile->SetInfo(AutoFillType(PHONE_HOME_COUNTRY_CODE), country_code);
385 profile->SetInfo(AutoFillType(PHONE_HOME_CITY_CODE), city_code);
386 profile->SetInfo(AutoFillType(PHONE_HOME_NUMBER), number);
387
388 PhoneNumber::ParsePhoneNumber(
389 GetEntryText(fax_), &number, &city_code, &country_code);
390 profile->SetInfo(AutoFillType(PHONE_FAX_COUNTRY_CODE), country_code);
391 profile->SetInfo(AutoFillType(PHONE_FAX_CITY_CODE), city_code);
392 profile->SetInfo(AutoFillType(PHONE_FAX_NUMBER), number);
393 }
394
395 void AutoFillProfileEditor::UpdatePhoneImage(GtkWidget* entry,
396 GtkWidget* image) {
397 string16 number, city_code, country_code;
398 string16 text(GetEntryText(entry));
399 if (text.empty()) {
400 gtk_image_set_from_pixbuf(GTK_IMAGE(image), NULL);
401 } else if (PhoneNumber::ParsePhoneNumber(text, &number, &city_code,
402 &country_code)) {
403 gtk_image_set_from_pixbuf(GTK_IMAGE(image),
404 ResourceBundle::GetSharedInstance().GetPixbufNamed(
405 IDR_INPUT_GOOD));
406 } else {
407 gtk_image_set_from_pixbuf(GTK_IMAGE(image),
408 ResourceBundle::GetSharedInstance().GetPixbufNamed(
409 IDR_INPUT_ALERT));
410 }
411 }
412
413 void AutoFillProfileEditor::SetPhoneSizeRequest(GtkWidget* widget) {
414 GdkPixbuf* buf =
415 ResourceBundle::GetSharedInstance().GetPixbufNamed(IDR_INPUT_ALERT);
416 gtk_widget_set_size_request(widget,
417 gdk_pixbuf_get_width(buf),
418 gdk_pixbuf_get_height(buf));
419 }
420
421 void AutoFillProfileEditor::OnDestroy(GtkWidget* widget) {
422 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
423 }
424
425 void AutoFillProfileEditor::OnResponse(GtkDialog* dialog, gint response_id) {
426 if (response_id == GTK_RESPONSE_APPLY || response_id == GTK_RESPONSE_OK)
427 ApplyEdits();
428
429 if (response_id == GTK_RESPONSE_OK ||
430 response_id == GTK_RESPONSE_APPLY ||
431 response_id == GTK_RESPONSE_CANCEL ||
432 response_id == GTK_RESPONSE_DELETE_EVENT) {
433 gtk_widget_destroy(GTK_WIDGET(dialog));
434 }
435 }
436
437 void AutoFillProfileEditor::OnPhoneChanged(GtkEditable* editable) {
438 UpdatePhoneImage(phone_, phone_image_);
439 }
440
441 void AutoFillProfileEditor::OnFaxChanged(GtkEditable* editable) {
442 UpdatePhoneImage(fax_, fax_image_);
443 }
444
445 // AutoFillCreditCardEditor ----------------------------------------------------
446
447 // Number of years shown in the expiration year combobox.
448 const int kNumYears = 10;
449
450 // Class responsible for editing/creating a CreditCard.
451 class AutoFillCreditCardEditor {
452 public:
453 AutoFillCreditCardEditor(AutoFillDialogObserver* observer,
454 Profile* profile,
455 CreditCard* credit_card);
456
457 private:
458 friend class DeleteTask<AutoFillCreditCardEditor>;
459
460 // Types of columns in the address_store_.
461 enum ColumnTypes {
462 // Unique if of the CreditCard.
463 COL_ID,
464
465 // Title of the column.
466 COL_TITLE,
467
468 COL_COUNT
469 };
470
471 ~AutoFillCreditCardEditor() {}
472
473 // Creates the GtkListStore used to show the billing addresses.
474 GtkListStore* CreateAddressStore();
475
476 // Creates the combobox used to show the billing addresses.
477 GtkWidget* CreateAddressWidget();
478
479 // Creates the combobox for chosing the month.
480 GtkWidget* CreateMonthWidget();
481
482 // Creates the combobox for chosing the year.
483 GtkWidget* CreateYearWidget();
484
485 void Init();
486
487 // Sets the values displayed in the various widgets from |profile|.
488 void SetWidgetValues(CreditCard* profile);
489
490 // Updates the observer with the CreditCard being edited.
491 void ApplyEdits();
492
493 // Updates |card| with the values from the widgets.
494 void SetCreditCardValuesFromWidgets(CreditCard* card);
495
496 CHROMEGTK_CALLBACK_0(AutoFillCreditCardEditor, void, OnDestroy);
497 CHROMEG_CALLBACK_1(AutoFillCreditCardEditor, void, OnResponse, GtkDialog*,
498 gint);
499
500 // Are we creating a new credit card?
501 const bool is_new_;
502
503 // If is_new_ is false this is the unique id of the credit card the user is
504 // editing.
505 const int credit_card_id_;
506
507 AutoFillDialogObserver* observer_;
508
509 Profile* profile_;
510
511 // Initial year shown in expiration date year combobox.
512 int base_year_;
513
514 GtkWidget* dialog_;
515 GtkWidget* name_;
516 GtkWidget* address_;
517 GtkWidget* number_;
518 GtkWidget* month_;
519 GtkWidget* year_;
520
521 GtkListStore* address_store_;
522
523 DISALLOW_COPY_AND_ASSIGN(AutoFillCreditCardEditor);
524 };
525
526 AutoFillCreditCardEditor::AutoFillCreditCardEditor(
527 AutoFillDialogObserver* observer,
528 Profile* profile,
529 CreditCard* credit_card)
530 : is_new_(!credit_card ? true : false),
531 credit_card_id_(credit_card ? credit_card->unique_id() : 0),
532 observer_(observer),
533 profile_(profile),
534 base_year_(0) {
535 base::Time::Exploded exploded_time;
536 base::Time::Now().LocalExplode(&exploded_time);
537 base_year_ = exploded_time.year;
538
539 Init();
540
541 if (credit_card) {
542 SetWidgetValues(credit_card);
543 } else {
544 // We're creating a new credit card. Select a default billing address (if
545 // there are any) and select Januay of next year.
546 PersonalDataManager* data_manager = profile_->GetPersonalDataManager();
547 if (!data_manager->profiles().empty())
548 gtk_combo_box_set_active(GTK_COMBO_BOX(address_), 0);
549 gtk_combo_box_set_active(GTK_COMBO_BOX(month_), 0);
550 gtk_combo_box_set_active(GTK_COMBO_BOX(year_), 1);
551 }
552
553 gtk_util::ShowDialogWithLocalizedSize(
554 dialog_,
555 IDS_AUTOFILL_DIALOG_EDIT_CCARD_WIDTH_CHARS,
556 IDS_AUTOFILL_DIALOG_EDIT_CCARD_HEIGHT_LINES,
557 true);
558 gtk_util::PresentWindow(dialog_, gtk_get_current_event_time());
559 }
560
561 GtkListStore* AutoFillCreditCardEditor::CreateAddressStore() {
562 GtkListStore* store =
563 gtk_list_store_new(COL_COUNT, G_TYPE_INT, G_TYPE_STRING);
564
565 GtkTreeIter iter;
566
567 PersonalDataManager* data_manager = profile_->GetPersonalDataManager();
568 for (std::vector<AutoFillProfile*>::const_iterator i =
569 data_manager->profiles().begin();
570 i != data_manager->profiles().end(); ++i) {
571 gtk_list_store_append(store, &iter);
572 gtk_list_store_set(
573 store, &iter,
574 COL_ID, (*i)->unique_id(),
575 COL_TITLE, UTF16ToUTF8((*i)->PreviewSummary()).c_str(),
576 -1);
577 }
578 return store;
579 }
580
581 GtkWidget* AutoFillCreditCardEditor::CreateAddressWidget() {
582 address_store_ = CreateAddressStore();
583
584 GtkWidget* widget = gtk_combo_box_new_with_model(
585 GTK_TREE_MODEL(address_store_));
586 g_object_unref(address_store_);
587
588 GtkCellRenderer* cell = gtk_cell_renderer_text_new();
589 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(widget), cell, TRUE);
590 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(widget), cell,
591 "text", COL_TITLE, NULL);
592 return widget;
593 }
594
595 GtkWidget* AutoFillCreditCardEditor::CreateMonthWidget() {
596 GtkWidget* combobox = gtk_combo_box_new_text();
597 for (int i = 1; i <= 12; ++i) {
598 gtk_combo_box_append_text(GTK_COMBO_BOX(combobox),
599 StringPrintf("%02i", i).c_str());
600 }
601
602 SetComboBoxCellRendererCharWidth(combobox, 2);
603 return combobox;
604 }
605
606 GtkWidget* AutoFillCreditCardEditor::CreateYearWidget() {
607 GtkWidget* combobox = gtk_combo_box_new_text();
608 for (int i = 0; i < kNumYears; ++i) {
609 gtk_combo_box_append_text(GTK_COMBO_BOX(combobox),
610 StringPrintf("%04i", i + base_year_).c_str());
611 }
612
613 SetComboBoxCellRendererCharWidth(combobox, 4);
614 return combobox;
615 }
616
617 void AutoFillCreditCardEditor::Init() {
618 TableBuilder main_table_builder(8, 2);
619
620 main_table_builder.AddWidget(
621 CreateLabel(IDS_AUTOFILL_DIALOG_NAME_ON_CARD), 2);
622 name_ = main_table_builder.AddWidget(gtk_entry_new(), 2);
623
624 main_table_builder.AddWidget(CreateLabel(IDS_AUTOFILL_DIALOG_BILLING_ADDRESS),
625 2);
626 address_ = main_table_builder.AddWidget(CreateAddressWidget(), 2);
627
628 main_table_builder.AddWidget(
629 CreateLabel(IDS_AUTOFILL_DIALOG_CREDIT_CARD_NUMBER), 2);
630 number_ = main_table_builder.AddWidget(gtk_entry_new(), 1);
631 gtk_entry_set_width_chars(GTK_ENTRY(number_), 20);
632 // Add an empty widget purely for spacing to match the mocks.
633 main_table_builder.AddWidget(gtk_hbox_new(FALSE, 0), 1);
634
635 main_table_builder.AddWidget(CreateLabel(IDS_AUTOFILL_DIALOG_EXPIRATION_DATE),
636 2);
637 GtkWidget* box = main_table_builder.AddWidget(
638 gtk_hbox_new(FALSE, gtk_util::kControlSpacing), 1);
639 month_ = CreateMonthWidget();
640 gtk_box_pack_start(GTK_BOX(box), month_, FALSE, FALSE, 0);
641 year_ = CreateYearWidget();
642 gtk_box_pack_start(GTK_BOX(box), year_, FALSE, FALSE, 0);
643 main_table_builder.increment_row();
644
645 int caption_id = is_new_ ? IDS_AUTOFILL_ADD_CREDITCARD_CAPTION :
646 IDS_AUTOFILL_EDIT_CREDITCARD_CAPTION;
647 dialog_ = gtk_dialog_new_with_buttons(
648 l10n_util::GetStringUTF8(caption_id).c_str(),
649 NULL,
650 static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
651 GTK_STOCK_APPLY,
652 GTK_RESPONSE_APPLY,
653 GTK_STOCK_CANCEL,
654 GTK_RESPONSE_CANCEL,
655 NULL);
656
657 g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this);
658 g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroyThunk), this);
659
660 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox),
661 main_table_builder.table(), TRUE, TRUE, 0);
662 }
663
664 void AutoFillCreditCardEditor::SetWidgetValues(CreditCard* card) {
665 SetEntryText(name_, card, CREDIT_CARD_NAME);
666
667 PersonalDataManager* data_manager = profile_->GetPersonalDataManager();
668 for (std::vector<AutoFillProfile*>::const_iterator i =
669 data_manager->profiles().begin();
670 i != data_manager->profiles().end(); ++i) {
671 if ((*i)->Label() == card->billing_address()) {
672 int index = static_cast<int>(i - data_manager->profiles().begin());
673 gtk_combo_box_set_active(GTK_COMBO_BOX(address_), index);
674 break;
675 }
676 }
677
678 SetEntryText(number_, card, CREDIT_CARD_NUMBER);
679
680 int month = StringToInt(
681 UTF16ToUTF8(card->GetFieldText(AutoFillType(CREDIT_CARD_EXP_MONTH))));
682 if (month >= 1 && month <= 12) {
683 gtk_combo_box_set_active(GTK_COMBO_BOX(month_), month - 1);
684 } else {
685 gtk_combo_box_set_active(GTK_COMBO_BOX(month_), 0);
686 }
687
688 int year = StringToInt(UTF16ToUTF8(
689 card->GetFieldText(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR))));
690 if (year >= base_year_ && year < base_year_ + kNumYears)
691 gtk_combo_box_set_active(GTK_COMBO_BOX(year_), year - base_year_);
692 else
693 gtk_combo_box_set_active(GTK_COMBO_BOX(year_), 0);
694 }
695
696 void AutoFillCreditCardEditor::ApplyEdits() {
697 // Build a vector of the current set of credit cards.
698 PersonalDataManager* data_manager = profile_->GetPersonalDataManager();
699 std::vector<CreditCard> cards;
700 for (std::vector<CreditCard*>::const_iterator i =
701 data_manager->credit_cards().begin();
702 i != data_manager->credit_cards().end(); ++i) {
703 cards.push_back(**i);
704 }
705
706 CreditCard* card = NULL;
707
708 if (!is_new_) {
709 // The user is editing an existing credit card, find it.
710 for (std::vector<CreditCard>::iterator i = cards.begin();
711 i != cards.end(); ++i) {
712 if (i->unique_id() == credit_card_id_) {
713 card = &(*i);
714 break;
715 }
716 }
717 DCHECK(card); // We should have found the credit card we were created with,
718 // if not we'll end up creating one below.
719 }
720
721 if (!card) {
722 cards.push_back(CreditCard());
723 card = &cards.back();
724 }
725
726 // Update the credit card from what the user typedi n.
727 SetCreditCardValuesFromWidgets(card);
728
729 // And update the model.
730 observer_->OnAutoFillDialogApply(NULL, &cards);
731 }
732
733 void AutoFillCreditCardEditor::SetCreditCardValuesFromWidgets(
734 CreditCard* card) {
735 PersonalDataManager* data_manager = profile_->GetPersonalDataManager();
736
737 SetFormValue(name_, card, CREDIT_CARD_NAME);
738
739 card->set_billing_address(string16());
740 int selected_address_index =
741 gtk_combo_box_get_active(GTK_COMBO_BOX(address_));
742 if (selected_address_index != -1) {
743 GtkTreeIter iter;
744 gtk_tree_model_iter_nth_child(
745 GTK_TREE_MODEL(address_store_), &iter, NULL, selected_address_index);
746 GValue value = { 0 };
747 gtk_tree_model_get_value(
748 GTK_TREE_MODEL(address_store_), &iter, COL_ID, &value);
749 int id = g_value_get_int(&value);
750 for (std::vector<AutoFillProfile*>::const_iterator i =
751 data_manager->profiles().begin();
752 i != data_manager->profiles().end(); ++i) {
753 if ((*i)->unique_id() == id) {
754 card->set_billing_address((*i)->Label());
755 break;
756 }
757 }
758 g_value_unset(&value);
759 }
760
761 SetFormValue(number_, card, CREDIT_CARD_NUMBER);
762
763 int selected_month_index =
764 gtk_combo_box_get_active(GTK_COMBO_BOX(month_));
765 if (selected_month_index == -1)
766 selected_month_index = 0;
767 card->SetInfo(AutoFillType(CREDIT_CARD_EXP_MONTH),
768 IntToString16(selected_month_index + 1));
769
770 int selected_year_index =
771 gtk_combo_box_get_active(GTK_COMBO_BOX(year_));
772 if (selected_year_index == -1)
773 selected_year_index = 0;
774 card->SetInfo(AutoFillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
775 IntToString16(selected_year_index + base_year_));
776 }
777
778 void AutoFillCreditCardEditor::OnDestroy(GtkWidget* widget) {
779 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
780 }
781
782 void AutoFillCreditCardEditor::OnResponse(GtkDialog* dialog, gint response_id) {
783 if (response_id == GTK_RESPONSE_APPLY || response_id == GTK_RESPONSE_OK)
784 ApplyEdits();
785
786 if (response_id == GTK_RESPONSE_OK ||
787 response_id == GTK_RESPONSE_APPLY ||
788 response_id == GTK_RESPONSE_CANCEL ||
789 response_id == GTK_RESPONSE_DELETE_EVENT) {
790 gtk_widget_destroy(GTK_WIDGET(dialog));
791 }
792 }
793
794 } // namespace
795
796 void ShowAutoFillProfileEditor(gfx::NativeView parent,
797 AutoFillDialogObserver* observer,
798 Profile* profile,
799 AutoFillProfile* auto_fill_profile) {
800 // AutoFillProfileEditor takes care of deleting itself.
801 new AutoFillProfileEditor(observer, profile, auto_fill_profile);
802 }
803
804 void ShowAutoFillCreditCardEditor(gfx::NativeView parent,
805 AutoFillDialogObserver* observer,
806 Profile* profile,
807 CreditCard* credit_card) {
808 // AutoFillCreditCardEditor takes care of deleting itself.
809 new AutoFillCreditCardEditor(observer, profile, credit_card);
810 }
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/autofill/autofill_dialog.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698