Location | Tool | Test ID | Function | Issue |
---|---|---|---|---|
e-contact-editor.c:1139:3 | clang-analyzer | Value stored to 'l' is never read | ||
e-contact-editor.c:1139:3 | clang-analyzer | Value stored to 'l' is never read | ||
e-contact-editor.c:1491:3 | clang-analyzer | Value stored to 'l' is never read | ||
e-contact-editor.c:1491:3 | clang-analyzer | Value stored to 'l' is never read | ||
e-contact-editor.c:1908:4 | clang-analyzer | Value stored to 'l' is never read | ||
e-contact-editor.c:1908:4 | clang-analyzer | Value stored to 'l' is never read |
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 *
16 * Authors:
17 * Chris Lahey <clahey@ximian.com>
18 *
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20 *
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include "eab-editor.h"
28 #include "e-contact-editor.h"
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <time.h>
33 #include <gtk/gtk.h>
34 #include <glib/gi18n.h>
35 #include <gdk/gdkkeysyms.h>
36 #include <gdk-pixbuf/gdk-pixbuf.h>
37
38 #include <libedataserverui/libedataserverui.h>
39
40 #include "addressbook/printing/e-contact-print.h"
41 #include "addressbook/gui/widgets/eab-gui-util.h"
42 #include "e-util/e-util.h"
43 #include "libevolution-utils/e-alert-dialog.h"
44 #include "misc/e-dateedit.h"
45 #include "misc/e-image-chooser.h"
46 #include "misc/e-url-entry.h"
47 #include "e-util/e-icon-factory.h"
48 #include "e-util/e-util-private.h"
49 #include "shell/e-shell.h"
50
51 #include "eab-contact-merging.h"
52
53 #include "e-contact-editor-fullname.h"
54
55 #define EMAIL_SLOTS 4
56 #define PHONE_SLOTS 8
57 #define IM_SLOTS 4
58 #define ADDRESS_SLOTS 3
59
60 #define EVOLUTION_UI_SLOT_PARAM "X-EVOLUTION-UI-SLOT"
61
62 /* IM columns */
63 enum {
64 COLUMN_IM_ICON,
65 COLUMN_IM_SERVICE,
66 COLUMN_IM_SCREENNAME,
67 COLUMN_IM_LOCATION,
68 COLUMN_IM_LOCATION_TYPE,
69 COLUMN_IM_SERVICE_FIELD,
70 NUM_IM_COLUMNS
71 };
72
73 static void e_contact_editor_set_property (GObject *object,
74 guint property_id,
75 const GValue *value,
76 GParamSpec *pspec);
77 static void e_contact_editor_get_property (GObject *object,
78 guint property_id,
79 GValue *value,
80 GParamSpec *pspec);
81 static void e_contact_editor_dispose (GObject *object);
82 static void e_contact_editor_raise (EABEditor *editor);
83 static void e_contact_editor_show (EABEditor *editor);
84 static void e_contact_editor_save_contact (EABEditor *editor,
85 gboolean should_close);
86 static void e_contact_editor_close (EABEditor *editor);
87 static gboolean e_contact_editor_is_valid (EABEditor *editor);
88 static gboolean e_contact_editor_is_changed (EABEditor *editor);
89 static GtkWindow *
90 e_contact_editor_get_window (EABEditor *editor);
91 static void save_contact (EContactEditor *ce,
92 gboolean should_close);
93 static void entry_activated (EContactEditor *editor);
94
95 static void set_entry_text (EContactEditor *editor,
96 GtkEntry *entry,
97 const gchar *string);
98 static void sensitize_ok (EContactEditor *ce);
99
100 static EABEditorClass *parent_class = NULL;
101
102 enum {
103 PROP_0,
104 PROP_SOURCE_CLIENT,
105 PROP_TARGET_CLIENT,
106 PROP_CONTACT,
107 PROP_IS_NEW_CONTACT,
108 PROP_EDITABLE,
109 PROP_CHANGED,
110 PROP_WRITABLE_FIELDS,
111 PROP_REQUIRED_FIELDS
112 };
113
114 enum {
115 DYNAMIC_LIST_EMAIL,
116 DYNAMIC_LIST_PHONE,
117 DYNAMIC_LIST_ADDRESS
118 };
119
120 static struct {
121 EContactField field_id;
122 const gchar *type_1;
123 const gchar *type_2;
124 }
125 phones[] = {
126 { E_CONTACT_PHONE_ASSISTANT, EVC_X_ASSISTANT, NULL },
127 { E_CONTACT_PHONE_BUSINESS, "WORK", "VOICE" },
128 { E_CONTACT_PHONE_BUSINESS_FAX, "WORK", "FAX" },
129 { E_CONTACT_PHONE_CALLBACK, EVC_X_CALLBACK, NULL },
130 { E_CONTACT_PHONE_CAR, "CAR", NULL },
131 { E_CONTACT_PHONE_COMPANY, "X-EVOLUTION-COMPANY", NULL },
132 { E_CONTACT_PHONE_HOME, "HOME", "VOICE" },
133 { E_CONTACT_PHONE_HOME_FAX, "HOME", "FAX" },
134 { E_CONTACT_PHONE_ISDN, "ISDN", NULL },
135 { E_CONTACT_PHONE_MOBILE, "CELL", NULL },
136 { E_CONTACT_PHONE_OTHER, "VOICE", NULL },
137 { E_CONTACT_PHONE_OTHER_FAX, "FAX", NULL },
138 { E_CONTACT_PHONE_PAGER, "PAGER", NULL },
139 { E_CONTACT_PHONE_PRIMARY, "PREF", NULL },
140 { E_CONTACT_PHONE_RADIO, EVC_X_RADIO, NULL },
141 { E_CONTACT_PHONE_TELEX, EVC_X_TELEX, NULL },
142 { E_CONTACT_PHONE_TTYTDD, EVC_X_TTYTDD, NULL }
143 };
144
145 /* Defaults from the table above */
146 static const gint phones_default[] = { 1, 6, 9, 2, 7, 12, 10, 10 };
147
148 static EContactField addresses[] = {
149 E_CONTACT_ADDRESS_WORK,
150 E_CONTACT_ADDRESS_HOME,
151 E_CONTACT_ADDRESS_OTHER
152 };
153
154 static EContactField address_labels[] = {
155 E_CONTACT_ADDRESS_LABEL_WORK,
156 E_CONTACT_ADDRESS_LABEL_HOME,
157 E_CONTACT_ADDRESS_LABEL_OTHER
158 };
159
160 static const gchar *address_name[] = {
161 "work",
162 "home",
163 "other"
164 };
165
166 static struct {
167 EContactField field;
168 const gchar *pretty_name;
169 }
170 im_service[] =
171 {
172 { E_CONTACT_IM_AIM, N_ ("AIM") },
173 { E_CONTACT_IM_JABBER, N_ ("Jabber") },
174 { E_CONTACT_IM_YAHOO, N_ ("Yahoo") },
175 { E_CONTACT_IM_GADUGADU, N_ ("Gadu-Gadu") },
176 { E_CONTACT_IM_MSN, N_ ("MSN") },
177 { E_CONTACT_IM_ICQ, N_ ("ICQ") },
178 { E_CONTACT_IM_GROUPWISE, N_ ("GroupWise") },
179 { E_CONTACT_IM_SKYPE, N_ ("Skype") },
180 { E_CONTACT_IM_TWITTER, N_ ("Twitter") }
181 };
182
183 /* Defaults from the table above */
184 static const gint im_service_default[] = { 0, 2, 4, 5 };
185
186 static struct {
187 const gchar *name;
188 const gchar *pretty_name;
189 }
190 common_location[] =
191 {
192 { "WORK", N_ ("Work") },
193 { "HOME", N_ ("Home") },
194 { "OTHER", N_ ("Other") }
195 };
196
197 /* Default from the table above */
198 static const gint email_default[] = { 0, 1, 2, 2 };
199
200 #define STRING_IS_EMPTY(x) (!(x) || !(*(x)))
201 #define STRING_MAKE_NON_NULL(x) ((x) ? (x) : "")
202
203 G_DEFINE_TYPE (EContactEditor, e_contact_editor, EAB_TYPE_EDITOR)
204
205 static void
206 e_contact_editor_contact_added (EABEditor *editor,
207 const GError *error,
208 EContact *contact)
209 {
210 if (!error)
211 return;
212
213 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
214 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
215 return;
216
217 eab_error_dialog (NULL, _("Error adding contact"), error);
218 }
219
220 static void
221 e_contact_editor_contact_modified (EABEditor *editor,
222 const GError *error,
223 EContact *contact)
224 {
225 if (!error)
226 return;
227
228 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
229 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
230 return;
231
232 eab_error_dialog (NULL, _("Error modifying contact"), error);
233 }
234
235 static void
236 e_contact_editor_contact_deleted (EABEditor *editor,
237 const GError *error,
238 EContact *contact)
239 {
240 if (!error)
241 return;
242
243 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
244 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
245 return;
246
247 eab_error_dialog (NULL, _("Error removing contact"), error);
248 }
249
250 static void
251 e_contact_editor_closed (EABEditor *editor)
252 {
253 g_object_unref (editor);
254 }
255
256 static void
257 e_contact_editor_class_init (EContactEditorClass *class)
258 {
259 GObjectClass *object_class = G_OBJECT_CLASS (class);
260 EABEditorClass *editor_class = EAB_EDITOR_CLASS (class);
261
262 parent_class = g_type_class_ref (EAB_TYPE_EDITOR);
263
264 object_class->set_property = e_contact_editor_set_property;
265 object_class->get_property = e_contact_editor_get_property;
266 object_class->dispose = e_contact_editor_dispose;
267
268 editor_class->raise = e_contact_editor_raise;
269 editor_class->show = e_contact_editor_show;
270 editor_class->close = e_contact_editor_close;
271 editor_class->is_valid = e_contact_editor_is_valid;
272 editor_class->save_contact = e_contact_editor_save_contact;
273 editor_class->is_changed = e_contact_editor_is_changed;
274 editor_class->get_window = e_contact_editor_get_window;
275 editor_class->contact_added = e_contact_editor_contact_added;
276 editor_class->contact_modified = e_contact_editor_contact_modified;
277 editor_class->contact_deleted = e_contact_editor_contact_deleted;
278 editor_class->editor_closed = e_contact_editor_closed;
279
280 g_object_class_install_property (
281 object_class,
282 PROP_SOURCE_CLIENT,
283 g_param_spec_object (
284 "source_client",
285 "Source EBookClient",
286 NULL,
287 E_TYPE_BOOK_CLIENT,
288 G_PARAM_READWRITE));
289
290 g_object_class_install_property (
291 object_class,
292 PROP_TARGET_CLIENT,
293 g_param_spec_object (
294 "target_client",
295 "Target EBookClient",
296 NULL,
297 E_TYPE_BOOK_CLIENT,
298 G_PARAM_READWRITE));
299
300 g_object_class_install_property (
301 object_class,
302 PROP_CONTACT,
303 g_param_spec_object (
304 "contact",
305 "Contact",
306 NULL,
307 E_TYPE_CONTACT,
308 G_PARAM_READWRITE));
309
310 g_object_class_install_property (
311 object_class,
312 PROP_IS_NEW_CONTACT,
313 g_param_spec_boolean (
314 "is_new_contact",
315 "Is New Contact",
316 NULL,
317 FALSE,
318 G_PARAM_READWRITE));
319
320 g_object_class_install_property (
321 object_class,
322 PROP_WRITABLE_FIELDS,
323 g_param_spec_pointer (
324 "writable_fields",
325 "Writable Fields",
326 NULL,
327 G_PARAM_READWRITE));
328
329 g_object_class_install_property (
330 object_class,
331 PROP_REQUIRED_FIELDS,
332 g_param_spec_pointer (
333 "required_fields",
334 "Required Fields",
335 NULL,
336 G_PARAM_READWRITE));
337
338 g_object_class_install_property (
339 object_class,
340 PROP_EDITABLE,
341 g_param_spec_boolean (
342 "editable",
343 "Editable",
344 NULL,
345 FALSE,
346 G_PARAM_READWRITE));
347
348 g_object_class_install_property (
349 object_class,
350 PROP_CHANGED,
351 g_param_spec_boolean (
352 "changed",
353 "Changed",
354 NULL,
355 FALSE,
356 G_PARAM_READWRITE));
357 }
358
359 static void
360 entry_activated (EContactEditor *editor)
361 {
362 save_contact (editor, TRUE);
363 }
364
365 /* FIXME: Linear time... */
366 static gboolean
367 is_field_supported (EContactEditor *editor,
368 EContactField field_id)
369 {
370 GSList *fields, *iter;
371 const gchar *field;
372
373 fields = editor->writable_fields;
374 if (!fields)
375 return FALSE;
376
377 field = e_contact_field_name (field_id);
378 if (!field)
379 return FALSE;
380
381 for (iter = fields; iter; iter = iter->next) {
382 const gchar *this_field = iter->data;
383
384 if (!this_field)
385 continue;
386
387 if (!strcmp (field, this_field))
388 return TRUE;
389 }
390
391 return FALSE;
392 }
393
394 /* This function tells you whether name_to_style will make sense. */
395 static gboolean
396 style_makes_sense (const EContactName *name,
397 const gchar *company,
398 gint style)
399 {
400 switch (style) {
401 case 0: /* Fall Through */
402 case 1:
403 return TRUE;
404 case 2:
405 if (name) {
406 if (name->additional && *name->additional)
407 return TRUE;
408 else
409 return FALSE;
410 }
411 case 3:
412 if (company && *company)
413 return TRUE;
414 else
415 return FALSE;
416 case 4: /* Fall Through */
417 case 5:
418 if (company && *company && name &&
419 ((name->given && *name->given) ||
420 (name->family && *name->family)))
421 return TRUE;
422 else
423 return FALSE;
424 default:
425 return FALSE;
426 }
427 }
428
429 static gchar *
430 name_to_style (const EContactName *name,
431 const gchar *company,
432 gint style)
433 {
434 gchar *string;
435 gchar *strings[4], **stringptr;
436 gchar *midstring[4], **midstrptr;
437 gchar *substring;
438 switch (style) {
439 case 0:
440 stringptr = strings;
441 if (name) {
442 if (name->family && *name->family)
443 *(stringptr++) = name->family;
444 if (name->given && *name->given)
445 *(stringptr++) = name->given;
446 }
447 *stringptr = NULL;
448 string = g_strjoinv (", ", strings);
449 break;
450 case 1:
451 stringptr = strings;
452 if (name) {
453 if (name->given && *name->given)
454 *(stringptr++) = name->given;
455 if (name->family && *name->family)
456 *(stringptr++) = name->family;
457 }
458 *stringptr = NULL;
459 string = g_strjoinv (" ", strings);
460 break;
461 case 2:
462 midstrptr = midstring;
463 if (name) {
464 if (name->family && *name->family)
465 *(midstrptr++) = name->family;
466 if (name->given && *name->given)
467 *(midstrptr++) = name->given;
468 }
469 *midstrptr = NULL;
470 stringptr = strings;
471 *(stringptr++) = g_strjoinv(", ", midstring);
472 if (name) {
473 if (name->additional && *name->additional)
474 *(stringptr++) = name->additional;
475 }
476 *stringptr = NULL;
477 string = g_strjoinv (" ", strings);
478 break;
479 case 3:
480 string = g_strdup (company);
481 break;
482 case 4: /* Fall Through */
483 case 5:
484 stringptr = strings;
485 if (name) {
486 if (name->family && *name->family)
487 *(stringptr++) = name->family;
488 if (name->given && *name->given)
489 *(stringptr++) = name->given;
490 }
491 *stringptr = NULL;
492 substring = g_strjoinv (", ", strings);
493 if (!(company && *company))
494 company = "";
495 if (style == 4)
496 string = g_strdup_printf ("%s (%s)", substring, company);
497 else
498 string = g_strdup_printf ("%s (%s)", company, substring);
499 g_free (substring);
500 break;
501 default:
502 string = g_strdup ("");
503 }
504 return string;
505 }
506
507 static gint
508 file_as_get_style (EContactEditor *editor)
509 {
510 GtkEntry *file_as = GTK_ENTRY (
511 gtk_bin_get_child (GTK_BIN (
512 e_builder_get_widget (editor->builder, "combo-file-as"))));
513 GtkEntry *company_w = GTK_ENTRY (
514 e_builder_get_widget (editor->builder, "entry-company"));
515 gchar *filestring;
516 gchar *trystring;
517 EContactName *name = editor->name;
518 const gchar *company;
519 gint i;
520
521 if (!(file_as && GTK_IS_ENTRY (file_as)))
522 return -1;
523
524 company = gtk_entry_get_text (GTK_ENTRY (company_w));
525 filestring = g_strdup (gtk_entry_get_text (file_as));
526
527 for (i = 0; i < 6; i++) {
528 trystring = name_to_style (name, company, i);
529 if (!strcmp (trystring, filestring)) {
530 g_free (trystring);
531 g_free (filestring);
532 return i;
533 }
534 g_free (trystring);
535 }
536 g_free (filestring);
537 return -1;
538 }
539
540 static void
541 file_as_set_style (EContactEditor *editor,
542 gint style)
543 {
544 gchar *string;
545 gint i;
546 GList *strings = NULL;
547 GtkComboBox *combo_file_as = GTK_COMBO_BOX (
548 e_builder_get_widget (editor->builder, "combo-file-as"));
549 GtkEntry *company_w = GTK_ENTRY (
550 e_builder_get_widget (editor->builder, "entry-company"));
551 const gchar *company;
552
553 if (!(combo_file_as && GTK_IS_COMBO_BOX (combo_file_as)))
554 return;
555
556 company = gtk_entry_get_text (GTK_ENTRY (company_w));
557
558 if (style == -1) {
559 GtkWidget *entry;
560
561 entry = gtk_bin_get_child (GTK_BIN (combo_file_as));
562 if (entry) {
563 string = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
564 strings = g_list_append (strings, string);
565 }
566 }
567
568 for (i = 0; i < 6; i++) {
569 if (style_makes_sense (editor->name, company, i)) {
570 gchar *u;
571 u = name_to_style (editor->name, company, i);
572 if (!STRING_IS_EMPTY (u))
573 strings = g_list_append (strings, u);
574 else
575 g_free (u);
576 }
577 }
578
579 if (combo_file_as) {
580 GList *l;
581 GtkListStore *list_store;
582 GtkTreeIter iter;
583
584 list_store = GTK_LIST_STORE (
585 gtk_combo_box_get_model (combo_file_as));
586
587 gtk_list_store_clear (list_store);
588
589 for (l = strings; l; l = l->next) {
590 gtk_list_store_append (list_store, &iter);
591 gtk_list_store_set (list_store, &iter, 0, l->data, -1);
592 }
593 }
594
595 g_list_foreach (strings, (GFunc) g_free, NULL);
596 g_list_free (strings);
597
598 if (style != -1) {
599 string = name_to_style (editor->name, company, style);
600 set_entry_text (
601 editor, GTK_ENTRY (gtk_bin_get_child (
602 GTK_BIN (combo_file_as))), string);
603 g_free (string);
604 }
605 }
606
607 static void
608 name_entry_changed (GtkWidget *widget,
609 EContactEditor *editor)
610 {
611 gint style = 0;
612 const gchar *string;
613
614 style = file_as_get_style (editor);
615 e_contact_name_free (editor->name);
616 string = gtk_entry_get_text (GTK_ENTRY (widget));
617 editor->name = e_contact_name_from_string (string);
618 file_as_set_style (editor, style);
619
620 editor->check_merge = TRUE;
621
622 sensitize_ok (editor);
623 if (string && !*string)
624 gtk_window_set_title (
625 GTK_WINDOW (editor->app), _("Contact Editor"));
626 }
627
628 static void
629 file_as_combo_changed (GtkWidget *widget,
630 EContactEditor *editor)
631 {
632 GtkWidget *entry;
633 gchar *string = NULL;
634
635 entry = gtk_bin_get_child (GTK_BIN (widget));
636 if (entry)
637 string = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
638
639 if (string && *string) {
640 gchar *title;
641 title = g_strdup_printf (_("Contact Editor - %s"), string);
642 gtk_window_set_title (GTK_WINDOW (editor->app), title);
643 g_free (title);
644 }
645 else {
646 gtk_window_set_title (
647 GTK_WINDOW (editor->app), _("Contact Editor"));
648 }
649 sensitize_ok (editor);
650
651 g_free (string);
652 }
653
654 static void
655 company_entry_changed (GtkWidget *widget,
656 EContactEditor *editor)
657 {
658 gint style = 0;
659
660 style = file_as_get_style (editor);
661 file_as_set_style (editor, style);
662 }
663
664 static void
665 update_file_as_combo (EContactEditor *editor)
666 {
667 file_as_set_style (editor, file_as_get_style (editor));
668 }
669
670 static void
671 fill_in_source_field (EContactEditor *editor)
672 {
673 GtkWidget *source_menu;
674
675 if (!editor->target_client)
676 return;
677
678 source_menu = e_builder_get_widget (
679 editor->builder, "source-combo-box-source");
680
681 e_source_combo_box_set_active (
682 E_SOURCE_COMBO_BOX (source_menu),
683 e_client_get_source (E_CLIENT (editor->target_client)));
684 }
685
686 static void
687 sensitize_ok (EContactEditor *ce)
688 {
689 GtkWidget *widget;
690 gboolean allow_save;
691 GtkWidget *entry_fullname =
692 e_builder_get_widget (ce->builder, "entry-fullname");
693 GtkWidget *entry_file_as =
694 gtk_bin_get_child (GTK_BIN (
695 e_builder_get_widget (ce->builder, "combo-file-as")));
696 GtkWidget *company_name =
697 e_builder_get_widget (ce->builder, "entry-company");
698 const gchar *name_entry_string =
699 gtk_entry_get_text (GTK_ENTRY (entry_fullname));
700 const gchar *file_as_entry_string =
701 gtk_entry_get_text (GTK_ENTRY (entry_file_as));
702 const gchar *company_name_string =
703 gtk_entry_get_text (GTK_ENTRY (company_name));
704
705 allow_save = ce->target_editable && ce->changed;
706
707 if (!strcmp (name_entry_string, "") ||
708 !strcmp (file_as_entry_string, "")) {
709 if (strcmp (company_name_string , "")) {
710 allow_save = TRUE;
711 }
712 else
713 allow_save = FALSE;
714 }
715 widget = e_builder_get_widget (ce->builder, "button-ok");
716 gtk_widget_set_sensitive (widget, allow_save);
717 }
718
719 static void
720 object_changed (GObject *object,
721 EContactEditor *editor)
722 {
723 if (!editor->target_editable) {
724 g_warning ("non-editable contact editor has an editable field in it.");
725 return;
726 }
727
728 if (!editor->check_merge && GTK_IS_WIDGET (object)) {
729 const gchar *widget_name;
730
731 widget_name = gtk_widget_get_name (GTK_WIDGET (object));
732
733 if (widget_name &&
734 ((g_str_equal (widget_name, "fullname")) ||
735 (g_str_equal (widget_name, "nickname")) ||
736 (g_str_equal (widget_name, "file-as")) ||
737 (g_str_has_prefix (widget_name, "email-"))))
738 editor->check_merge = TRUE;
739 }
740
741 if (!editor->changed) {
742 editor->changed = TRUE;
743 sensitize_ok (editor);
744 }
745 }
746
747 static void
748 image_chooser_changed (GtkWidget *widget,
749 EContactEditor *editor)
750 {
751 editor->image_set = TRUE;
752 editor->image_changed = TRUE;
753 }
754
755 static void
756 set_entry_text (EContactEditor *editor,
757 GtkEntry *entry,
758 const gchar *string)
759 {
760 const gchar *oldstring = gtk_entry_get_text (entry);
761
762 if (!string)
763 string = "";
764
765 if (strcmp (string, oldstring)) {
766 g_signal_handlers_block_matched (
767 entry, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
768 gtk_entry_set_text (entry, string);
769 g_signal_handlers_unblock_matched (
770 entry, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
771 }
772 }
773
774 static void
775 set_combo_box_active (EContactEditor *editor,
776 GtkComboBox *combo_box,
777 gint active)
778 {
779 g_signal_handlers_block_matched (
780 combo_box, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
781 gtk_combo_box_set_active (combo_box, active);
782 g_signal_handlers_unblock_matched (
783 combo_box, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
784 }
785
786 static void
787 init_email_record_location (EContactEditor *editor,
788 gint record)
789 {
790 GtkComboBox *location_combo_box;
791 GtkWidget *email_entry;
792 gchar *widget_name;
793 gint i;
794 GtkTreeIter iter;
795 GtkListStore *store;
796
797 widget_name = g_strdup_printf ("entry-email-%d", record);
798 email_entry = e_builder_get_widget (editor->builder, widget_name);
799 g_free (widget_name);
800
801 widget_name = g_strdup_printf ("combobox-email-%d", record);
802 location_combo_box = GTK_COMBO_BOX (
803 e_builder_get_widget (editor->builder, widget_name));
804 g_free (widget_name);
805
806 store = GTK_LIST_STORE (gtk_combo_box_get_model (location_combo_box));
807 gtk_list_store_clear (store);
808
809 for (i = 0; i < G_N_ELEMENTS (common_location); i++) {
810 gtk_list_store_append (store, &iter);
811 gtk_list_store_set (
812 store, &iter,
813 0, _(common_location[i].pretty_name),
814 -1);
815 }
816
817 g_signal_connect_swapped (
818 location_combo_box, "changed",
819 G_CALLBACK (gtk_widget_grab_focus), email_entry);
820 g_signal_connect (
821 location_combo_box, "changed",
822 G_CALLBACK (object_changed), editor);
823 g_signal_connect (
824 email_entry, "changed",
825 G_CALLBACK (object_changed), editor);
826 g_signal_connect_swapped (
827 email_entry, "activate",
828 G_CALLBACK (entry_activated), editor);
829 }
830
831 static void
832 fill_in_email_record (EContactEditor *editor,
833 gint record,
834 const gchar *address,
835 gint location)
836 {
837 GtkWidget *location_combo_box;
838 GtkWidget *email_entry;
839 gchar *widget_name;
840
841 widget_name = g_strdup_printf ("combobox-email-%d", record);
842 location_combo_box = e_builder_get_widget (editor->builder, widget_name);
843 g_free (widget_name);
844
845 widget_name = g_strdup_printf ("entry-email-%d", record);
846 email_entry = e_builder_get_widget (editor->builder, widget_name);
847 g_free (widget_name);
848
849 set_combo_box_active (
850 editor, GTK_COMBO_BOX (location_combo_box),
851 location >= 0 ? location : email_default[2]);
852 set_entry_text (editor, GTK_ENTRY (email_entry), address ? address : "");
853 }
854
855 static void
856 extract_email_record (EContactEditor *editor,
857 gint record,
858 gchar **address,
859 gint *location)
860 {
861 GtkWidget *location_combo_box;
862 GtkWidget *email_entry;
863 gchar *widget_name;
864 const gchar *text;
865
866 widget_name = g_strdup_printf ("combobox-email-%d", record);
867 location_combo_box = e_builder_get_widget (editor->builder, widget_name);
868 g_free (widget_name);
869
870 widget_name = g_strdup_printf ("entry-email-%d", record);
871 email_entry = e_builder_get_widget (editor->builder, widget_name);
872 g_free (widget_name);
873
874 text = gtk_entry_get_text (GTK_ENTRY (email_entry));
875 *address = g_strstrip (g_strdup (text));
876 *location = gtk_combo_box_get_active (GTK_COMBO_BOX (location_combo_box));
877 }
878
879 static const gchar *
880 email_index_to_location (gint index)
881 {
882 return common_location[index].name;
883 }
884
885 static const gchar *
886 im_index_to_location (gint index)
887 {
888 return common_location[index].name;
889 }
890
891 static void
892 phone_index_to_type (gint index,
893 const gchar **type_1,
894 const gchar **type_2)
895 {
896 *type_1 = phones [index].type_1;
897 *type_2 = phones [index].type_2;
898 }
899
900 static gint
901 get_email_location (EVCardAttribute *attr)
902 {
903 gint i;
904
905 for (i = 0; i < G_N_ELEMENTS (common_location); i++) {
906 if (e_vcard_attribute_has_type (attr, common_location[i].name))
907 return i;
908 }
909
910 return -1;
911 }
912
913 static gint
914 get_im_location (EVCardAttribute *attr)
915 {
916 gint i;
917
918 for (i = 0; i < G_N_ELEMENTS (common_location); i++) {
919 if (e_vcard_attribute_has_type (attr, common_location[i].name))
920 return i;
921 }
922
923 return -1;
924 }
925
926 static gint
927 get_phone_type (EVCardAttribute *attr)
928 {
929 gint i;
930
931 for (i = 0; i < G_N_ELEMENTS (phones); i++) {
932 if (e_vcard_attribute_has_type (attr, phones[i].type_1) &&
933 (phones[i].type_2 == NULL ||
934 e_vcard_attribute_has_type (attr, phones[i].type_2)))
935 return i;
936 }
937
938 return -1;
939 }
940
941 static EVCardAttributeParam *
942 get_ui_slot_param (EVCardAttribute *attr)
943 {
944 EVCardAttributeParam *param = NULL;
945 GList *param_list;
946 GList *l;
947
948 param_list = e_vcard_attribute_get_params (attr);
949
950 for (l = param_list; l; l = g_list_next (l)) {
951 const gchar *str;
952
953 param = l->data;
954
955 str = e_vcard_attribute_param_get_name (param);
956 if (!g_ascii_strcasecmp (str, EVOLUTION_UI_SLOT_PARAM))
957 break;
958
959 param = NULL;
960 }
961
962 return param;
963 }
964
965 static gint
966 get_ui_slot (EVCardAttribute *attr)
967 {
968 EVCardAttributeParam *param;
969 gint slot = -1;
970
971 param = get_ui_slot_param (attr);
972
973 if (param) {
974 GList *value_list;
975
976 value_list = e_vcard_attribute_param_get_values (param);
977 slot = atoi (value_list->data);
978 }
979
980 return slot;
981 }
982
983 static void
984 set_ui_slot (EVCardAttribute *attr,
985 gint slot)
986 {
987 EVCardAttributeParam *param;
988 gchar *slot_str;
989
990 param = get_ui_slot_param (attr);
991 if (!param) {
992 param = e_vcard_attribute_param_new (EVOLUTION_UI_SLOT_PARAM);
993 e_vcard_attribute_add_param (attr, param);
994 }
995
996 e_vcard_attribute_param_remove_values (param);
997
998 slot_str = g_strdup_printf ("%d", slot);
999 e_vcard_attribute_param_add_value (param, slot_str);
1000 g_free (slot_str);
1001 }
1002
1003 static gint
1004 alloc_ui_slot (EContactEditor *editor,
1005 const gchar *widget_base,
1006 gint preferred_slot,
1007 gint num_slots)
1008 {
1009 gchar *widget_name;
1010 GtkWidget *widget;
1011 const gchar *entry_contents;
1012 gint i;
1013
1014 /* See if we can get the preferred slot */
1015
1016 if (preferred_slot >= 1) {
1017 widget_name = g_strdup_printf ("%s-%d", widget_base, preferred_slot);
1018 widget = e_builder_get_widget (editor->builder, widget_name);
1019 entry_contents = gtk_entry_get_text (GTK_ENTRY (widget));
1020 g_free (widget_name);
1021
1022 if (STRING_IS_EMPTY (entry_contents))
1023 return preferred_slot;
1024 }
1025
1026 /* Find first empty slot */
1027
1028 for (i = 1; i <= num_slots; i++) {
1029 widget_name = g_strdup_printf ("%s-%d", widget_base, i);
1030 widget = e_builder_get_widget (editor->builder, widget_name);
1031 entry_contents = gtk_entry_get_text (GTK_ENTRY (widget));
1032 g_free (widget_name);
1033
1034 if (STRING_IS_EMPTY (entry_contents))
1035 return i;
1036 }
1037
1038 return -1;
1039 }
1040
1041 static void
1042 free_attr_list (GList *attr_list)
1043 {
1044 GList *l;
1045
1046 for (l = attr_list; l; l = g_list_next (l)) {
1047 EVCardAttribute *attr = l->data;
1048 e_vcard_attribute_free (attr);
1049 }
1050
1051 g_list_free (attr_list);
1052 }
1053
1054 static void
1055 fill_in_email (EContactEditor *editor)
1056 {
1057 GList *email_attr_list;
1058 GList *l;
1059 gint record_n;
1060
1061 /* Clear */
1062
1063 for (record_n = 1; record_n <= EMAIL_SLOTS; record_n++) {
1064 fill_in_email_record (
1065 editor, record_n, NULL, email_default[record_n - 1]);
1066 }
1067
1068 /* Fill in */
1069
1070 email_attr_list = e_contact_get_attributes (
1071 editor->contact, E_CONTACT_EMAIL);
1072
1073 for (record_n = 1, l = email_attr_list;
1074 l && record_n <= EMAIL_SLOTS; l = g_list_next (l)) {
1075 EVCardAttribute *attr = l->data;
1076 gchar *email_address;
1077 gint slot;
1078
1079 email_address = e_vcard_attribute_get_value (attr);
1080 slot = alloc_ui_slot (
1081 editor, "entry-email",
1082 get_ui_slot (attr), EMAIL_SLOTS);
1083 if (slot < 1)
1084 break;
1085
1086 fill_in_email_record (
1087 editor, slot, email_address,
1088 get_email_location (attr));
1089
1090 record_n++;
1091
1092 g_free (email_address);
1093 }
1094
1095 g_list_free_full (email_attr_list, (GDestroyNotify) e_vcard_attribute_free);
1096 }
1097
1098 static void
1099 extract_email (EContactEditor *editor)
1100 {
1101 GList *attr_list = NULL;
1102 GList *old_attr_list;
1103 GList *l, *l_next;
1104 gint i;
1105
1106 for (i = 1; i <= EMAIL_SLOTS; i++) {
1107 gchar *address;
1108 gint location;
1109
1110 extract_email_record (editor, i, &address, &location);
1111
1112 if (!STRING_IS_EMPTY (address)) {
1113 EVCardAttribute *attr;
1114 attr = e_vcard_attribute_new (
1115 "", e_contact_vcard_attribute (E_CONTACT_EMAIL));
1116
1117 if (location >= 0)
1118 e_vcard_attribute_add_param_with_value (
1119 attr,
1120 e_vcard_attribute_param_new (EVC_TYPE),
1121 email_index_to_location (location));
1122
1123 e_vcard_attribute_add_value (attr, address);
1124 set_ui_slot (attr, i);
1125
1126 attr_list = g_list_append (attr_list, attr);
1127 }
1128
1129 g_free (address);
1130 }
1131
1132 /* Splice in the old attributes, minus the EMAIL_SLOTS first */
1133
1134 old_attr_list = e_contact_get_attributes (editor->contact, E_CONTACT_EMAIL);
1135 for (l = old_attr_list, i = 1; l && i <= EMAIL_SLOTS; l = l_next, i++) {
1136 l_next = g_list_next (l);
1137
1138 e_vcard_attribute_free (l->data);
1139 l = g_list_delete_link (l, l);
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
1140 }
1141
1142 old_attr_list = l;
1143 attr_list = g_list_concat (attr_list, old_attr_list);
1144
1145 e_contact_set_attributes (editor->contact, E_CONTACT_EMAIL, attr_list);
1146
1147 free_attr_list (attr_list);
1148 }
1149
1150 static void
1151 sensitize_email_record (EContactEditor *editor,
1152 gint record,
1153 gboolean enabled)
1154 {
1155 GtkWidget *location_combo_box;
1156 GtkWidget *email_entry;
1157 gchar *widget_name;
1158
1159 widget_name = g_strdup_printf ("combobox-email-%d", record);
1160 location_combo_box = e_builder_get_widget (editor->builder, widget_name);
1161 g_free (widget_name);
1162
1163 widget_name = g_strdup_printf ("entry-email-%d", record);
1164 email_entry = e_builder_get_widget (editor->builder, widget_name);
1165 g_free (widget_name);
1166
1167 gtk_widget_set_sensitive (location_combo_box, enabled);
1168 gtk_editable_set_editable (GTK_EDITABLE (email_entry), enabled);
1169 }
1170
1171 static void
1172 sensitize_email (EContactEditor *editor)
1173 {
1174 gint i;
1175
1176 for (i = 1; i <= EMAIL_SLOTS; i++) {
1177 gboolean enabled = TRUE;
1178
1179 if (!editor->target_editable)
1180 enabled = FALSE;
1181
1182 if (E_CONTACT_FIRST_EMAIL_ID + i - 1 <= E_CONTACT_LAST_EMAIL_ID &&
1183 !is_field_supported (editor, E_CONTACT_FIRST_EMAIL_ID + i - 1))
1184 enabled = FALSE;
1185
1186 sensitize_email_record (editor, i, enabled);
1187 }
1188 }
1189
1190 static void
1191 init_item_sensitiveable_combo_box (GtkComboBox *combo)
1192 {
1193 GtkCellRenderer *cell;
1194 GtkListStore *store;
1195
1196 g_return_if_fail (combo != NULL);
1197 g_return_if_fail (GTK_IS_COMBO_BOX (combo));
1198
1199 store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
1200 gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store));
1201 g_object_unref (store);
1202
1203 gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo));
1204
1205 cell = gtk_cell_renderer_text_new ();
1206 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
1207 gtk_cell_layout_set_attributes (
1208 GTK_CELL_LAYOUT (combo), cell,
1209 "text", 0, "sensitive", 1, NULL);
1210 }
1211
1212 /* EContact can get attributes by field ID only,
1213 * and there is none for TEL, so we need this */
1214 static GList *
1215 get_attributes_named (EVCard *vcard,
1216 const gchar *attr_name)
1217 {
1218 GList *attr_list_in;
1219 GList *attr_list_out = NULL;
1220 GList *l;
1221
1222 attr_list_in = e_vcard_get_attributes (vcard);
1223
1224 for (l = attr_list_in; l; l = g_list_next (l)) {
1225 EVCardAttribute *attr = l->data;
1226 const gchar *name;
1227
1228 name = e_vcard_attribute_get_name (attr);
1229
1230 if (!g_ascii_strcasecmp (attr_name, name)) {
1231 attr_list_out = g_list_append (
1232 attr_list_out,
1233 e_vcard_attribute_copy (attr));
1234 }
1235 }
1236
1237 return attr_list_out;
1238 }
1239
1240 /* EContact can set attributes by field ID only,
1241 * and there is none for TEL, so we need this */
1242 static void
1243 set_attributes_named (EVCard *vcard,
1244 const gchar *attr_name,
1245 GList *attr_list)
1246 {
1247 GList *l;
1248
1249 e_vcard_remove_attributes (vcard, NULL, attr_name);
1250
1251 for (l = attr_list; l; l = g_list_next (l)) {
1252 EVCardAttribute *attr = l->data;
1253
1254 e_vcard_add_attribute (vcard, e_vcard_attribute_copy (attr));
1255 }
1256 }
1257
1258 static void
1259 set_arrow_image (EContactEditor *editor,
1260 const gchar *arrow_widget,
1261 gboolean expanded)
1262 {
1263 GtkWidget *arrow;
1264
1265 arrow = e_builder_get_widget (editor->builder, arrow_widget);
1266 if (expanded)
1267 gtk_arrow_set (
1268 GTK_ARROW (arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
1269 else
1270 gtk_arrow_set (
1271 GTK_ARROW (arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
1272 }
1273
1274 static void
1275 expand_widget_list (EContactEditor *editor,
1276 const gchar **widget_names,
1277 gboolean expanded)
1278 {
1279 gint i;
1280 for (i = 0; widget_names[i]; i++)
1281 gtk_widget_set_visible (
1282 e_builder_get_widget (editor->builder, widget_names[i]),
1283 expanded);
1284 }
1285
1286 static void
1287 expand_web (EContactEditor *editor,
1288 gboolean expanded)
1289 {
1290 const gchar *names[] = {
1291 "label-videourl", "label-fburl",
1292 "entry-videourl", "entry-fburl",
1293 NULL
1294 };
1295 set_arrow_image (editor, "arrow-web-expand", expanded);
1296 expand_widget_list (editor, names, expanded);
1297 }
1298
1299 static void
1300 expand_phone (EContactEditor *editor,
1301 gboolean expanded)
1302 {
1303 const gchar *names[] = {
1304 "entry-phone-3", "combobox-phone-3",
1305 "entry-phone-4", "combobox-phone-4",
1306 "table-phone-extended", NULL
1307 };
1308 set_arrow_image (editor, "arrow-phone-expand", expanded);
1309 expand_widget_list (editor, names, expanded);
1310 }
1311
1312 static void
1313 expand_mail (EContactEditor *editor,
1314 gboolean expanded)
1315 {
1316 GtkTable *table;
1317 GtkWidget *check;
1318 const gchar *names[] = {
1319 "entry-email-2", "combobox-email-2",
1320 "entry-email-3", "combobox-email-3",
1321 "entry-email-4", "combobox-email-4",
1322 NULL
1323 };
1324 set_arrow_image (editor, "arrow-mail-expand", expanded);
1325 expand_widget_list (editor, names, expanded);
1326
1327 /* move 'use html mail' into position */
1328 check = e_builder_get_widget (editor->builder, "checkbutton-htmlmail");
1329 table = GTK_TABLE (e_builder_get_widget (editor->builder, "email-table"));
1330 if (check != NULL && table != NULL) {
1331 GtkWidget *parent;
1332
1333 g_object_ref (check);
1334 parent = gtk_widget_get_parent (check);
1335 gtk_container_remove (GTK_CONTAINER (parent), check);
1336 if (expanded)
1337 gtk_table_attach_defaults (table, check, 0, 4, 2, 3);
1338 else
1339 gtk_table_attach_defaults (table, check, 2, 4, 0, 1);
1340 g_object_unref (check);
1341 }
1342 }
1343
1344 static void
1345 init_email (EContactEditor *editor)
1346 {
1347 gint i;
1348
1349 for (i = 1; i <= EMAIL_SLOTS; i++)
1350 init_email_record_location (editor, i);
1351
1352 expand_mail (editor, !editor->compress_ui);
1353 }
1354
1355 static void
1356 fill_in_phone_record (EContactEditor *editor,
1357 gint record,
1358 const gchar *phone,
1359 gint phone_type)
1360 {
1361 GtkWidget *phone_type_combo_box;
1362 GtkWidget *phone_entry;
1363 gchar *widget_name;
1364
1365 widget_name = g_strdup_printf ("combobox-phone-%d", record);
1366 phone_type_combo_box = e_builder_get_widget (editor->builder, widget_name);
1367 g_free (widget_name);
1368
1369 widget_name = g_strdup_printf ("entry-phone-%d", record);
1370 phone_entry = e_builder_get_widget (editor->builder, widget_name);
1371 g_free (widget_name);
1372
1373 set_combo_box_active (
1374 editor, GTK_COMBO_BOX (phone_type_combo_box),
1375 phone_type >= 0 ? phone_type : phones_default[record - 1]);
1376 set_entry_text (editor, GTK_ENTRY (phone_entry), phone ? phone : "");
1377
1378 if (phone && *phone && record >= 3)
1379 expand_phone (editor, TRUE);
1380 }
1381
1382 static void
1383 extract_phone_record (EContactEditor *editor,
1384 gint record,
1385 gchar **phone,
1386 gint *phone_type)
1387 {
1388 GtkWidget *phone_type_combo_box;
1389 GtkWidget *phone_entry;
1390 gchar *widget_name;
1391
1392 widget_name = g_strdup_printf ("combobox-phone-%d", record);
1393 phone_type_combo_box = e_builder_get_widget (editor->builder, widget_name);
1394 g_free (widget_name);
1395
1396 widget_name = g_strdup_printf ("entry-phone-%d", record);
1397 phone_entry = e_builder_get_widget (editor->builder, widget_name);
1398 g_free (widget_name);
1399
1400 *phone = g_strdup (gtk_entry_get_text (GTK_ENTRY (phone_entry)));
1401 *phone_type = gtk_combo_box_get_active (GTK_COMBO_BOX (phone_type_combo_box));
1402 }
1403
1404 static void
1405 fill_in_phone (EContactEditor *editor)
1406 {
1407 GList *phone_attr_list;
1408 GList *l;
1409 gint record_n;
1410
1411 /* Clear */
1412
1413 for (record_n = 1; record_n <= PHONE_SLOTS; record_n++) {
1414 fill_in_phone_record (editor, record_n, NULL, -1);
1415 }
1416
1417 /* Fill in */
1418
1419 phone_attr_list = get_attributes_named (E_VCARD (editor->contact), "TEL");
1420
1421 for (record_n = 1, l = phone_attr_list;
1422 l && record_n <= PHONE_SLOTS; l = g_list_next (l)) {
1423 EVCardAttribute *attr = l->data;
1424 gchar *phone;
1425 gint slot;
1426
1427 phone = e_vcard_attribute_get_value (attr);
1428 slot = alloc_ui_slot (editor, "entry-phone", get_ui_slot (attr), PHONE_SLOTS);
1429 if (slot < 1)
1430 break;
1431
1432 fill_in_phone_record (
1433 editor, slot, phone, get_phone_type (attr));
1434
1435 record_n++;
1436
1437 g_free (phone);
1438 }
1439 }
1440
1441 static void
1442 extract_phone (EContactEditor *editor)
1443 {
1444 GList *attr_list = NULL;
1445 GList *old_attr_list;
1446 GList *l, *l_next;
1447 gint i;
1448
1449 for (i = 1; i <= PHONE_SLOTS; i++) {
1450 gchar *phone;
1451 gint phone_type;
1452
1453 extract_phone_record (editor, i, &phone, &phone_type);
1454
1455 if (!STRING_IS_EMPTY (phone)) {
1456 EVCardAttribute *attr;
1457
1458 attr = e_vcard_attribute_new ("", "TEL");
1459
1460 if (phone_type >= 0) {
1461 const gchar *type_1;
1462 const gchar *type_2;
1463
1464 phone_index_to_type (phone_type, &type_1, &type_2);
1465
1466 e_vcard_attribute_add_param_with_value (
1467 attr, e_vcard_attribute_param_new (EVC_TYPE), type_1);
1468
1469 if (type_2)
1470 e_vcard_attribute_add_param_with_value (
1471 attr, e_vcard_attribute_param_new (EVC_TYPE), type_2);
1472
1473 }
1474
1475 e_vcard_attribute_add_value (attr, phone);
1476 set_ui_slot (attr, i);
1477
1478 attr_list = g_list_append (attr_list, attr);
1479 }
1480
1481 g_free (phone);
1482 }
1483
1484 /* Splice in the old attributes, minus the PHONE_SLOTS first */
1485
1486 old_attr_list = get_attributes_named (E_VCARD (editor->contact), "TEL");
1487 for (l = old_attr_list, i = 1; l && i <= PHONE_SLOTS; l = l_next, i++) {
1488 l_next = g_list_next (l);
1489
1490 e_vcard_attribute_free (l->data);
1491 l = g_list_delete_link (l, l);
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
1492 }
1493
1494 old_attr_list = l;
1495 attr_list = g_list_concat (attr_list, old_attr_list);
1496
1497 set_attributes_named (E_VCARD (editor->contact), "TEL", attr_list);
1498
1499 free_attr_list (attr_list);
1500 }
1501
1502 static void
1503 init_phone_record_type (EContactEditor *editor,
1504 gint record)
1505 {
1506 GtkWidget *phone_type_combo_box;
1507 GtkWidget *phone_entry;
1508 gchar *widget_name;
1509 gint i;
1510 GtkListStore *store;
1511
1512 widget_name = g_strdup_printf ("entry-phone-%d", record);
1513 phone_entry = e_builder_get_widget (editor->builder, widget_name);
1514 g_free (widget_name);
1515
1516 widget_name = g_strdup_printf ("combobox-phone-%d", record);
1517 phone_type_combo_box = e_builder_get_widget (editor->builder, widget_name);
1518 g_free (widget_name);
1519
1520 init_item_sensitiveable_combo_box (GTK_COMBO_BOX (phone_type_combo_box));
1521
1522 store = GTK_LIST_STORE (
1523 gtk_combo_box_get_model (
1524 GTK_COMBO_BOX (phone_type_combo_box)));
1525
1526 for (i = 0; i < G_N_ELEMENTS (phones); i++) {
1527 GtkTreeIter iter;
1528
1529 gtk_list_store_append (store, &iter);
1530 gtk_list_store_set (
1531 store, &iter,
1532 0, e_contact_pretty_name (phones[i].field_id),
1533 1, TRUE,
1534 -1);
1535 }
1536
1537 g_signal_connect_swapped (
1538 phone_type_combo_box, "changed",
1539 G_CALLBACK (gtk_widget_grab_focus), phone_entry);
1540 g_signal_connect (
1541 phone_type_combo_box, "changed",
1542 G_CALLBACK (object_changed), editor);
1543 g_signal_connect (
1544 phone_entry, "changed",
1545 G_CALLBACK (object_changed), editor);
1546 g_signal_connect_swapped (
1547 phone_entry, "activate",
1548 G_CALLBACK (entry_activated), editor);
1549 }
1550
1551 static void
1552 init_phone (EContactEditor *editor)
1553 {
1554 gint i;
1555
1556 expand_phone (editor, FALSE);
1557
1558 for (i = 1; i <= PHONE_SLOTS; i++)
1559 init_phone_record_type (editor, i);
1560 }
1561
1562 static void
1563 sensitize_phone_types (EContactEditor *editor,
1564 GtkWidget *combo_box)
1565 {
1566 GtkTreeModel *model;
1567 GtkTreeIter iter;
1568 gint i;
1569 gboolean valid;
1570
1571 model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
1572 valid = gtk_tree_model_get_iter_first (model, &iter);
1573
1574 for (i = 0; i < G_N_ELEMENTS (phones); i++) {
1575 if (!valid) {
1576 g_warning (G_STRLOC ": Unexpected end of phone items in combo box");
1577 return;
1578 }
1579
1580 gtk_list_store_set (
1581 GTK_LIST_STORE (model), &iter,
1582 1, is_field_supported (editor, phones[i].field_id),
1583 -1);
1584
1585 valid = gtk_tree_model_iter_next (model, &iter);
1586 }
1587 }
1588
1589 static void
1590 sensitize_phone_record (EContactEditor *editor,
1591 gint record,
1592 gboolean enabled)
1593 {
1594 GtkWidget *phone_type_combo_box;
1595 GtkWidget *phone_entry;
1596 gchar *widget_name;
1597
1598 widget_name = g_strdup_printf ("combobox-phone-%d", record);
1599 phone_type_combo_box = e_builder_get_widget (editor->builder, widget_name);
1600 g_free (widget_name);
1601
1602 widget_name = g_strdup_printf ("entry-phone-%d", record);
1603 phone_entry = e_builder_get_widget (editor->builder, widget_name);
1604 g_free (widget_name);
1605
1606 gtk_widget_set_sensitive (phone_type_combo_box, enabled);
1607 gtk_editable_set_editable (GTK_EDITABLE (phone_entry), enabled);
1608
1609 sensitize_phone_types (editor, phone_type_combo_box);
1610 }
1611
1612 static void
1613 sensitize_phone (EContactEditor *editor)
1614 {
1615 gint i;
1616
1617 for (i = 1; i <= PHONE_SLOTS; i++) {
1618 gboolean enabled = TRUE;
1619
1620 if (!editor->target_editable)
1621 enabled = FALSE;
1622
1623 sensitize_phone_record (editor, i, enabled);
1624 }
1625 }
1626
1627 static void
1628 init_im_record_location (EContactEditor *editor,
1629 gint record)
1630 {
1631
1632 #ifdef ENABLE_IM_LOCATION
1633 GtkWidget *location_combo_box;
1634 GtkListStore *store;
1635 gint i;
1636 gchar *widget_name;
1637
1638 widget_name = g_strdup_printf ("combobox-im-location-%d", record);
1639 location_combo_box = e_builder_get_widget (editor->builder, widget_name);
1640 g_free (widget_name);
1641
1642 init_item_sensitiveable_combo_box (GTK_COMBO_BOX (location_combo_box));
1643
1644 store = GTK_LIST_STORE (
1645 gtk_combo_box_get_model (
1646 GTK_COMBO_BOX (location_combo_box)));
1647
1648 for (i = 0; i < G_N_ELEMENTS (common_location); i++) {
1649 GtkTreeIter iter;
1650
1651 gtk_list_store_append (store, &iter);
1652 gtk_list_store_set (
1653 store, &iter,
1654 0, _(common_location[i].pretty_name),
1655 1, TRUE,
1656 -1);
1657 }
1658
1659 g_signal_connect (
1660 location_combo_box, "changed",
1661 G_CALLBACK (object_changed), editor);
1662 #endif
1663 }
1664
1665 static void
1666 init_im_record_service (EContactEditor *editor,
1667 gint record)
1668 {
1669 GtkWidget *service_combo_box;
1670 GtkListStore *store;
1671 GtkWidget *name_entry;
1672 gchar *widget_name;
1673 gint i;
1674
1675 widget_name = g_strdup_printf ("entry-im-name-%d", record);
1676 name_entry = e_builder_get_widget (editor->builder, widget_name);
1677 g_free (widget_name);
1678
1679 widget_name = g_strdup_printf ("combobox-im-service-%d", record);
1680 service_combo_box = e_builder_get_widget (editor->builder, widget_name);
1681 g_free (widget_name);
1682
1683 if (editor->compress_ui && record > 2) {
1684 gtk_widget_hide (name_entry);
1685 gtk_widget_hide (service_combo_box);
1686 }
1687
1688 init_item_sensitiveable_combo_box (GTK_COMBO_BOX (service_combo_box));
1689
1690 store = GTK_LIST_STORE (
1691 gtk_combo_box_get_model (
1692 GTK_COMBO_BOX (service_combo_box)));
1693
1694 for (i = 0; i < G_N_ELEMENTS (im_service); i++) {
1695 GtkTreeIter iter;
1696
1697 gtk_list_store_append (store, &iter);
1698 gtk_list_store_set (
1699 store, &iter,
1700 0, im_service[i].pretty_name,
1701 1, TRUE,
1702 -1);
1703 }
1704
1705 g_signal_connect_swapped (
1706 service_combo_box, "changed",
1707 G_CALLBACK (gtk_widget_grab_focus), name_entry);
1708 g_signal_connect (
1709 service_combo_box, "changed",
1710 G_CALLBACK (object_changed), editor);
1711 g_signal_connect (
1712 name_entry, "changed",
1713 G_CALLBACK (object_changed), editor);
1714 g_signal_connect_swapped (
1715 name_entry, "activate",
1716 G_CALLBACK (entry_activated), editor);
1717 }
1718
1719 static void
1720 init_im (EContactEditor *editor)
1721 {
1722 gint i;
1723
1724 for (i = 1; i <= IM_SLOTS; i++) {
1725 init_im_record_service (editor, i);
1726 init_im_record_location (editor, i);
1727 }
1728 }
1729
1730 static void
1731 fill_in_im_record (EContactEditor *editor,
1732 gint record,
1733 gint service,
1734 const gchar *name,
1735 gint location)
1736 {
1737 GtkWidget *service_combo_box;
1738 #ifdef ENABLE_IM_LOCATION
1739 GtkWidget *location_combo_box;
1740 #endif
1741 GtkWidget *name_entry;
1742 gchar *widget_name;
1743
1744 widget_name = g_strdup_printf ("combobox-im-service-%d", record);
1745 service_combo_box = e_builder_get_widget (editor->builder, widget_name);
1746 g_free (widget_name);
1747
1748 #ifdef ENABLE_IM_LOCATION
1749 widget_name = g_strdup_printf ("combobox-im-location-%d", record);
1750 location_combo_box = e_builder_get_widget (editor->builder, widget_name);
1751 g_free (widget_name);
1752 #endif
1753
1754 widget_name = g_strdup_printf ("entry-im-name-%d", record);
1755 name_entry = e_builder_get_widget (editor->builder, widget_name);
1756 g_free (widget_name);
1757
1758 #ifdef ENABLE_IM_LOCATION
1759 set_combo_box_active (
1760 editor, GTK_COMBO_BOX (location_combo_box),
1761 location >= 0 ? location : 0);
1762 #endif
1763 set_combo_box_active (
1764 editor, GTK_COMBO_BOX (service_combo_box),
1765 service >= 0 ? service : im_service_default[record - 1]);
1766 set_entry_text (editor, GTK_ENTRY (name_entry), name ? name : "");
1767 }
1768
1769 static void
1770 fill_in_im (EContactEditor *editor)
1771 {
1772 GList *im_attr_list;
1773 GList *l;
1774 gint record_n;
1775 gint i;
1776
1777 /* Clear */
1778
1779 for (record_n = 1; record_n <= IM_SLOTS; record_n++) {
1780 fill_in_im_record (editor, record_n, -1, NULL, -1);
1781 }
1782
1783 /* Fill in */
1784
1785 for (record_n = 1, i = 0; i < G_N_ELEMENTS (im_service); i++) {
1786 im_attr_list = e_contact_get_attributes (editor->contact, im_service[i].field);
1787
1788 for (l = im_attr_list; l && record_n <= IM_SLOTS; l = g_list_next (l)) {
1789 EVCardAttribute *attr = l->data;
1790 gchar *im_name;
1791 gint slot;
1792
1793 im_name = e_vcard_attribute_get_value (attr);
1794 slot = alloc_ui_slot (
1795 editor, "entry-im-name",
1796 get_ui_slot (attr), IM_SLOTS);
1797 if (slot < 1)
1798 break;
1799
1800 fill_in_im_record (
1801 editor, slot, i, im_name,
1802 get_im_location (attr));
1803
1804 record_n++;
1805
1806 g_free (im_name);
1807 }
1808
1809 g_list_free_full (im_attr_list, (GDestroyNotify) e_vcard_attribute_free);
1810 }
1811 }
1812
1813 static void
1814 extract_im_record (EContactEditor *editor,
1815 gint record,
1816 gint *service,
1817 gchar **name,
1818 gint *location)
1819 {
1820 GtkWidget *service_combo_box;
1821 #ifdef ENABLE_IM_LOCATION
1822 GtkWidget *location_combo_box;
1823 #endif
1824 GtkWidget *name_entry;
1825 gchar *widget_name;
1826
1827 widget_name = g_strdup_printf ("combobox-im-service-%d", record);
1828 service_combo_box = e_builder_get_widget (editor->builder, widget_name);
1829 g_free (widget_name);
1830
1831 #ifdef ENABLE_IM_LOCATION
1832 widget_name = g_strdup_printf ("combobox-im-location-%d", record);
1833 location_combo_box = e_builder_get_widget (editor->builder, widget_name);
1834 g_free (widget_name);
1835 #endif
1836
1837 widget_name = g_strdup_printf ("entry-im-name-%d", record);
1838 name_entry = e_builder_get_widget (editor->builder, widget_name);
1839 g_free (widget_name);
1840
1841 *name = g_strdup (gtk_entry_get_text (GTK_ENTRY (name_entry)));
1842 *service = gtk_combo_box_get_active (GTK_COMBO_BOX (service_combo_box));
1843 #ifdef ENABLE_IM_LOCATION
1844 *location = gtk_combo_box_get_active (GTK_COMBO_BOX (location_combo_box));
1845 #else
1846 *location = 1; /* set everything to HOME */
1847 #endif
1848 }
1849
1850 static void
1851 extract_im (EContactEditor *editor)
1852 {
1853 GList **service_attr_list;
1854 gint remaining_slots = IM_SLOTS;
1855 gint i;
1856
1857 service_attr_list = g_new0 (GList *, G_N_ELEMENTS (im_service));
1858
1859 for (i = 1; i <= IM_SLOTS; i++) {
1860 EVCardAttribute *attr;
1861 gchar *name;
1862 gint service;
1863 gint location;
1864
1865 extract_im_record (editor, i, &service, &name, &location);
1866
1867 if (!STRING_IS_EMPTY (name)) {
1868 attr = e_vcard_attribute_new (
1869 "", e_contact_vcard_attribute (
1870 im_service[service].field));
1871
1872 if (location >= 0)
1873 e_vcard_attribute_add_param_with_value (
1874 attr,
1875 e_vcard_attribute_param_new (EVC_TYPE),
1876 im_index_to_location (location));
1877
1878 e_vcard_attribute_add_value (attr, name);
1879 set_ui_slot (attr, i);
1880
1881 service_attr_list[service] = g_list_append (
1882 service_attr_list[service], attr);
1883 }
1884
1885 g_free (name);
1886 }
1887
1888 for (i = 0; i < G_N_ELEMENTS (im_service); i++) {
1889 GList *old_service_attr_list;
1890 gint filled_in_slots;
1891 GList *l, *l_next;
1892 gint j;
1893
1894 /* Splice in the old attributes, minus the filled_in_slots first */
1895
1896 old_service_attr_list = e_contact_get_attributes (
1897 editor->contact, im_service[i].field);
1898 filled_in_slots = MIN (
1899 remaining_slots,
1900 g_list_length (old_service_attr_list));
1901 remaining_slots -= filled_in_slots;
1902
1903 for (l = old_service_attr_list, j = 0;
1904 l && j < filled_in_slots; l = l_next, j++) {
1905 l_next = g_list_next (l);
1906
1907 e_vcard_attribute_free (l->data);
1908 l = g_list_delete_link (l, l);
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
1909 }
1910
1911 old_service_attr_list = l;
1912 service_attr_list[i] = g_list_concat (
1913 service_attr_list[i], old_service_attr_list);
1914
1915 e_contact_set_attributes (
1916 editor->contact,
1917 im_service[i].field,
1918 service_attr_list[i]);
1919
1920 free_attr_list (service_attr_list[i]);
1921 }
1922
1923 g_free (service_attr_list);
1924 }
1925
1926 static void
1927 sensitize_im_types (EContactEditor *editor,
1928 GtkWidget *combo_box)
1929 {
1930 GtkTreeModel *model;
1931 GtkTreeIter iter;
1932 gint i;
1933 gboolean valid;
1934
1935 model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
1936 valid = gtk_tree_model_get_iter_first (model, &iter);
1937
1938 for (i = 0; i < G_N_ELEMENTS (im_service); i++) {
1939 if (!valid) {
1940 g_warning (G_STRLOC ": Unexpected end of im items in combo box");
1941 return;
1942 }
1943
1944 gtk_list_store_set (
1945 GTK_LIST_STORE (model), &iter,
1946 1, is_field_supported (editor, im_service[i].field),
1947 -1);
1948
1949 valid = gtk_tree_model_iter_next (model, &iter);
1950 }
1951 }
1952
1953 static void
1954 sensitize_im_record (EContactEditor *editor,
1955 gint record,
1956 gboolean enabled)
1957 {
1958 GtkWidget *service_combo_box;
1959 #ifdef ENABLE_IM_LOCATION
1960 GtkWidget *location_combo_box;
1961 #endif
1962 GtkWidget *name_entry;
1963 gchar *widget_name;
1964
1965 widget_name = g_strdup_printf ("combobox-im-service-%d", record);
1966 service_combo_box = e_builder_get_widget (editor->builder, widget_name);
1967 g_free (widget_name);
1968
1969 #ifdef ENABLE_IM_LOCATION
1970 widget_name = g_strdup_printf ("combobox-im-location-%d", record);
1971 location_combo_box = e_builder_get_widget (editor->builder, widget_name);
1972 g_free (widget_name);
1973 #endif
1974
1975 widget_name = g_strdup_printf ("entry-im-name-%d", record);
1976 name_entry = e_builder_get_widget (editor->builder, widget_name);
1977 g_free (widget_name);
1978
1979 gtk_widget_set_sensitive (service_combo_box, enabled);
1980 #ifdef ENABLE_IM_LOCATION
1981 gtk_widget_set_sensitive (location_combo_box, enabled);
1982 #endif
1983 gtk_editable_set_editable (GTK_EDITABLE (name_entry), enabled);
1984 sensitize_im_types (editor, service_combo_box);
1985 }
1986
1987 static void
1988 sensitize_im (EContactEditor *editor)
1989 {
1990 gint i;
1991 gboolean enabled;
1992 gboolean no_ims_supported;
1993
1994 enabled = editor->target_editable;
1995 no_ims_supported = TRUE;
1996
1997 for (i = 0; i < G_N_ELEMENTS (im_service); i++)
1998 if (is_field_supported (editor, im_service[i].field)) {
1999 no_ims_supported = FALSE;
2000 break;
2001 }
2002
2003 if (no_ims_supported)
2004 enabled = FALSE;
2005
2006 for (i = 1; i <= IM_SLOTS; i++) {
2007 sensitize_im_record (editor, i, enabled);
2008 }
2009 }
2010
2011 static void
2012 init_personal (EContactEditor *editor)
2013 {
2014 gtk_expander_set_expanded (
2015 GTK_EXPANDER (e_builder_get_widget (
2016 editor->builder, "expander-personal-misc")),
2017 !editor->compress_ui);
2018
2019 expand_web (editor, !editor->compress_ui);
2020 }
2021
2022 static void
2023 init_address_textview (EContactEditor *editor,
2024 gint record)
2025 {
2026 gchar *textview_name;
2027 GtkWidget *textview;
2028 GtkTextBuffer *text_buffer;
2029
2030 textview_name = g_strdup_printf (
2031 "textview-%s-address", address_name[record]);
2032 textview = e_builder_get_widget (editor->builder, textview_name);
2033 g_free (textview_name);
2034
2035 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
2036
2037 g_signal_connect (
2038 text_buffer, "changed",
2039 G_CALLBACK (object_changed), editor);
2040 }
2041
2042 static void
2043 init_address_field (EContactEditor *editor,
2044 gint record,
2045 const gchar *widget_field_name)
2046 {
2047 gchar *entry_name;
2048 GtkWidget *entry;
2049
2050 entry_name = g_strdup_printf (
2051 "entry-%s-%s", address_name[record], widget_field_name);
2052 entry = e_builder_get_widget (editor->builder, entry_name);
2053 g_free (entry_name);
2054
2055 g_signal_connect (
2056 entry, "changed",
2057 G_CALLBACK (object_changed), editor);
2058 g_signal_connect_swapped (
2059 entry, "activate",
2060 G_CALLBACK (entry_activated), editor);
2061 }
2062
2063 static void
2064 init_address_record (EContactEditor *editor,
2065 gint record)
2066 {
2067 init_address_textview (editor, record);
2068 init_address_field (editor, record, "city");
2069 init_address_field (editor, record, "state");
2070 init_address_field (editor, record, "zip");
2071 init_address_field (editor, record, "country");
2072 init_address_field (editor, record, "pobox");
2073 }
2074
2075 static void
2076 init_address (EContactEditor *editor)
2077 {
2078 gint i;
2079
2080 for (i = 0; i < ADDRESS_SLOTS; i++)
2081 init_address_record (editor, i);
2082
2083 gtk_expander_set_expanded (
2084 GTK_EXPANDER (e_builder_get_widget (
2085 editor->builder, "expander-address-other")),
2086 !editor->compress_ui);
2087 }
2088
2089 static void
2090 fill_in_address_textview (EContactEditor *editor,
2091 gint record,
2092 EContactAddress *address)
2093 {
2094 gchar *textview_name;
2095 GtkWidget *textview;
2096 GtkTextBuffer *text_buffer;
2097 GtkTextIter iter_end, iter_start;
2098
2099 textview_name = g_strdup_printf ("textview-%s-address", address_name[record]);
2100 textview = e_builder_get_widget (editor->builder, textview_name);
2101 g_free (textview_name);
2102
2103 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
2104 gtk_text_buffer_set_text (text_buffer, address->street ? address->street : "", -1);
2105
2106 gtk_text_buffer_get_end_iter (text_buffer, &iter_end);
2107 if (address->ext && *address->ext) {
2108 gtk_text_buffer_insert (text_buffer, &iter_end, "\n", -1);
2109 gtk_text_buffer_insert (text_buffer, &iter_end, address->ext, -1);
2110 } else {
2111 gtk_text_buffer_insert (text_buffer, &iter_end, "", -1);
2112 }
2113 gtk_text_buffer_get_iter_at_line (text_buffer, &iter_start, 0);
2114 gtk_text_buffer_place_cursor (text_buffer, &iter_start);
2115 }
2116
2117 static void
2118 fill_in_address_label_textview (EContactEditor *editor,
2119 gint record,
2120 const gchar *label)
2121 {
2122 gchar *textview_name;
2123 GtkWidget *textview;
2124 GtkTextBuffer *text_buffer;
2125
2126 textview_name = g_strdup_printf (
2127 "textview-%s-address", address_name[record]);
2128 textview = e_builder_get_widget (editor->builder, textview_name);
2129 g_free (textview_name);
2130
2131 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
2132 gtk_text_buffer_set_text (text_buffer, label ? label : "", -1);
2133 }
2134
2135 static void
2136 fill_in_address_field (EContactEditor *editor,
2137 gint record,
2138 const gchar *widget_field_name,
2139 const gchar *string)
2140 {
2141 gchar *entry_name;
2142 GtkWidget *entry;
2143
2144 entry_name = g_strdup_printf (
2145 "entry-%s-%s", address_name[record], widget_field_name);
2146 entry = e_builder_get_widget (editor->builder, entry_name);
2147 g_free (entry_name);
2148
2149 set_entry_text (editor, GTK_ENTRY (entry), string);
2150 }
2151
2152 static void
2153 fill_in_address_record (EContactEditor *editor,
2154 gint record)
2155 {
2156 EContactAddress *address;
2157 gchar *address_label;
2158
2159 address = e_contact_get (editor->contact, addresses[record]);
2160 address_label = e_contact_get (editor->contact, address_labels[record]);
2161
2162 if (address &&
2163 (!STRING_IS_EMPTY (address->street) ||
2164 !STRING_IS_EMPTY (address->ext) ||
2165 !STRING_IS_EMPTY (address->locality) ||
2166 !STRING_IS_EMPTY (address->region) ||
2167 !STRING_IS_EMPTY (address->code) ||
2168 !STRING_IS_EMPTY (address->po) ||
2169 !STRING_IS_EMPTY (address->country))) {
2170 fill_in_address_textview (editor, record, address);
2171 fill_in_address_field (editor, record, "city", address->locality);
2172 fill_in_address_field (editor, record, "state", address->region);
2173 fill_in_address_field (editor, record, "zip", address->code);
2174 fill_in_address_field (editor, record, "country", address->country);
2175 fill_in_address_field (editor, record, "pobox", address->po);
2176 } else if (!STRING_IS_EMPTY (address_label)) {
2177 fill_in_address_label_textview (editor, record, address_label);
2178 }
2179
2180 g_free (address_label);
2181 if (address)
2182 g_boxed_free (e_contact_address_get_type (), address);
2183 }
2184
2185 static void
2186 fill_in_address (EContactEditor *editor)
2187 {
2188 gint i;
2189
2190 for (i = 0; i < ADDRESS_SLOTS; i++)
2191 fill_in_address_record (editor, i);
2192 }
2193
2194 static void
2195 extract_address_textview (EContactEditor *editor,
2196 gint record,
2197 EContactAddress *address)
2198 {
2199 gchar *textview_name;
2200 GtkWidget *textview;
2201 GtkTextBuffer *text_buffer;
2202 GtkTextIter iter_1, iter_2;
2203
2204 textview_name = g_strdup_printf ("textview-%s-address", address_name[record]);
2205 textview = e_builder_get_widget (editor->builder, textview_name);
2206 g_free (textview_name);
2207
2208 text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
2209 gtk_text_buffer_get_start_iter (text_buffer, &iter_1);
2210
2211 /* Skip blank lines */
2212 while (gtk_text_iter_get_chars_in_line (&iter_1) < 1 &&
2213 !gtk_text_iter_is_end (&iter_1))
2214 gtk_text_iter_forward_line (&iter_1);
2215
2216 if (gtk_text_iter_is_end (&iter_1))
2217 return;
2218
2219 iter_2 = iter_1;
2220 gtk_text_iter_forward_to_line_end (&iter_2);
2221
2222 /* Extract street (first line of text) */
2223 address->street = gtk_text_iter_get_text (&iter_1, &iter_2);
2224
2225 iter_1 = iter_2;
2226 gtk_text_iter_forward_line (&iter_1);
2227
2228 if (gtk_text_iter_is_end (&iter_1))
2229 return;
2230
2231 gtk_text_iter_forward_to_end (&iter_2);
2232
2233 /* Extract extended address (remaining lines of text) */
2234 address->ext = gtk_text_iter_get_text (&iter_1, &iter_2);
2235 }
2236
2237 static gchar *
2238 extract_address_field (EContactEditor *editor,
2239 gint record,
2240 const gchar *widget_field_name)
2241 {
2242 gchar *entry_name;
2243 GtkWidget *entry;
2244
2245 entry_name = g_strdup_printf (
2246 "entry-%s-%s", address_name[record], widget_field_name);
2247 entry = e_builder_get_widget (editor->builder, entry_name);
2248 g_free (entry_name);
2249
2250 return g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
2251 }
2252
2253 static gchar *
2254 append_to_address_label (gchar *address_label,
2255 const gchar *part,
2256 gboolean newline)
2257 {
2258 gchar *new_address_label;
2259
2260 if (STRING_IS_EMPTY (part))
2261 return address_label;
2262
2263 if (address_label)
2264 new_address_label = g_strjoin (
2265 newline ? "\n" : ", ",
2266 address_label, part, NULL);
2267 else
2268 new_address_label = g_strdup (part);
2269
2270 g_free (address_label);
2271 return new_address_label;
2272 }
2273
2274 static void
2275 set_address_label (EContact *contact,
2276 EContactField field,
2277 EContactAddress *address)
2278 {
2279 gchar *address_label = NULL;
2280 gboolean format_address;
2281 GSettings *settings;
2282
2283 if (!address) {
2284 e_contact_set (contact, field, NULL);
2285 return;
2286 }
2287
2288 settings = g_settings_new ("org.gnome.evolution.addressbook");
2289 format_address = g_settings_get_boolean (settings, "address-formatting");
2290 g_object_unref (settings);
2291
2292 if (format_address) {
2293 address_label = eab_format_address (
2294 contact,
2295 (field == E_CONTACT_ADDRESS_LABEL_WORK) ?
2296 E_CONTACT_ADDRESS_WORK :
2297 E_CONTACT_ADDRESS_HOME);
2298 }
2299
2300 if (!format_address || !address_label) {
2301 address_label = append_to_address_label (
2302 address_label, address->street, TRUE);
2303 address_label = append_to_address_label (
2304 address_label, address->ext, TRUE);
2305 address_label = append_to_address_label (
2306 address_label, address->locality, TRUE);
2307 address_label = append_to_address_label (
2308 address_label, address->region, FALSE);
2309 address_label = append_to_address_label (
2310 address_label, address->code, TRUE);
2311 address_label = append_to_address_label (
2312 address_label, address->po, TRUE);
2313 address_label = append_to_address_label (
2314 address_label, address->country, TRUE);
2315 }
2316
2317 e_contact_set (contact, field, address_label);
2318 g_free (address_label);
2319 }
2320
2321 static void
2322 extract_address_record (EContactEditor *editor,
2323 gint record)
2324 {
2325 EContactAddress *address;
2326
2327 address = g_new0 (EContactAddress, 1);
2328
2329 extract_address_textview (editor, record, address);
2330 address->locality = extract_address_field (editor, record, "city");
2331 address->region = extract_address_field (editor, record, "state");
2332 address->code = extract_address_field (editor, record, "zip");
2333 address->country = extract_address_field (editor, record, "country");
2334 address->po = extract_address_field (editor, record, "pobox");
2335
2336 if (!STRING_IS_EMPTY (address->street) ||
2337 !STRING_IS_EMPTY (address->ext) ||
2338 !STRING_IS_EMPTY (address->locality) ||
2339 !STRING_IS_EMPTY (address->region) ||
2340 !STRING_IS_EMPTY (address->code) ||
2341 !STRING_IS_EMPTY (address->po) ||
2342 !STRING_IS_EMPTY (address->country)) {
2343 e_contact_set (editor->contact, addresses[record], address);
2344 set_address_label (editor->contact, address_labels[record], address);
2345 }
2346 else {
2347 e_contact_set (editor->contact, addresses[record], NULL);
2348 set_address_label (editor->contact, address_labels[record], NULL);
2349 }
2350
2351 g_boxed_free (e_contact_address_get_type (), address);
2352 }
2353
2354 static void
2355 extract_address (EContactEditor *editor)
2356 {
2357 gint i;
2358
2359 for (i = 0; i < ADDRESS_SLOTS; i++)
2360 extract_address_record (editor, i);
2361 }
2362
2363 static void
2364 sensitize_address_textview (EContactEditor *editor,
2365 gint record,
2366 gboolean enabled)
2367 {
2368 gchar *widget_name;
2369 GtkWidget *textview;
2370 GtkWidget *label;
2371
2372 widget_name = g_strdup_printf ("textview-%s-address", address_name[record]);
2373 textview = e_builder_get_widget (editor->builder, widget_name);
2374 g_free (widget_name);
2375
2376 widget_name = g_strdup_printf ("label-%s-address", address_name[record]);
2377 label = e_builder_get_widget (editor->builder, widget_name);
2378 g_free (widget_name);
2379
2380 gtk_text_view_set_editable (GTK_TEXT_VIEW (textview), enabled);
2381 gtk_widget_set_sensitive (label, enabled);
2382 }
2383
2384 static void
2385 sensitize_address_field (EContactEditor *editor,
2386 gint record,
2387 const gchar *widget_field_name,
2388 gboolean enabled)
2389 {
2390 gchar *widget_name;
2391 GtkWidget *entry;
2392 GtkWidget *label;
2393
2394 widget_name = g_strdup_printf (
2395 "entry-%s-%s", address_name[record], widget_field_name);
2396 entry = e_builder_get_widget (editor->builder, widget_name);
2397 g_free (widget_name);
2398
2399 widget_name = g_strdup_printf (
2400 "label-%s-%s", address_name[record], widget_field_name);
2401 label = e_builder_get_widget (editor->builder, widget_name);
2402 g_free (widget_name);
2403
2404 gtk_editable_set_editable (GTK_EDITABLE (entry), enabled);
2405 gtk_widget_set_sensitive (label, enabled);
2406 }
2407
2408 static void
2409 sensitize_address_record (EContactEditor *editor,
2410 gint record,
2411 gboolean enabled)
2412 {
2413 sensitize_address_textview (editor, record, enabled);
2414 sensitize_address_field (editor, record, "city", enabled);
2415 sensitize_address_field (editor, record, "state", enabled);
2416 sensitize_address_field (editor, record, "zip", enabled);
2417 sensitize_address_field (editor, record, "country", enabled);
2418 sensitize_address_field (editor, record, "pobox", enabled);
2419 }
2420
2421 static void
2422 sensitize_address (EContactEditor *editor)
2423 {
2424 gint i;
2425
2426 for (i = 0; i < ADDRESS_SLOTS; i++) {
2427 gboolean enabled = TRUE;
2428
2429 if (!editor->target_editable ||
2430 !(is_field_supported (editor, addresses[i]) ||
2431 is_field_supported (editor, address_labels[i])))
2432 enabled = FALSE;
2433
2434 sensitize_address_record (editor, i, enabled);
2435 }
2436 }
2437
2438 typedef struct {
2439 const gchar *widget_name;
2440 gint field_id; /* EContactField or -1 */
2441 gboolean process_data; /* If we should extract/fill in contents */
2442 gboolean desensitize_for_read_only;
2443 }
2444 FieldMapping;
2445
2446 /* Table of widgets that interact with simple fields. This table is used to:
2447 *
2448 * - Fill in data.
2449 * - Extract data.
2450 * - Set sensitivity based on backend capabilities.
2451 * - Set sensitivity based on book writeability. */
2452
2453 static FieldMapping simple_field_map[] = {
2454 { "entry-homepage", E_CONTACT_HOMEPAGE_URL, TRUE, TRUE },
2455 { "accellabel-homepage", E_CONTACT_HOMEPAGE_URL, FALSE, TRUE },
2456
2457 { "entry-jobtitle", E_CONTACT_TITLE, TRUE, TRUE },
2458 { "label-jobtitle", E_CONTACT_TITLE, FALSE, TRUE },
2459
2460 { "entry-company", E_CONTACT_ORG, TRUE, TRUE },
2461 { "label-company", E_CONTACT_ORG, FALSE, TRUE },
2462
2463 { "entry-department", E_CONTACT_ORG_UNIT, TRUE, TRUE },
2464 { "label-department", E_CONTACT_ORG_UNIT, FALSE, TRUE },
2465
2466 { "entry-profession", E_CONTACT_ROLE, TRUE, TRUE },
2467 { "label-profession", E_CONTACT_ROLE, FALSE, TRUE },
2468
2469 { "entry-manager", E_CONTACT_MANAGER, TRUE, TRUE },
2470 { "label-manager", E_CONTACT_MANAGER, FALSE, TRUE },
2471
2472 { "entry-assistant", E_CONTACT_ASSISTANT, TRUE, TRUE },
2473 { "label-assistant", E_CONTACT_ASSISTANT, FALSE, TRUE },
2474
2475 { "entry-nickname", E_CONTACT_NICKNAME, TRUE, TRUE },
2476 { "label-nickname", E_CONTACT_NICKNAME, FALSE, TRUE },
2477
2478 { "dateedit-birthday", E_CONTACT_BIRTH_DATE, TRUE, TRUE },
2479 { "label-birthday", E_CONTACT_BIRTH_DATE, FALSE, TRUE },
2480
2481 { "dateedit-anniversary", E_CONTACT_ANNIVERSARY, TRUE, TRUE },
2482 { "label-anniversary", E_CONTACT_ANNIVERSARY, FALSE, TRUE },
2483
2484 { "entry-spouse", E_CONTACT_SPOUSE, TRUE, TRUE },
2485 { "label-spouse", E_CONTACT_SPOUSE, FALSE, TRUE },
2486
2487 { "entry-office", E_CONTACT_OFFICE, TRUE, TRUE },
2488 { "label-office", E_CONTACT_OFFICE, FALSE, TRUE },
2489
2490 { "text-comments", E_CONTACT_NOTE, TRUE, TRUE },
2491
2492 { "entry-fullname", E_CONTACT_FULL_NAME, TRUE, TRUE },
2493 { "button-fullname", E_CONTACT_FULL_NAME, FALSE, TRUE },
2494
2495 { "entry-categories", E_CONTACT_CATEGORIES, TRUE, TRUE },
2496 { "button-categories", E_CONTACT_CATEGORIES, FALSE, TRUE },
2497
2498 { "entry-weblog", E_CONTACT_BLOG_URL, TRUE, TRUE },
2499 { "label-weblog", E_CONTACT_BLOG_URL, FALSE, TRUE },
2500
2501 { "entry-caluri", E_CONTACT_CALENDAR_URI, TRUE, TRUE },
2502 { "label-caluri", E_CONTACT_CALENDAR_URI, FALSE, TRUE },
2503
2504 { "entry-fburl", E_CONTACT_FREEBUSY_URL, TRUE, TRUE },
2505 { "label-fburl", E_CONTACT_FREEBUSY_URL, FALSE, TRUE },
2506
2507 { "entry-videourl", E_CONTACT_VIDEO_URL, TRUE, TRUE },
2508 { "label-videourl", E_CONTACT_VIDEO_URL, FALSE, TRUE },
2509
2510 { "checkbutton-htmlmail", E_CONTACT_WANTS_HTML, TRUE, TRUE },
2511
2512 { "image-chooser", E_CONTACT_PHOTO, TRUE, TRUE },
2513 { "button-image", E_CONTACT_PHOTO, FALSE, TRUE },
2514
2515 { "combo-file-as", E_CONTACT_FILE_AS, TRUE, TRUE },
2516 { "accellabel-fileas", E_CONTACT_FILE_AS, FALSE, TRUE },
2517 };
2518
2519 static void
2520 init_simple_field (EContactEditor *editor,
2521 GtkWidget *widget)
2522 {
2523 GObject *changed_object = NULL;
2524
2525 if (GTK_IS_ENTRY (widget)) {
2526 changed_object = G_OBJECT (widget);
2527 g_signal_connect_swapped (
2528 widget, "activate",
2529 G_CALLBACK (entry_activated), editor);
2530
2531 } else if (GTK_IS_COMBO_BOX (widget)) {
2532 changed_object = G_OBJECT (widget);
2533 g_signal_connect_swapped (
2534 gtk_bin_get_child (GTK_BIN (widget)), "activate",
2535 G_CALLBACK (entry_activated), editor);
2536
2537 } else if (GTK_IS_TEXT_VIEW (widget)) {
2538 changed_object = G_OBJECT (
2539 gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget)));
2540
2541 } else if (E_IS_URL_ENTRY (widget)) {
2542 changed_object = G_OBJECT (
2543 e_url_entry_get_entry (E_URL_ENTRY (widget)));
2544 g_signal_connect_swapped (
2545 changed_object, "activate",
2546 G_CALLBACK (entry_activated), editor);
2547
2548 } else if (E_IS_DATE_EDIT (widget)) {
2549 changed_object = G_OBJECT (widget);
2550
2551 } else if (E_IS_IMAGE_CHOOSER (widget)) {
2552 changed_object = G_OBJECT (widget);
2553 g_signal_connect (
2554 widget, "changed",
2555 G_CALLBACK (image_chooser_changed), editor);
2556
2557 } else if (GTK_IS_TOGGLE_BUTTON (widget)) {
2558 g_signal_connect (
2559 widget, "toggled",
2560 G_CALLBACK (object_changed), editor);
2561 }
2562
2563 if (changed_object)
2564 g_signal_connect (
2565 changed_object, "changed",
2566 G_CALLBACK (object_changed), editor);
2567 }
2568
2569 static void
2570 fill_in_simple_field (EContactEditor *editor,
2571 GtkWidget *widget,
2572 gint field_id)
2573 {
2574 EContact *contact;
2575
2576 contact = editor->contact;
2577
2578 g_signal_handlers_block_matched (
2579 widget, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
2580
2581 if (GTK_IS_ENTRY (widget)) {
2582 gchar *text = e_contact_get (contact, field_id);
2583 gtk_entry_set_text (GTK_ENTRY (widget), STRING_MAKE_NON_NULL (text));
2584 g_free (text);
2585
2586 } else if (GTK_IS_COMBO_BOX (widget)) {
2587 gchar *text = e_contact_get (contact, field_id);
2588 gtk_entry_set_text (
2589 GTK_ENTRY (gtk_bin_get_child (GTK_BIN (widget))),
2590 STRING_MAKE_NON_NULL (text));
2591 g_free (text);
2592
2593 } else if (GTK_IS_TEXT_VIEW (widget)) {
2594 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
2595 gchar *text = e_contact_get (contact, field_id);
2596 gtk_text_buffer_set_text (buffer, STRING_MAKE_NON_NULL (text), -1);
2597 g_free (text);
2598
2599 } else if (E_IS_URL_ENTRY (widget)) {
2600 GtkWidget *entry = e_url_entry_get_entry (E_URL_ENTRY (widget));
2601 gchar *text = e_contact_get (contact, field_id);
2602 gtk_entry_set_text (GTK_ENTRY (entry), STRING_MAKE_NON_NULL (text));
2603 g_free (text);
2604
2605 } else if (E_IS_DATE_EDIT (widget)) {
2606 EContactDate *date = e_contact_get (contact, field_id);
2607 if (date)
2608 e_date_edit_set_date (
2609 E_DATE_EDIT (widget),
2610 date->year, date->month, date->day);
2611 else
2612 e_date_edit_set_time (E_DATE_EDIT (widget), -1);
2613
2614 e_contact_date_free (date);
2615
2616 } else if (E_IS_IMAGE_CHOOSER (widget)) {
2617 EContactPhoto *photo = e_contact_get (contact, field_id);
2618 editor->image_set = FALSE;
2619 if (photo && photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
2620 e_image_chooser_set_image_data (
2621 E_IMAGE_CHOOSER (widget),
2622 (gchar *) photo->data.inlined.data,
2623 photo->data.inlined.length);
2624 editor->image_set = TRUE;
2625 } else if (photo && photo->type == E_CONTACT_PHOTO_TYPE_URI) {
2626 gchar *file_name = g_filename_from_uri (photo->data.uri, NULL, NULL);
2627 if (file_name) {
2628 e_image_chooser_set_from_file (
2629 E_IMAGE_CHOOSER (widget),
2630 file_name);
2631 editor->image_set = TRUE;
2632 g_free (file_name);
2633 }
2634 }
2635
2636 if (!editor->image_set) {
2637 gchar *file_name;
2638
2639 file_name = e_icon_factory_get_icon_filename (
2640 "avatar-default", GTK_ICON_SIZE_DIALOG);
2641 e_image_chooser_set_from_file (
2642 E_IMAGE_CHOOSER (widget), file_name);
2643 editor->image_set = FALSE;
2644 g_free (file_name);
2645 }
2646
2647 editor->image_changed = FALSE;
2648 e_contact_photo_free (photo);
2649
2650 } else if (GTK_IS_TOGGLE_BUTTON (widget)) {
2651 gboolean val = e_contact_get (contact, field_id) != NULL;
2652
2653 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), val);
2654
2655 } else {
2656 g_warning (G_STRLOC ": Unhandled widget class in mappings!");
2657 }
2658
2659 g_signal_handlers_unblock_matched (
2660 widget, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
2661 }
2662
2663 static void
2664 extract_simple_field (EContactEditor *editor,
2665 GtkWidget *widget,
2666 gint field_id)
2667 {
2668 EContact *contact;
2669
2670 contact = editor->contact;
2671
2672 if (GTK_IS_ENTRY (widget)) {
2673 const gchar *text = gtk_entry_get_text (GTK_ENTRY (widget));
2674 e_contact_set (contact, field_id, (gchar *) text);
2675
2676 } else if (GTK_IS_COMBO_BOX_TEXT (widget)) {
2677 gchar *text = NULL;
2678
2679 if (gtk_combo_box_get_has_entry (GTK_COMBO_BOX (widget))) {
2680 GtkWidget *entry = gtk_bin_get_child (GTK_BIN (widget));
2681
2682 text = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
2683 }
2684
2685 if (!text)
2686 text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (widget));
2687
2688 e_contact_set (contact, field_id, text);
2689
2690 g_free (text);
2691 } else if (GTK_IS_COMBO_BOX (widget)) {
2692 GtkTreeIter iter;
2693 gchar *text = NULL;
2694
2695 if (gtk_combo_box_get_has_entry (GTK_COMBO_BOX (widget))) {
2696 GtkWidget *entry = gtk_bin_get_child (GTK_BIN (widget));
2697
2698 text = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
2699 }
2700
2701 if (!text && gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter)) {
2702 GtkListStore *store;
2703
2704 store = GTK_LIST_STORE (
2705 gtk_combo_box_get_model (
2706 GTK_COMBO_BOX (widget)));
2707
2708 gtk_tree_model_get (
2709 GTK_TREE_MODEL (store), &iter,
2710 0, &text,
2711 -1);
2712 }
2713
2714 e_contact_set (contact, field_id, text);
2715
2716 g_free (text);
2717
2718 } else if (GTK_IS_TEXT_VIEW (widget)) {
2719 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
2720 GtkTextIter start, end;
2721 gchar *text;
2722
2723 gtk_text_buffer_get_start_iter (buffer, &start);
2724 gtk_text_buffer_get_end_iter (buffer, &end);
2725 text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
2726 e_contact_set (contact, field_id, text);
2727 g_free (text);
2728
2729 } else if (E_IS_URL_ENTRY (widget)) {
2730 GtkWidget *entry = e_url_entry_get_entry (E_URL_ENTRY (widget));
2731 const gchar *text = gtk_entry_get_text (GTK_ENTRY (entry));
2732 e_contact_set (contact, field_id, (gchar *) text);
2733
2734 } else if (E_IS_DATE_EDIT (widget)) {
2735 EContactDate date;
2736 if (e_date_edit_get_date (
2737 E_DATE_EDIT (widget),
2738 (gint *) &date.year,
2739 (gint *) &date.month,
2740 (gint *) &date.day))
2741 e_contact_set (contact, field_id, &date);
2742 else
2743 e_contact_set (contact, field_id, NULL);
2744
2745 } else if (E_IS_IMAGE_CHOOSER (widget)) {
2746 EContactPhoto photo;
2747 photo.type = E_CONTACT_PHOTO_TYPE_INLINED;
2748 photo.data.inlined.mime_type = NULL;
2749 if (editor->image_changed) {
2750 gchar *img_buff = NULL;
2751 if (editor->image_set &&
2752 e_image_chooser_get_image_data (
2753 E_IMAGE_CHOOSER (widget),
2754 &img_buff, &photo.data.inlined.length)) {
2755 GdkPixbuf *pixbuf, *new;
2756 GdkPixbufLoader *loader = gdk_pixbuf_loader_new ();
2757
2758 photo.data.inlined.data = (guchar *) img_buff;
2759 img_buff = NULL;
2760 gdk_pixbuf_loader_write (
2761 loader,
2762 photo.data.inlined.data,
2763 photo.data.inlined.length, NULL);
2764 gdk_pixbuf_loader_close (loader, NULL);
2765
2766 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
2767 if (pixbuf) {
2768 gint width, height, prompt_response;
2769
2770 g_object_ref (pixbuf);
2771
2772 height = gdk_pixbuf_get_height (pixbuf);
2773 width = gdk_pixbuf_get_width (pixbuf);
2774 if ((height > 96 || width > 96)) {
2775
2776 prompt_response =
2777 e_alert_run_dialog_for_args
2778 (GTK_WINDOW (editor->app),
2779 "addressbook:prompt-resize",
2780 NULL);
2781
2782 if (prompt_response == GTK_RESPONSE_YES) {
2783 if (width > height) {
2784 height = height * 96 / width;
2785 width = 96;
2786 } else {
2787 width = width *96 / height;
2788 height = 96;
2789 }
2790
2791 new = e_icon_factory_pixbuf_scale (pixbuf, width, height);
2792 if (new) {
2793 GdkPixbufFormat *format =
2794 gdk_pixbuf_loader_get_format (loader);
2795 gchar *format_name =
2796 gdk_pixbuf_format_get_name (format);
2797 g_free (photo.data.inlined.data);
2798 gdk_pixbuf_save_to_buffer (
2799 new, &img_buff,
2800 &photo.data.inlined.length,
2801 format_name, NULL, NULL);
2802 photo.data.inlined.data = (guchar *) img_buff;
2803 img_buff = NULL;
2804 g_free (format_name);
2805 g_object_unref (new);
2806 }
2807 } else if (prompt_response == GTK_RESPONSE_CANCEL) {
2808 g_object_unref (pixbuf);
2809 g_object_unref (loader);
2810 return;
2811 }
2812 }
2813 g_object_unref (pixbuf);
2814 }
2815 editor->image_changed = FALSE;
2816 g_object_unref (loader);
2817
2818 e_contact_set (contact, field_id, &photo);
2819
2820 g_free (photo.data.inlined.data);
2821
2822 } else {
2823 editor->image_changed = FALSE;
2824 e_contact_set (contact, E_CONTACT_PHOTO, NULL);
2825 }
2826 }
2827
2828 } else if (GTK_IS_TOGGLE_BUTTON (widget)) {
2829 gboolean val;
2830
2831 val = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
2832 e_contact_set (contact, field_id, val ? (gpointer) 1 : NULL);
2833
2834 } else {
2835 g_warning (G_STRLOC ": Unhandled widget class in mappings!");
2836 }
2837 }
2838
2839 static void
2840 sensitize_simple_field (GtkWidget *widget,
2841 gboolean enabled)
2842 {
2843 if (GTK_IS_ENTRY (widget))
2844 gtk_editable_set_editable (GTK_EDITABLE (widget), enabled);
2845 else if (GTK_IS_TEXT_VIEW (widget))
2846 gtk_text_view_set_editable (GTK_TEXT_VIEW (widget), enabled);
2847 else if (E_IS_URL_ENTRY (widget)) {
2848 GtkWidget *entry = e_url_entry_get_entry (E_URL_ENTRY (widget));
2849 gtk_editable_set_editable (GTK_EDITABLE (entry), enabled);
2850 }
2851 else if (E_IS_DATE_EDIT (widget))
2852 e_date_edit_set_editable (E_DATE_EDIT (widget), enabled);
2853 else
2854 gtk_widget_set_sensitive (widget, enabled);
2855 }
2856
2857 static void
2858 init_simple (EContactEditor *editor)
2859 {
2860 GtkWidget *widget;
2861 gint i;
2862
2863 for (i = 0; i < G_N_ELEMENTS (simple_field_map); i++) {
2864 widget = e_builder_get_widget (
2865 editor->builder, simple_field_map[i].widget_name);
2866 if (!widget)
2867 continue;
2868
2869 init_simple_field (editor, widget);
2870 }
2871
2872 /* --- Special cases --- */
2873
2874 /* Update file_as */
2875
2876 widget = e_builder_get_widget (editor->builder, "entry-fullname");
2877 g_signal_connect (
2878 widget, "changed",
2879 G_CALLBACK (name_entry_changed), editor);
2880
2881 widget = e_builder_get_widget (editor->builder, "combo-file-as");
2882 gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (widget), 0);
2883 g_signal_connect (
2884 widget, "changed",
2885 G_CALLBACK (file_as_combo_changed), editor);
2886
2887 widget = e_builder_get_widget (editor->builder, "entry-company");
2888 g_signal_connect (
2889 widget, "changed",
2890 G_CALLBACK (company_entry_changed), editor);
2891 }
2892
2893 static void
2894 fill_in_simple (EContactEditor *editor)
2895 {
2896 EContactName *name;
2897 gchar *filename;
2898 gint i;
2899
2900 for (i = 0; i < G_N_ELEMENTS (simple_field_map); i++) {
2901 GtkWidget *widget;
2902
2903 if (simple_field_map[i].field_id < 0 ||
2904 !simple_field_map[i].process_data)
2905 continue;
2906
2907 widget = e_builder_get_widget (
2908 editor->builder, simple_field_map[i].widget_name);
2909 if (!widget)
2910 continue;
2911
2912 fill_in_simple_field (
2913 editor, widget, simple_field_map[i].field_id);
2914 }
2915
2916 /* --- Special cases --- */
2917
2918 /* Update broken-up name */
2919
2920 g_object_get (editor->contact, "name", &name, NULL);
2921
2922 if (editor->name)
2923 e_contact_name_free (editor->name);
2924
2925 editor->name = name;
2926
2927 /* Update the contact editor title */
2928
2929 filename = (gchar *) e_contact_get (editor->contact, E_CONTACT_FILE_AS);
2930
2931 if (filename) {
2932 gchar *title;
2933 title = g_strdup_printf (_("Contact Editor - %s"), filename);
2934 gtk_window_set_title (GTK_WINDOW (editor->app), title);
2935 g_free (title);
2936 g_free (filename);
2937 } else
2938 gtk_window_set_title (
2939 GTK_WINDOW (editor->app), _("Contact Editor"));
2940
2941 /* Update file_as combo options */
2942
2943 update_file_as_combo (editor);
2944 }
2945
2946 static void
2947 extract_simple (EContactEditor *editor)
2948 {
2949 gint i;
2950
2951 for (i = 0; i < G_N_ELEMENTS (simple_field_map); i++) {
2952 GtkWidget *widget;
2953
2954 if (simple_field_map[i].field_id < 0 ||
2955 !simple_field_map[i].process_data)
2956 continue;
2957
2958 widget = e_builder_get_widget (
2959 editor->builder, simple_field_map[i].widget_name);
2960 if (!widget)
2961 continue;
2962
2963 extract_simple_field (
2964 editor, widget, simple_field_map[i].field_id);
2965 }
2966
2967 /* Special cases */
2968
2969 e_contact_set (editor->contact, E_CONTACT_NAME, editor->name);
2970 }
2971
2972 static void
2973 sensitize_simple (EContactEditor *editor)
2974 {
2975 gint i;
2976
2977 for (i = 0; i < G_N_ELEMENTS (simple_field_map); i++) {
2978 GtkWidget *widget;
2979 gboolean enabled = TRUE;
2980
2981 widget = e_builder_get_widget (
2982 editor->builder, simple_field_map[i].widget_name);
2983 if (!widget)
2984 continue;
2985
2986 if (simple_field_map[i].field_id >= 0 &&
2987 !is_field_supported (editor, simple_field_map[i].field_id))
2988 enabled = FALSE;
2989
2990 if (simple_field_map[i].desensitize_for_read_only &&
2991 !editor->target_editable)
2992 enabled = FALSE;
2993
2994 sensitize_simple_field (widget, enabled);
2995 }
2996 }
2997
2998 static void
2999 fill_in_all (EContactEditor *editor)
3000 {
3001 fill_in_source_field (editor);
3002 fill_in_simple (editor);
3003 fill_in_email (editor);
3004 fill_in_phone (editor);
3005 fill_in_im (editor);
3006 fill_in_address (editor);
3007 }
3008
3009 static void
3010 extract_all (EContactEditor *editor)
3011 {
3012 extract_simple (editor);
3013 extract_email (editor);
3014 extract_phone (editor);
3015 extract_im (editor);
3016 extract_address (editor);
3017 }
3018
3019 static void
3020 sensitize_all (EContactEditor *editor)
3021 {
3022 sensitize_ok (editor);
3023 sensitize_simple (editor);
3024 sensitize_email (editor);
3025 sensitize_phone (editor);
3026 sensitize_im (editor);
3027 sensitize_address (editor);
3028 }
3029
3030 static void
3031 init_all (EContactEditor *editor)
3032 {
3033 const gchar *contents[] = { "viewport1", "viewport2", "viewport3", "text-comments" };
3034 gint ii;
3035 GtkRequisition tab_req, requisition;
3036 GtkWidget *widget;
3037
3038 init_simple (editor);
3039 init_email (editor);
3040 init_phone (editor);
3041 init_im (editor);
3042 init_personal (editor);
3043 init_address (editor);
3044
3045 /* with so many scrolled windows, we need to
3046 * do some manual sizing */
3047 requisition.width = -1;
3048 requisition.height = -1;
3049
3050 for (ii = 0; ii < G_N_ELEMENTS (contents); ii++) {
3051 widget = e_builder_get_widget (editor->builder, contents[ii]);
3052
3053 gtk_widget_get_preferred_size (widget, NULL, &tab_req);
3054
3055 if (tab_req.width > requisition.width)
3056 requisition.width = tab_req.width;
3057 if (tab_req.height > requisition.height)
3058 requisition.height = tab_req.height;
3059 }
3060
3061 if (requisition.width > 0 && requisition.height > 0) {
3062 GtkWindow *window;
3063 GdkScreen *screen;
3064 GdkRectangle monitor_area;
3065 gint x = 0, y = 0, monitor, width, height;
3066
3067 window = GTK_WINDOW (e_builder_get_widget (editor->builder, "contact editor"));
3068
3069 gtk_widget_get_preferred_size (GTK_WIDGET (window), &tab_req, NULL);
3070 width = tab_req.width - 320 + 24;
3071 height = tab_req.height - 240 + 24;
3072
3073 screen = gtk_window_get_screen (window);
3074 gtk_window_get_position (window, &x, &y);
3075
3076 monitor = gdk_screen_get_monitor_at_point (screen, x, y);
3077 if (monitor < 0 || monitor >= gdk_screen_get_n_monitors (screen))
3078 monitor = 0;
3079
3080 gdk_screen_get_monitor_workarea (screen, monitor, &monitor_area);
3081
3082 if (requisition.width > monitor_area.width - width)
3083 requisition.width = monitor_area.width - width;
3084
3085 if (requisition.height > monitor_area.height - height)
3086 requisition.height = monitor_area.height - height;
3087
3088 if (requisition.width > 0 && requisition.height > 0)
3089 gtk_window_set_default_size (window, width + requisition.width, height + requisition.height);
3090 }
3091 }
3092
3093 static void
3094 contact_editor_book_loaded_cb (GObject *source_object,
3095 GAsyncResult *result,
3096 gpointer user_data)
3097 {
3098 ESource *source = E_SOURCE (source_object);
3099 EContactEditor *editor = user_data;
3100 EClient *client = NULL;
3101 GError *error = NULL;
3102
3103 e_client_utils_open_new_finish (source, result, &client, &error);
3104
3105 if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
3106 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
3107 g_warn_if_fail (client == NULL);
3108 g_error_free (error);
3109 goto exit;
3110
3111 } else if (error != NULL) {
3112 GtkWidget *source_combo_box;
3113 GtkWindow *parent;
3114
3115 g_warn_if_fail (client == NULL);
3116
3117 parent = eab_editor_get_window (EAB_EDITOR (editor));
3118 eab_load_error_dialog (GTK_WIDGET (parent), NULL, source, error);
3119
3120 source_combo_box = e_builder_get_widget (
3121 editor->builder, "source-combo-box-source");
3122 e_source_combo_box_set_active (
3123 E_SOURCE_COMBO_BOX (source_combo_box), source);
3124
3125 g_error_free (error);
3126 goto exit;
3127 }
3128
3129 g_return_if_fail (E_IS_CLIENT (client));
3130
3131 /* FIXME Write a private contact_editor_set_target_client(). */
3132 g_object_set (editor, "target_client", client, NULL);
3133
3134 g_object_unref (client);
3135
3136 exit:
3137 g_object_unref (editor);
3138 }
3139
3140 static void
3141 source_changed (ESourceComboBox *source_combo_box,
3142 EContactEditor *editor)
3143 {
3144 ESource *target_source;
3145 ESource *source_source;
3146 ESource *source;
3147
3148 source = e_source_combo_box_ref_active (source_combo_box);
3149 g_return_if_fail (source != NULL);
3150
3151 if (editor->cancellable != NULL) {
3152 g_cancellable_cancel (editor->cancellable);
3153 g_object_unref (editor->cancellable);
3154 editor->cancellable = NULL;
3155 }
3156
3157 target_source = e_client_get_source (E_CLIENT (editor->target_client));
3158 source_source = e_client_get_source (E_CLIENT (editor->source_client));
3159
3160 if (e_source_equal (target_source, source))
3161 goto exit;
3162
3163 if (e_source_equal (source_source, source)) {
3164 g_object_set (
3165 editor, "target_client",
3166 editor->source_client, NULL);
3167 goto exit;
3168 }
3169
3170 editor->cancellable = g_cancellable_new ();
3171
3172 e_client_utils_open_new (
3173 source, E_CLIENT_SOURCE_TYPE_CONTACTS,
3174 FALSE, editor->cancellable,
3175 contact_editor_book_loaded_cb, g_object_ref (editor));
3176
3177 exit:
3178 g_object_unref (source);
3179 }
3180
3181 static void
3182 full_name_response (GtkDialog *dialog,
3183 gint response,
3184 EContactEditor *editor)
3185 {
3186 EContactName *name;
3187 GtkWidget *fname_widget;
3188 gint style = 0;
3189 gboolean editable = FALSE;
3190
3191 g_object_get (dialog, "editable", &editable, NULL);
3192
3193 if (editable && response == GTK_RESPONSE_OK) {
3194 g_object_get (dialog, "name", &name, NULL);
3195
3196 style = file_as_get_style (editor);
3197
3198 fname_widget = e_builder_get_widget (
3199 editor->builder, "entry-fullname");
3200
3201 if (GTK_IS_ENTRY (fname_widget)) {
3202 GtkEntry *entry;
3203 gchar *full_name = e_contact_name_to_string (name);
3204 const gchar *old_full_name;
3205
3206 entry = GTK_ENTRY (fname_widget);
3207 old_full_name = gtk_entry_get_text (entry);
3208
3209 if (strcmp (full_name, old_full_name))
3210 gtk_entry_set_text (entry, full_name);
3211 g_free (full_name);
3212 }
3213
3214 e_contact_name_free (editor->name);
3215 editor->name = name;
3216
3217 file_as_set_style (editor, style);
3218 }
3219
3220 gtk_widget_destroy (GTK_WIDGET (dialog));
3221 editor->fullname_dialog = NULL;
3222 }
3223
3224 static gint
3225 full_name_editor_delete_event_cb (GtkWidget *widget,
3226 GdkEvent *event,
3227 gpointer data)
3228 {
3229 if (GTK_IS_WIDGET (widget))
3230 gtk_widget_destroy (widget);
3231
3232 return TRUE;
3233 }
3234
3235 static void
3236 full_name_clicked (GtkWidget *button,
3237 EContactEditor *editor)
3238 {
3239 GtkDialog *dialog;
3240 gboolean fullname_supported;
3241
3242 if (editor->fullname_dialog) {
3243 gtk_window_present (GTK_WINDOW (editor->fullname_dialog));
3244 return;
3245 }
3246
3247 dialog = GTK_DIALOG (e_contact_editor_fullname_new (editor->name));
3248 fullname_supported = is_field_supported (editor, E_CONTACT_FULL_NAME);
3249
3250 g_object_set (
3251 dialog, "editable",
3252 fullname_supported & editor->target_editable, NULL);
3253
3254 g_signal_connect (
3255 dialog, "response",
3256 G_CALLBACK (full_name_response), editor);
3257
3258 /* Close the fullname dialog if the editor is closed */
3259 g_signal_connect_swapped (
3260 editor, "editor_closed",
3261 G_CALLBACK (full_name_editor_delete_event_cb), dialog);
3262
3263 gtk_widget_show (GTK_WIDGET (dialog));
3264 editor->fullname_dialog = GTK_WIDGET (dialog);
3265 }
3266
3267 static void
3268 categories_response (GtkDialog *dialog,
3269 gint response,
3270 EContactEditor *editor)
3271 {
3272 gchar *categories;
3273 GtkWidget *entry;
3274
3275 entry = e_builder_get_widget (editor->builder, "entry-categories");
3276
3277 if (response == GTK_RESPONSE_OK) {
3278 categories = e_categories_dialog_get_categories (
3279 E_CATEGORIES_DIALOG (dialog));
3280 if (GTK_IS_ENTRY (entry))
3281 gtk_entry_set_text (
3282 GTK_ENTRY (entry), categories);
3283 else
3284 e_contact_set (
3285 editor->contact,
3286 E_CONTACT_CATEGORIES,
3287 categories);
3288 g_free (categories);
3289 }
3290
3291 gtk_widget_destroy (GTK_WIDGET (dialog));
3292 editor->categories_dialog = NULL;
3293 }
3294
3295 static gint
3296 categories_editor_delete_event_cb (GtkWidget *widget,
3297 GdkEvent *event,
3298 gpointer data)
3299 {
3300 if (GTK_IS_WIDGET (widget))
3301 gtk_widget_destroy (widget);
3302
3303 return TRUE;
3304 }
3305
3306 static void
3307 categories_clicked (GtkWidget *button,
3308 EContactEditor *editor)
3309 {
3310 gchar *categories = NULL;
3311 GtkDialog *dialog;
3312 GtkWidget *entry = e_builder_get_widget (editor->builder, "entry-categories");
3313
3314 if (entry && GTK_IS_ENTRY (entry))
3315 categories = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
3316 else if (editor->contact)
3317 categories = e_contact_get (editor->contact, E_CONTACT_CATEGORIES);
3318
3319 if (editor->categories_dialog != NULL) {
3320 gtk_window_present (GTK_WINDOW (editor->categories_dialog));
3321 g_free (categories);
3322 return;
3323 }else if (!(dialog = GTK_DIALOG (e_categories_dialog_new (categories)))) {
3324 e_alert_run_dialog_for_args (
3325 GTK_WINDOW (editor->app),
3326 "addressbook:edit-categories", NULL);
3327 g_free (categories);
3328 return;
3329 }
3330
3331 g_signal_connect (
3332 dialog, "response",
3333 G_CALLBACK (categories_response), editor);
3334
3335 /* Close the category dialog if the editor is closed*/
3336 g_signal_connect_swapped (
3337 editor, "editor_closed",
3338 G_CALLBACK (categories_editor_delete_event_cb), dialog);
3339
3340 gtk_widget_show (GTK_WIDGET (dialog));
3341 g_free (categories);
3342
3343 editor->categories_dialog = GTK_WIDGET (dialog);
3344 }
3345
3346 static void
3347 image_selected (EContactEditor *editor)
3348 {
3349 gchar *file_name;
3350 GtkWidget *image_chooser;
3351
3352 file_name = gtk_file_chooser_get_filename (
3353 GTK_FILE_CHOOSER (editor->file_selector));
3354
3355 if (!file_name)
3356 return;
3357
3358 image_chooser = e_builder_get_widget (editor->builder, "image-chooser");
3359
3360 g_signal_handlers_block_by_func (
3361 image_chooser, image_chooser_changed, editor);
3362 e_image_chooser_set_from_file (
3363 E_IMAGE_CHOOSER (image_chooser), file_name);
3364 g_signal_handlers_unblock_by_func (
3365 image_chooser, image_chooser_changed, editor);
3366
3367 editor->image_set = TRUE;
3368 editor->image_changed = TRUE;
3369 object_changed (G_OBJECT (image_chooser), editor);
3370 }
3371
3372 static void
3373 image_cleared (EContactEditor *editor)
3374 {
3375 GtkWidget *image_chooser;
3376 gchar *file_name;
3377
3378 image_chooser = e_builder_get_widget (
3379 editor->builder, "image-chooser");
3380
3381 file_name = e_icon_factory_get_icon_filename (
3382 "avatar-default", GTK_ICON_SIZE_DIALOG);
3383
3384 g_signal_handlers_block_by_func (
3385 image_chooser, image_chooser_changed, editor);
3386 e_image_chooser_set_from_file (
3387 E_IMAGE_CHOOSER (image_chooser), file_name);
3388 g_signal_handlers_unblock_by_func (
3389 image_chooser, image_chooser_changed, editor);
3390
3391 g_free (file_name);
3392
3393 editor->image_set = FALSE;
3394 editor->image_changed = TRUE;
3395 object_changed (G_OBJECT (image_chooser), editor);
3396 }
3397
3398 static void
3399 file_chooser_response (GtkWidget *widget,
3400 gint response,
3401 EContactEditor *editor)
3402 {
3403 if (response == GTK_RESPONSE_ACCEPT)
3404 image_selected (editor);
3405 else if (response == GTK_RESPONSE_NO)
3406 image_cleared (editor);
3407
3408 gtk_widget_hide (editor->file_selector);
3409 }
3410
3411 static gboolean
3412 file_selector_deleted (GtkWidget *widget)
3413 {
3414 gtk_widget_hide (widget);
3415 return TRUE;
3416 }
3417
3418 static void
3419 update_preview_cb (GtkFileChooser *file_chooser,
3420 gpointer data)
3421 {
3422 GtkWidget *preview;
3423 gchar *filename = NULL;
3424 GdkPixbuf *pixbuf;
3425
3426 gtk_file_chooser_set_preview_widget_active (file_chooser, TRUE);
3427 preview = GTK_WIDGET (data);
3428 filename = gtk_file_chooser_get_preview_filename (file_chooser);
3429 if (filename == NULL)
3430 return;
3431
3432 pixbuf = gdk_pixbuf_new_from_file_at_size (filename, 128, 128, NULL);
3433 if (!pixbuf) {
3434 gchar *alternate_file;
3435 alternate_file = e_icon_factory_get_icon_filename (
3436 "avatar-default", GTK_ICON_SIZE_DIALOG);
3437 if (alternate_file) {
3438 pixbuf = gdk_pixbuf_new_from_file_at_size (
3439 alternate_file, 128, 128, NULL);
3440 g_free (alternate_file);
3441 }
3442 }
3443 g_free (filename);
3444
3445 gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf);
3446 if (pixbuf)
3447 g_object_unref (pixbuf);
3448 }
3449
3450 static void
3451 image_clicked (GtkWidget *button,
3452 EContactEditor *editor)
3453 {
3454 const gchar *title = _("Please select an image for this contact");
3455 const gchar *no_image = _("_No image");
3456 GtkImage *preview;
3457
3458 if (!editor->file_selector) {
3459 editor->file_selector = gtk_file_chooser_dialog_new (
3460 title, GTK_WINDOW (editor->app),
3461 GTK_FILE_CHOOSER_ACTION_OPEN,
3462 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
3463 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
3464 no_image, GTK_RESPONSE_NO,
3465 NULL);
3466 preview = GTK_IMAGE (gtk_image_new ());
3467 gtk_file_chooser_set_preview_widget (
3468 GTK_FILE_CHOOSER (editor->file_selector),
3469 GTK_WIDGET (preview));
3470 g_signal_connect (
3471 editor->file_selector, "update-preview",
3472 G_CALLBACK (update_preview_cb), preview);
3473 gtk_dialog_set_default_response (
3474 GTK_DIALOG (editor->file_selector),
3475 GTK_RESPONSE_ACCEPT);
3476
3477 g_signal_connect (
3478 editor->file_selector, "response",
3479 G_CALLBACK (file_chooser_response), editor);
3480
3481 g_signal_connect_after (
3482 editor->file_selector, "delete-event",
3483 G_CALLBACK (file_selector_deleted),
3484 editor->file_selector);
3485 }
3486
3487 /* Display the dialog */
3488
3489 gtk_window_set_modal (GTK_WINDOW (editor->file_selector), TRUE);
3490 gtk_window_present (GTK_WINDOW (editor->file_selector));
3491 }
3492
3493 typedef struct {
3494 EContactEditor *ce;
3495 gboolean should_close;
3496 gchar *new_id;
3497 } EditorCloseStruct;
3498
3499 static void
3500 contact_removed_cb (GObject *source_object,
3501 GAsyncResult *result,
3502 gpointer user_data)
3503 {
3504 EBookClient *book_client = E_BOOK_CLIENT (source_object);
3505 EditorCloseStruct *ecs = user_data;
3506 EContactEditor *ce = ecs->ce;
3507 gboolean should_close = ecs->should_close;
3508 GError *error = NULL;
3509
3510 e_book_client_remove_contact_finish (book_client, result, &error);
3511
3512 gtk_widget_set_sensitive (ce->app, TRUE);
3513 ce->in_async_call = FALSE;
3514
3515 e_contact_set (ce->contact, E_CONTACT_UID, ecs->new_id);
3516
3517 eab_editor_contact_deleted (EAB_EDITOR (ce), error, ce->contact);
3518
3519 ce->is_new_contact = FALSE;
3520
3521 if (should_close) {
3522 eab_editor_close (EAB_EDITOR (ce));
3523 } else {
3524 ce->changed = FALSE;
3525
3526 g_object_ref (ce->target_client);
3527 g_object_unref (ce->source_client);
3528 ce->source_client = ce->target_client;
3529
3530 sensitize_all (ce);
3531 }
3532
3533 if (error)
3534 g_error_free (error);
3535
3536 g_object_unref (ce);
3537 g_free (ecs->new_id);
3538 g_free (ecs);
3539 }
3540
3541 static void
3542 contact_added_cb (EBookClient *book_client,
3543 const GError *error,
3544 const gchar *id,
3545 gpointer closure)
3546 {
3547 EditorCloseStruct *ecs = closure;
3548 EContactEditor *ce = ecs->ce;
3549 gboolean should_close = ecs->should_close;
3550
3551 if (ce->source_client != ce->target_client && !e_client_is_readonly (E_CLIENT (ce->source_client)) &&
3552 !error && ce->is_new_contact == FALSE) {
3553 ecs->new_id = g_strdup (id);
3554 e_book_client_remove_contact (
3555 ce->source_client, ce->contact, NULL, contact_removed_cb, ecs);
3556 return;
3557 }
3558
3559 gtk_widget_set_sensitive (ce->app, TRUE);
3560 ce->in_async_call = FALSE;
3561
3562 e_contact_set (ce->contact, E_CONTACT_UID, id);
3563
3564 eab_editor_contact_added (EAB_EDITOR (ce), error, ce->contact);
3565
3566 if (!error) {
3567 ce->is_new_contact = FALSE;
3568
3569 if (should_close) {
3570 eab_editor_close (EAB_EDITOR (ce));
3571 } else {
3572 ce->changed = FALSE;
3573 sensitize_all (ce);
3574 }
3575 }
3576
3577 g_object_unref (ce);
3578 g_free (ecs);
3579 }
3580
3581 static void
3582 contact_modified_cb (EBookClient *book_client,
3583 const GError *error,
3584 gpointer closure)
3585 {
3586 EditorCloseStruct *ecs = closure;
3587 EContactEditor *ce = ecs->ce;
3588 gboolean should_close = ecs->should_close;
3589
3590 gtk_widget_set_sensitive (ce->app, TRUE);
3591 ce->in_async_call = FALSE;
3592
3593 eab_editor_contact_modified (EAB_EDITOR (ce), error, ce->contact);
3594
3595 if (!error) {
3596 if (should_close) {
3597 eab_editor_close (EAB_EDITOR (ce));
3598 }
3599 else {
3600 ce->changed = FALSE;
3601 sensitize_all (ce);
3602 }
3603 }
3604
3605 g_object_unref (ce);
3606 g_free (ecs);
3607 }
3608
3609 static void
3610 contact_modified_ready_cb (GObject *source_object,
3611 GAsyncResult *result,
3612 gpointer user_data)
3613 {
3614 EBookClient *book_client = E_BOOK_CLIENT (source_object);
3615 GError *error = NULL;
3616
3617 e_book_client_modify_contact_finish (book_client, result, &error);
3618
3619 contact_modified_cb (book_client, error, user_data);
3620
3621 if (error)
3622 g_error_free (error);
3623 }
3624
3625 /* Emits the signal to request saving a contact */
3626 static void
3627 real_save_contact (EContactEditor *ce,
3628 gboolean should_close)
3629 {
3630 EShell *shell;
3631 EditorCloseStruct *ecs;
3632 ESourceRegistry *registry;
3633
3634 shell = eab_editor_get_shell (EAB_EDITOR (ce));
3635 registry = e_shell_get_registry (shell);
3636
3637 ecs = g_new0 (EditorCloseStruct, 1);
3638 ecs->ce = ce;
3639 g_object_ref (ecs->ce);
3640
3641 ecs->should_close = should_close;
3642
3643 gtk_widget_set_sensitive (ce->app, FALSE);
3644 ce->in_async_call = TRUE;
3645
3646 if (ce->source_client != ce->target_client) {
3647 /* Two-step move; add to target, then remove from source */
3648 eab_merging_book_add_contact (
3649 registry, ce->target_client,
3650 ce->contact, contact_added_cb, ecs);
3651 } else {
3652 if (ce->is_new_contact)
3653 eab_merging_book_add_contact (
3654 registry, ce->target_client,
3655 ce->contact, contact_added_cb, ecs);
3656 else if (ce->check_merge)
3657 eab_merging_book_modify_contact (
3658 registry, ce->target_client,
3659 ce->contact, contact_modified_cb, ecs);
3660 else
3661 e_book_client_modify_contact (
3662 ce->target_client, ce->contact, NULL,
3663 contact_modified_ready_cb, ecs);
3664 }
3665 }
3666
3667 static void
3668 save_contact (EContactEditor *ce,
3669 gboolean should_close)
3670 {
3671 gchar *uid;
3672 const gchar *name_entry_string;
3673 const gchar *file_as_entry_string;
3674 const gchar *company_name_string;
3675 GtkWidget *entry_fullname, *entry_file_as, *company_name;
3676
3677 if (!ce->target_client)
3678 return;
3679
3680 if (ce->target_editable && e_client_is_readonly (E_CLIENT (ce->source_client))) {
3681 if (e_alert_run_dialog_for_args (
3682 GTK_WINDOW (ce->app),
3683 "addressbook:prompt-move",
3684 NULL) == GTK_RESPONSE_NO)
3685 return;
3686 }
3687
3688 entry_fullname = e_builder_get_widget (ce->builder, "entry-fullname");
3689 entry_file_as = gtk_bin_get_child (
3690 GTK_BIN (e_builder_get_widget (ce->builder, "combo-file-as")));
3691 company_name = e_builder_get_widget (ce->builder, "entry-company");
3692 name_entry_string = gtk_entry_get_text (GTK_ENTRY (entry_fullname));
3693 file_as_entry_string = gtk_entry_get_text (GTK_ENTRY (entry_file_as));
3694 company_name_string = gtk_entry_get_text (GTK_ENTRY (company_name));
3695
3696 if (strcmp (company_name_string , "")) {
3697 if (!strcmp (name_entry_string, ""))
3698 gtk_entry_set_text (
3699 GTK_ENTRY (entry_fullname),
3700 company_name_string);
3701 if (!strcmp (file_as_entry_string, ""))
3702 gtk_entry_set_text (
3703 GTK_ENTRY (entry_file_as),
3704 company_name_string);
3705 }
3706
3707 extract_all (ce);
3708
3709 if (!e_contact_editor_is_valid (EAB_EDITOR (ce))) {
3710 uid = e_contact_get (ce->contact, E_CONTACT_UID);
3711 g_object_unref (ce->contact);
3712 ce->contact = e_contact_new ();
3713 if (uid) {
3714 e_contact_set (ce->contact, E_CONTACT_UID, uid);
3715 g_free (uid);
3716 }
3717 return;
3718 }
3719
3720 real_save_contact (ce, should_close);
3721 }
3722
3723 static void
3724 e_contact_editor_save_contact (EABEditor *editor,
3725 gboolean should_close)
3726 {
3727 save_contact (E_CONTACT_EDITOR (editor), should_close);
3728 }
3729
3730 /* Closes the dialog box and emits the appropriate signals */
3731 static void
3732 e_contact_editor_close (EABEditor *editor)
3733 {
3734 EContactEditor *ce = E_CONTACT_EDITOR (editor);
3735
3736 if (ce->app != NULL) {
3737 gtk_widget_destroy (ce->app);
3738 ce->app = NULL;
3739 eab_editor_closed (editor);
3740 }
3741 }
3742
3743 static const EContactField non_string_fields[] = {
3744 E_CONTACT_FULL_NAME,
3745 E_CONTACT_ADDRESS,
3746 E_CONTACT_ADDRESS_HOME,
3747 E_CONTACT_ADDRESS_WORK,
3748 E_CONTACT_ADDRESS_OTHER,
3749 E_CONTACT_EMAIL,
3750 E_CONTACT_IM_AIM,
3751 E_CONTACT_IM_GROUPWISE,
3752 E_CONTACT_IM_JABBER,
3753 E_CONTACT_IM_YAHOO,
3754 E_CONTACT_IM_GADUGADU,
3755 E_CONTACT_IM_MSN,
3756 E_CONTACT_IM_ICQ,
3757 E_CONTACT_IM_SKYPE,
3758 E_CONTACT_IM_TWITTER,
3759 E_CONTACT_PHOTO,
3760 E_CONTACT_LOGO,
3761 E_CONTACT_X509_CERT,
3762 E_CONTACT_CATEGORY_LIST,
3763 E_CONTACT_BIRTH_DATE,
3764 E_CONTACT_ANNIVERSARY
3765
3766 };
3767
3768 static gboolean
3769 is_non_string_field (EContactField id)
3770 {
3771 gint count = sizeof (non_string_fields) / sizeof (EContactField);
3772 gint i;
3773 for (i = 0; i < count; i++)
3774 if (id == non_string_fields[i])
3775 return TRUE;
3776 return FALSE;
3777
3778 }
3779
3780 /* insert checks here (date format, for instance, etc.) */
3781 static gboolean
3782 e_contact_editor_is_valid (EABEditor *editor)
3783 {
3784 EContactEditor *ce = E_CONTACT_EDITOR (editor);
3785 GtkWidget *widget;
3786 gboolean validation_error = FALSE;
3787 GSList *iter;
3788 GString *errmsg = g_string_new (_("The contact data is invalid:\n\n"));
3789 time_t bday, now = time (NULL);
3790
3791 widget = e_builder_get_widget (ce->builder, "dateedit-birthday");
3792 if (!(e_date_edit_date_is_valid (E_DATE_EDIT (widget)))) {
3793 g_string_append_printf (
3794 errmsg, _("'%s' has an invalid format"),
3795 e_contact_pretty_name (E_CONTACT_BIRTH_DATE));
3796 validation_error = TRUE;
3797 }
3798 /* If valid, see if the birthday is a future date */
3799 bday = e_date_edit_get_time (E_DATE_EDIT (widget));
3800 if (bday > now) {
3801 g_string_append_printf (
3802 errmsg, _("'%s' cannot be a future date"),
3803 e_contact_pretty_name (E_CONTACT_BIRTH_DATE));
3804 validation_error = TRUE;
3805 }
3806
3807 widget = e_builder_get_widget (ce->builder, "dateedit-anniversary");
3808 if (!(e_date_edit_date_is_valid (E_DATE_EDIT (widget)))) {
3809 g_string_append_printf (
3810 errmsg, _("%s'%s' has an invalid format"),
3811 validation_error ? ",\n" : "",
3812 e_contact_pretty_name (E_CONTACT_ANNIVERSARY));
3813 validation_error = TRUE;
3814 }
3815
3816 for (iter = ce->required_fields; iter; iter = iter->next) {
3817 const gchar *field_name = iter->data;
3818 EContactField field_id = e_contact_field_id (field_name);
3819
3820 if (is_non_string_field (field_id)) {
3821 if (e_contact_get_const (ce->contact, field_id) == NULL) {
3822 g_string_append_printf (
3823 errmsg, _("%s'%s' is empty"),
3824 validation_error ? ",\n" : "",
3825 e_contact_pretty_name (field_id));
3826 validation_error = TRUE;
3827 break;
3828 }
3829
3830 } else {
3831 const gchar *text;
3832
3833 text = e_contact_get_const (ce->contact, field_id);
3834
3835 if (STRING_IS_EMPTY (text)) {
3836 g_string_append_printf (
3837 errmsg, _("%s'%s' is empty"),
3838 validation_error ? ",\n" : "",
3839 e_contact_pretty_name (field_id));
3840 validation_error = TRUE;
3841 break;
3842 }
3843
3844 }
3845 }
3846
3847 if (validation_error) {
3848 g_string_append (errmsg, ".");
3849 e_alert_run_dialog_for_args (
3850 GTK_WINDOW (ce->app),
3851 "addressbook:generic-error",
3852 _("Invalid contact."), errmsg->str, NULL);
3853 g_string_free (errmsg, TRUE);
3854 return FALSE;
3855 }
3856 else {
3857 g_string_free (errmsg, TRUE);
3858 return TRUE;
3859 }
3860 }
3861
3862 static gboolean
3863 e_contact_editor_is_changed (EABEditor *editor)
3864 {
3865 return E_CONTACT_EDITOR (editor)->changed;
3866 }
3867
3868 static GtkWindow *
3869 e_contact_editor_get_window (EABEditor *editor)
3870 {
3871 return GTK_WINDOW (E_CONTACT_EDITOR (editor)->app);
3872 }
3873
3874 static void
3875 file_save_and_close_cb (GtkWidget *widget,
3876 EContactEditor *ce)
3877 {
3878 save_contact (ce, TRUE);
3879 }
3880
3881 static void
3882 file_cancel_cb (GtkWidget *widget,
3883 EContactEditor *ce)
3884 {
3885 eab_editor_close (EAB_EDITOR (ce));
3886 }
3887
3888 /* Callback used when the dialog box is destroyed */
3889 static gint
3890 app_delete_event_cb (GtkWidget *widget,
3891 GdkEvent *event,
3892 gpointer data)
3893 {
3894 EContactEditor *ce;
3895
3896 ce = E_CONTACT_EDITOR (data);
3897
3898 /* if we're saving, don't allow the dialog to close */
3899 if (ce->in_async_call)
3900 return TRUE;
3901
3902 if (ce->changed) {
3903 switch (eab_prompt_save_dialog (GTK_WINDOW (ce->app))) {
3904 case GTK_RESPONSE_YES:
3905 eab_editor_save_contact (EAB_EDITOR (ce), TRUE);
3906 return TRUE;
3907
3908 case GTK_RESPONSE_NO:
3909 break;
3910
3911 case GTK_RESPONSE_CANCEL:
3912 default:
3913 return TRUE;
3914
3915 }
3916 }
3917
3918 eab_editor_close (EAB_EDITOR (ce));
3919 return TRUE;
3920 }
3921
3922 static void
3923 show_help_cb (GtkWidget *widget,
3924 gpointer data)
3925 {
3926 /* FIXME Pass a proper parent window. */
3927 e_display_help (NULL, "contacts-usage-add-contact");
3928 }
3929
3930 static GList *
3931 add_to_tab_order (GList *list,
3932 GtkBuilder *builder,
3933 const gchar *name)
3934 {
3935 GtkWidget *widget = e_builder_get_widget (builder, name);
3936 return g_list_prepend (list, widget);
3937 }
3938
3939 static void
3940 setup_tab_order (GtkBuilder *builder)
3941 {
3942 GtkWidget *container;
3943 GList *list = NULL;
3944 /*
3945 container = e_builder_get_widget (builder, "table-contact-editor-general");
3946 *
3947 if (container) {
3948 list = add_to_tab_order (list, builder, "entry-fullname");
3949 list = add_to_tab_order (list, builder, "entry-jobtitle");
3950 list = add_to_tab_order (list, builder, "entry-company");
3951 list = add_to_tab_order (list, builder, "combo-file-as");
3952 list = add_to_tab_order (list, builder, "entry-phone-1");
3953 list = add_to_tab_order (list, builder, "entry-phone-2");
3954 list = add_to_tab_order (list, builder, "entry-phone-3");
3955 list = add_to_tab_order (list, builder, "entry-phone-4");
3956 *
3957 list = add_to_tab_order (list, builder, "entry-email1");
3958 list = add_to_tab_order (list, builder, "alignment-htmlmail");
3959 list = add_to_tab_order (list, builder, "entry-web");
3960 list = add_to_tab_order (list, builder, "entry-homepage");
3961 list = add_to_tab_order (list, builder, "button-fulladdr");
3962 list = add_to_tab_order (list, builder, "text-address");
3963 list = g_list_reverse (list);
3964 e_container_change_tab_order (GTK_CONTAINER (container), list);
3965 g_list_free (list);
3966 }
3967 */
3968
3969 container = e_builder_get_widget (builder, "table-home-address");
3970 gtk_container_get_focus_chain (GTK_CONTAINER (container), &list);
3971
3972 list = add_to_tab_order (list, builder, "scrolledwindow-home-address");
3973 list = add_to_tab_order (list, builder, "entry-home-city");
3974 list = add_to_tab_order (list, builder, "entry-home-zip");
3975 list = add_to_tab_order (list, builder, "entry-home-state");
3976 list = add_to_tab_order (list, builder, "entry-home-pobox");
3977 list = add_to_tab_order (list, builder, "entry-home-country");
3978 list = g_list_reverse (list);
3979
3980 gtk_container_set_focus_chain (GTK_CONTAINER (container), list);
3981 g_list_free (list);
3982
3983 container = e_builder_get_widget (builder, "table-work-address");
3984 gtk_container_get_focus_chain (GTK_CONTAINER (container), &list);
3985
3986 list = add_to_tab_order (list, builder, "scrolledwindow-work-address");
3987 list = add_to_tab_order (list, builder, "entry-work-city");
3988 list = add_to_tab_order (list, builder, "entry-work-zip");
3989 list = add_to_tab_order (list, builder, "entry-work-state");
3990 list = add_to_tab_order (list, builder, "entry-work-pobox");
3991 list = add_to_tab_order (list, builder, "entry-work-country");
3992 list = g_list_reverse (list);
3993
3994 gtk_container_set_focus_chain (GTK_CONTAINER (container), list);
3995 g_list_free (list);
3996
3997 container = e_builder_get_widget (builder, "table-other-address");
3998 gtk_container_get_focus_chain (GTK_CONTAINER (container), &list);
3999
4000 list = add_to_tab_order (list, builder, "scrolledwindow-other-address");
4001 list = add_to_tab_order (list, builder, "entry-other-city");
4002 list = add_to_tab_order (list, builder, "entry-other-zip");
4003 list = add_to_tab_order (list, builder, "entry-other-state");
4004 list = add_to_tab_order (list, builder, "entry-other-pobox");
4005 list = add_to_tab_order (list, builder, "entry-other-country");
4006 list = g_list_reverse (list);
4007
4008 gtk_container_set_focus_chain (GTK_CONTAINER (container), list);
4009 g_list_free (list);
4010 }
4011
4012 static void
4013 expand_web_toggle (EContactEditor *ce)
4014 {
4015 GtkWidget *widget;
4016
4017 widget = e_builder_get_widget (ce->builder, "label-videourl");
4018 expand_web (ce, !gtk_widget_get_visible (widget));
4019 }
4020
4021 static void
4022 expand_phone_toggle (EContactEditor *ce)
4023 {
4024 GtkWidget *phone_ext_table;
4025
4026 phone_ext_table = e_builder_get_widget (
4027 ce->builder, "table-phone-extended");
4028 expand_phone (ce, !gtk_widget_get_visible (phone_ext_table));
4029 }
4030
4031 static void
4032 expand_mail_toggle (EContactEditor *ce)
4033 {
4034 GtkWidget *mail;
4035
4036 mail = e_builder_get_widget (ce->builder, "entry-email-4");
4037 expand_mail (ce, !gtk_widget_get_visible (mail));
4038 }
4039
4040 static void
4041 e_contact_editor_init (EContactEditor *e_contact_editor)
4042 {
4043 GtkBuilder *builder;
4044 EShell *shell;
4045 ESourceRegistry *registry;
4046 GtkWidget *container;
4047 GtkWidget *widget, *label;
4048 GtkEntryCompletion *completion;
4049
4050 /* FIXME The shell should be obtained
4051 * through a constructor property. */
4052 shell = e_shell_get_default ();
4053 registry = e_shell_get_registry (shell);
4054
4055 e_contact_editor->name = e_contact_name_new ();
4056
4057 e_contact_editor->contact = NULL;
4058 e_contact_editor->changed = FALSE;
4059 e_contact_editor->check_merge = FALSE;
4060 e_contact_editor->image_set = FALSE;
4061 e_contact_editor->image_changed = FALSE;
4062 e_contact_editor->in_async_call = FALSE;
4063 e_contact_editor->target_editable = TRUE;
4064 e_contact_editor->fullname_dialog = NULL;
4065 e_contact_editor->categories_dialog = NULL;
4066 e_contact_editor->compress_ui = e_shell_get_express_mode (shell);
4067
4068 builder = gtk_builder_new ();
4069 e_load_ui_builder_definition (builder, "contact-editor.ui");
4070
4071 e_contact_editor->builder = builder;
4072
4073 setup_tab_order (builder);
4074
4075 e_contact_editor->app =
4076 e_builder_get_widget (builder, "contact editor");
4077 widget = e_contact_editor->app;
4078
4079 gtk_widget_ensure_style (widget);
4080 gtk_window_set_type_hint (
4081 GTK_WINDOW (widget), GDK_WINDOW_TYPE_HINT_NORMAL);
4082 container = gtk_dialog_get_action_area (GTK_DIALOG (widget));
4083 gtk_container_set_border_width (GTK_CONTAINER (container), 12);
4084 container = gtk_dialog_get_content_area (GTK_DIALOG (widget));
4085 gtk_container_set_border_width (GTK_CONTAINER (container), 0);
4086
4087 init_all (e_contact_editor);
4088
4089 widget = e_builder_get_widget (
4090 e_contact_editor->builder, "button-image");
4091 g_signal_connect (
4092 widget, "clicked",
4093 G_CALLBACK (image_clicked), e_contact_editor);
4094 widget = e_builder_get_widget (
4095 e_contact_editor->builder, "button-fullname");
4096 g_signal_connect (
4097 widget, "clicked",
4098 G_CALLBACK (full_name_clicked), e_contact_editor);
4099 widget = e_builder_get_widget (
4100 e_contact_editor->builder, "button-categories");
4101 g_signal_connect (
4102 widget, "clicked",
4103 G_CALLBACK (categories_clicked), e_contact_editor);
4104 widget = e_builder_get_widget (
4105 e_contact_editor->builder, "source-combo-box-source");
4106 e_source_combo_box_set_registry (
4107 E_SOURCE_COMBO_BOX (widget), registry);
4108 g_signal_connect (
4109 widget, "changed",
4110 G_CALLBACK (source_changed), e_contact_editor);
4111 label = e_builder_get_widget (
4112 e_contact_editor->builder, "where-label");
4113 gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
4114 widget = e_builder_get_widget (
4115 e_contact_editor->builder, "button-ok");
4116 g_signal_connect (
4117 widget, "clicked",
4118 G_CALLBACK (file_save_and_close_cb), e_contact_editor);
4119 widget = e_builder_get_widget (
4120 e_contact_editor->builder, "button-cancel");
4121 g_signal_connect (
4122 widget, "clicked",
4123 G_CALLBACK (file_cancel_cb), e_contact_editor);
4124 widget = e_builder_get_widget (
4125 e_contact_editor->builder, "button-help");
4126 g_signal_connect (
4127 widget, "clicked",
4128 G_CALLBACK (show_help_cb), e_contact_editor);
4129 widget = e_builder_get_widget (
4130 e_contact_editor->builder, "button-web-expand");
4131 g_signal_connect_swapped (
4132 widget, "clicked",
4133 G_CALLBACK (expand_web_toggle), e_contact_editor);
4134 widget = e_builder_get_widget (
4135 e_contact_editor->builder, "button-phone-expand");
4136 g_signal_connect_swapped (
4137 widget, "clicked",
4138 G_CALLBACK (expand_phone_toggle), e_contact_editor);
4139 widget = e_builder_get_widget (
4140 e_contact_editor->builder, "button-mail-expand");
4141 g_signal_connect_swapped (
4142 widget, "clicked",
4143 G_CALLBACK (expand_mail_toggle), e_contact_editor);
4144
4145 widget = e_builder_get_widget (
4146 e_contact_editor->builder, "entry-fullname");
4147 if (widget)
4148 gtk_widget_grab_focus (widget);
4149
4150 widget = e_builder_get_widget (
4151 e_contact_editor->builder, "entry-categories");
4152 completion = e_category_completion_new ();
4153 gtk_entry_set_completion (GTK_ENTRY (widget), completion);
4154 g_object_unref (completion);
4155
4156 /* Connect to the deletion of the dialog */
4157
4158 g_signal_connect (
4159 e_contact_editor->app, "delete_event",
4160 G_CALLBACK (app_delete_event_cb), e_contact_editor);
4161
4162 /* set the icon */
4163 gtk_window_set_icon_name (
4164 GTK_WINDOW (e_contact_editor->app), "contact-editor");
4165
4166 /* show window */
4167 gtk_widget_show (e_contact_editor->app);
4168
4169 gtk_application_add_window (
4170 GTK_APPLICATION (shell),
4171 GTK_WINDOW (e_contact_editor->app));
4172 }
4173
4174 static void
4175 e_contact_editor_dispose (GObject *object)
4176 {
4177 EContactEditor *e_contact_editor = E_CONTACT_EDITOR (object);
4178
4179 if (e_contact_editor->file_selector != NULL) {
4180 gtk_widget_destroy (e_contact_editor->file_selector);
4181 e_contact_editor->file_selector = NULL;
4182 }
4183
4184 if (e_contact_editor->writable_fields) {
4185 e_client_util_free_string_slist (
4186 e_contact_editor->writable_fields);
4187 e_contact_editor->writable_fields = NULL;
4188 }
4189
4190 if (e_contact_editor->required_fields) {
4191 e_client_util_free_string_slist (
4192 e_contact_editor->required_fields);
4193 e_contact_editor->required_fields = NULL;
4194 }
4195
4196 if (e_contact_editor->contact) {
4197 g_object_unref (e_contact_editor->contact);
4198 e_contact_editor->contact = NULL;
4199 }
4200
4201 if (e_contact_editor->source_client) {
4202 g_object_unref (e_contact_editor->source_client);
4203 e_contact_editor->source_client = NULL;
4204 }
4205
4206 if (e_contact_editor->target_client) {
4207 g_signal_handler_disconnect (
4208 e_contact_editor->target_client,
4209 e_contact_editor->target_editable_id);
4210 g_object_unref (e_contact_editor->target_client);
4211 e_contact_editor->target_client = NULL;
4212 }
4213
4214 if (e_contact_editor->name) {
4215 e_contact_name_free (e_contact_editor->name);
4216 e_contact_editor->name = NULL;
4217 }
4218
4219 if (e_contact_editor->builder) {
4220 g_object_unref (e_contact_editor->builder);
4221 e_contact_editor->builder = NULL;
4222 }
4223
4224 if (e_contact_editor->cancellable != NULL) {
4225 g_object_unref (e_contact_editor->cancellable);
4226 e_contact_editor->cancellable = NULL;
4227 }
4228
4229 /* Chain up to parent's dispose() method. */
4230 G_OBJECT_CLASS (parent_class)->dispose (object);
4231 }
4232
4233 static void
4234 supported_fields_cb (GObject *source_object,
4235 GAsyncResult *result,
4236 gpointer user_data)
4237 {
4238 EBookClient *book_client = E_BOOK_CLIENT (source_object);
4239 EContactEditor *ce = user_data;
4240 gchar *prop_value = NULL;
4241 GSList *fields;
4242 gboolean success;
4243 GError *error = NULL;
4244
4245 success = e_client_get_backend_property_finish (
4246 E_CLIENT (book_client), result, &prop_value, &error);
4247
4248 if (!success)
4249 prop_value = NULL;
4250
4251 if (error != NULL) {
4252 g_warning (
4253 "%s: Failed to get supported fields: %s",
4254 G_STRFUNC, error->message);
4255 g_error_free (error);
4256 }
4257
4258 if (!g_slist_find (eab_editor_get_all_editors (), ce)) {
4259 g_warning (
4260 "supported_fields_cb called for book that's still "
4261 "around, but contact editor that's been destroyed.");
4262 g_free (prop_value);
4263 return;
4264 }
4265
4266 fields = e_client_util_parse_comma_strings (prop_value);
4267
4268 g_object_set (ce, "writable_fields", fields, NULL);
4269
4270 e_client_util_free_string_slist (fields);
4271 g_free (prop_value);
4272
4273 eab_editor_show (EAB_EDITOR (ce));
4274
4275 sensitize_all (ce);
4276 }
4277
4278 static void
4279 required_fields_cb (GObject *source_object,
4280 GAsyncResult *result,
4281 gpointer user_data)
4282 {
4283 EBookClient *book_client = E_BOOK_CLIENT (source_object);
4284 EContactEditor *ce = user_data;
4285 gchar *prop_value = NULL;
4286 GSList *fields;
4287 gboolean success;
4288 GError *error = NULL;
4289
4290 success = e_client_get_backend_property_finish (
4291 E_CLIENT (book_client), result, &prop_value, &error);
4292
4293 if (!success)
4294 prop_value = NULL;
4295
4296 if (error != NULL) {
4297 g_warning (
4298 "%s: Failed to get supported fields: %s",
4299 G_STRFUNC, error->message);
4300 g_error_free (error);
4301 }
4302
4303 if (!g_slist_find (eab_editor_get_all_editors (), ce)) {
4304 g_warning (
4305 "supported_fields_cb called for book that's still "
4306 "around, but contact editor that's been destroyed.");
4307 g_free (prop_value);
4308 return;
4309 }
4310
4311 fields = e_client_util_parse_comma_strings (prop_value);
4312
4313 g_object_set (ce, "required_fields", fields, NULL);
4314
4315 e_client_util_free_string_slist (fields);
4316 g_free (prop_value);
4317 }
4318
4319 EABEditor *
4320 e_contact_editor_new (EShell *shell,
4321 EBookClient *book_client,
4322 EContact *contact,
4323 gboolean is_new_contact,
4324 gboolean editable)
4325 {
4326 EABEditor *editor;
4327
4328 g_return_val_if_fail (E_IS_SHELL (shell), NULL);
4329 g_return_val_if_fail (E_IS_BOOK_CLIENT (book_client), NULL);
4330 g_return_val_if_fail (E_IS_CONTACT (contact), NULL);
4331
4332 editor = g_object_new (E_TYPE_CONTACT_EDITOR, "shell", shell, NULL);
4333
4334 g_object_set (
4335 editor,
4336 "source_client", book_client,
4337 "contact", contact,
4338 "is_new_contact", is_new_contact,
4339 "editable", editable,
4340 NULL);
4341
4342 return editor;
4343 }
4344
4345 static void
4346 notify_readonly_cb (EBookClient *book_client,
4347 GParamSpec *pspec,
4348 EContactEditor *ce)
4349 {
4350 EClient *client;
4351 gint new_target_editable;
4352 gboolean changed = FALSE;
4353
4354 client = E_CLIENT (ce->target_client);
4355 new_target_editable = !e_client_is_readonly (client);
4356
4357 if (ce->target_editable != new_target_editable)
4358 changed = TRUE;
4359
4360 ce->target_editable = new_target_editable;
4361
4362 if (changed)
4363 sensitize_all (ce);
4364 }
4365
4366 static void
4367 e_contact_editor_set_property (GObject *object,
4368 guint property_id,
4369 const GValue *value,
4370 GParamSpec *pspec)
4371 {
4372 EContactEditor *editor;
4373
4374 editor = E_CONTACT_EDITOR (object);
4375
4376 switch (property_id) {
4377 case PROP_SOURCE_CLIENT: {
4378 gboolean writable;
4379 gboolean changed = FALSE;
4380 EBookClient *source_client;
4381
4382 source_client = E_BOOK_CLIENT (g_value_get_object (value));
4383
4384 if (source_client == editor->source_client)
4385 break;
4386
4387 if (editor->source_client)
4388 g_object_unref (editor->source_client);
4389
4390 editor->source_client = source_client;
4391 g_object_ref (editor->source_client);
4392
4393 if (!editor->target_client) {
4394 editor->target_client = editor->source_client;
4395 g_object_ref (editor->target_client);
4396
4397 editor->target_editable_id = g_signal_connect (
4398 editor->target_client, "notify::readonly",
4399 G_CALLBACK (notify_readonly_cb), editor);
4400
4401 e_client_get_backend_property (
4402 E_CLIENT (editor->target_client),
4403 BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS,
4404 NULL, supported_fields_cb, editor);
4405
4406 e_client_get_backend_property (
4407 E_CLIENT (editor->target_client),
4408 BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS,
4409 NULL, required_fields_cb, editor);
4410 }
4411
4412 writable = !e_client_is_readonly (E_CLIENT (editor->target_client));
4413 if (writable != editor->target_editable) {
4414 editor->target_editable = writable;
4415 changed = TRUE;
4416 }
4417
4418 if (changed)
4419 sensitize_all (editor);
4420
4421 break;
4422 }
4423
4424 case PROP_TARGET_CLIENT: {
4425 gboolean writable;
4426 gboolean changed = FALSE;
4427 EBookClient *target_client;
4428
4429 target_client = E_BOOK_CLIENT (g_value_get_object (value));
4430
4431 if (target_client == editor->target_client)
4432 break;
4433
4434 if (editor->target_client) {
4435 g_signal_handler_disconnect (
4436 editor->target_client,
4437 editor->target_editable_id);
4438 g_object_unref (editor->target_client);
4439 }
4440
4441 editor->target_client = target_client;
4442 g_object_ref (editor->target_client);
4443
4444 editor->target_editable_id = g_signal_connect (
4445 editor->target_client, "notify::readonly",
4446 G_CALLBACK (notify_readonly_cb), editor);
4447
4448 e_client_get_backend_property (
4449 E_CLIENT (editor->target_client),
4450 BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS,
4451 NULL, supported_fields_cb, editor);
4452
4453 e_client_get_backend_property (
4454 E_CLIENT (editor->target_client),
4455 BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS,
4456 NULL, required_fields_cb, editor);
4457
4458 if (!editor->is_new_contact)
4459 editor->changed = TRUE;
4460
4461 writable = !e_client_is_readonly (E_CLIENT (editor->target_client));
4462
4463 if (writable != editor->target_editable) {
4464 editor->target_editable = writable;
4465 changed = TRUE;
4466 }
4467
4468 if (changed)
4469 sensitize_all (editor);
4470
4471 break;
4472 }
4473
4474 case PROP_CONTACT:
4475 if (editor->contact)
4476 g_object_unref (editor->contact);
4477 editor->contact = e_contact_duplicate (
4478 E_CONTACT (g_value_get_object (value)));
4479 fill_in_all (editor);
4480 editor->changed = FALSE;
4481 break;
4482
4483 case PROP_IS_NEW_CONTACT:
4484 editor->is_new_contact = g_value_get_boolean (value);
4485 break;
4486
4487 case PROP_EDITABLE: {
4488 gboolean new_value = g_value_get_boolean (value);
4489 gboolean changed = (editor->target_editable != new_value);
4490
4491 editor->target_editable = new_value;
4492
4493 if (changed)
4494 sensitize_all (editor);
4495 break;
4496 }
4497
4498 case PROP_CHANGED: {
4499 gboolean new_value = g_value_get_boolean (value);
4500 gboolean changed = (editor->changed != new_value);
4501
4502 editor->changed = new_value;
4503
4504 if (changed)
4505 sensitize_ok (editor);
4506 break;
4507 }
4508 case PROP_WRITABLE_FIELDS:
4509 if (editor->writable_fields)
4510 e_client_util_free_string_slist (editor->writable_fields);
4511
4512 editor->writable_fields =
4513 e_client_util_copy_string_slist (
4514 NULL, g_value_get_pointer (value));
4515
4516 sensitize_all (editor);
4517 break;
4518 case PROP_REQUIRED_FIELDS:
4519 if (editor->required_fields)
4520 e_client_util_free_string_slist (editor->required_fields);
4521 editor->required_fields =
4522 e_client_util_copy_string_slist (
4523 NULL, g_value_get_pointer (value));
4524 break;
4525 default:
4526 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
4527 break;
4528 }
4529 }
4530
4531 static void
4532 e_contact_editor_get_property (GObject *object,
4533 guint property_id,
4534 GValue *value,
4535 GParamSpec *pspec)
4536 {
4537 EContactEditor *e_contact_editor;
4538
4539 e_contact_editor = E_CONTACT_EDITOR (object);
4540
4541 switch (property_id) {
4542 case PROP_SOURCE_CLIENT:
4543 g_value_set_object (value, e_contact_editor->source_client);
4544 break;
4545
4546 case PROP_TARGET_CLIENT:
4547 g_value_set_object (value, e_contact_editor->target_client);
4548 break;
4549
4550 case PROP_CONTACT:
4551 extract_all (e_contact_editor);
4552 g_value_set_object (value, e_contact_editor->contact);
4553 break;
4554
4555 case PROP_IS_NEW_CONTACT:
4556 g_value_set_boolean (
4557 value, e_contact_editor->is_new_contact);
4558 break;
4559
4560 case PROP_EDITABLE:
4561 g_value_set_boolean (
4562 value, e_contact_editor->target_editable);
4563 break;
4564
4565 case PROP_CHANGED:
4566 g_value_set_boolean (
4567 value, e_contact_editor->changed);
4568 break;
4569
4570 case PROP_WRITABLE_FIELDS:
4571 g_value_set_pointer (value, e_contact_editor->writable_fields);
4572 break;
4573 case PROP_REQUIRED_FIELDS:
4574 g_value_set_pointer (value, e_contact_editor->required_fields);
4575 break;
4576 default:
4577 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
4578 break;
4579 }
4580 }
4581
4582 /**
4583 * e_contact_editor_raise:
4584 * @config: The %EContactEditor object.
4585 *
4586 * Raises the dialog associated with this %EContactEditor object.
4587 */
4588 static void
4589 e_contact_editor_raise (EABEditor *editor)
4590 {
4591 EContactEditor *ce = E_CONTACT_EDITOR (editor);
4592 GdkWindow *window;
4593
4594 window = gtk_widget_get_window (ce->app);
4595
4596 if (window != NULL)
4597 gdk_window_raise (window);
4598 }
4599
4600 /**
4601 * e_contact_editor_show:
4602 * @ce: The %EContactEditor object.
4603 *
4604 * Shows the dialog associated with this %EContactEditor object.
4605 */
4606 static void
4607 e_contact_editor_show (EABEditor *editor)
4608 {
4609 EContactEditor *ce = E_CONTACT_EDITOR (editor);
4610 gtk_widget_show (ce->app);
4611 }