9b158ed587be8db4ef66dc2e4e40b38a02cfe3dc
[claws.git] / src / editaddress.c
1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2016 Hiroyuki Yamamoto and the Claws Mail team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #  include "config.h"
21 #include "claws-features.h"
22 #endif
23
24 #include "defs.h"
25
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <gtk/gtk.h>
30
31 #include "alertpanel.h"
32 #include "stock_pixmap.h"
33 #include "mgutils.h"
34 #include "addressbook.h"
35 #include "addressitem.h"
36 #include "addritem.h"
37 #include "addrbook.h"
38 #include "manage_window.h"
39 #include "gtkutils.h"
40 #include "filesel.h"
41 #include "codeconv.h"
42 #include "editaddress.h"
43 #include "editaddress_other_attributes_ldap.h"
44 #include "prefs_common.h"
45 #include "menu.h"
46 #include "combobox.h"
47
48 /* transient data */
49 static struct _PersonEdit_dlg personeditdlg;
50 static AddressBookFile *current_abf = NULL;
51 static ItemPerson *current_person = NULL;
52 static ItemFolder *current_parent_folder = NULL;
53 static EditAddressPostUpdateCallback edit_person_close_post_update_cb = NULL;
54
55 typedef enum {
56         EMAIL_COL_EMAIL,
57         EMAIL_COL_ALIAS,
58         EMAIL_COL_REMARKS,
59         EMAIL_COL_PTR
60 } PersonEditEMailColumnPos;
61
62 #define EDITPERSON_WIDTH      520
63 #define EDITPERSON_HEIGHT     320
64
65 #ifndef GENERIC_UMPC
66 # define EMAIL_N_COLS          4
67 # define EMAIL_COL_WIDTH_EMAIL 180
68 # define EMAIL_COL_WIDTH_ALIAS 80
69 #else
70 # define EMAIL_N_COLS          2
71 # define EMAIL_COL_WIDTH_EMAIL 130
72 # define EMAIL_COL_WIDTH_ALIAS 130
73 #endif
74
75 #ifndef GENERIC_UMPC
76 # define ATTRIB_COL_WIDTH_NAME  240
77 # define ATTRIB_COL_WIDTH_VALUE 0
78 #else
79 # define ATTRIB_COL_WIDTH_NAME  120
80 # define ATTRIB_COL_WIDTH_VALUE 120
81 #endif
82
83 #define PAGE_BASIC             0
84 #define PAGE_EMAIL             1
85 #define PAGE_ATTRIBUTES        2
86
87 static gboolean addressbook_edit_person_close( gboolean cancelled );
88 static GList *edit_person_build_email_list();
89 static GList *edit_person_build_attrib_list();
90
91 static gchar* edit_person_get_common_name_from_widgets(void)
92 {
93         gchar *cn = NULL; /* cn must be freed by caller */
94
95 #ifndef GENERIC_UMPC
96         {
97                 cn = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_name), 0, -1 );
98                 if ( cn == NULL || *cn == '\0' ) {
99                         gchar *first = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_first), 0, -1 );
100                         gchar *last = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_last), 0, -1 );
101                         cn = g_strdup_printf("%s%s%s", first?first:"", (first && last && *first && *last)?" ":"", last?last:"");
102                         g_free(first);
103                         g_free(last);
104                 }
105                 if ( cn == NULL || *cn == '\0' ) {
106                         g_free(cn);
107                         cn = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_nick), 0, -1 );;
108                 }
109         }
110 #else
111         {
112                 gchar *first = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_first), 0, -1 );
113                 gchar *last = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_last), 0, -1 );
114                 cn = g_strdup_printf("%s%s%s", first?first:"", (first && last && *first && *last)?" ":"", last?last:"");
115                 g_free(first);
116                 g_free(last);
117         }
118 #endif
119         if ( cn != NULL )
120                 g_strstrip(cn);
121         return cn;
122 }
123
124 static void edit_person_status_show( gchar *msg ) {
125         if( personeditdlg.statusbar != NULL ) {
126                 gtk_statusbar_pop( GTK_STATUSBAR(personeditdlg.statusbar), personeditdlg.status_cid );
127                 if( msg ) {
128                         gtk_statusbar_push( GTK_STATUSBAR(personeditdlg.statusbar), personeditdlg.status_cid, msg );
129                 }
130         }
131 }
132
133 static void edit_person_cancel(GtkWidget *widget, gboolean *cancelled) {
134         *cancelled = TRUE;
135         if (prefs_common.addressbook_use_editaddress_dialog)
136                 gtk_main_quit();
137         else
138                 addressbook_edit_person_close( *cancelled );
139 }
140
141 static void edit_person_ok(GtkWidget *widget, gboolean *cancelled) {
142         GList *listEMail = edit_person_build_email_list();
143         GList *listAttrib = edit_person_build_attrib_list();
144         gchar *cn = edit_person_get_common_name_from_widgets();
145
146         if( (cn == NULL || *cn == '\0') && listEMail == NULL && listAttrib == NULL ) {
147                 gint val;
148
149                 val = alertpanel( _("Add New Person"),
150 #ifndef GENERIC_UMPC
151                                 _("Adding a new person requires at least one of the\n"
152                                   "following values to be set:\n"
153                                   " - Display Name\n"
154                                   " - First Name\n"
155                                   " - Last Name\n"
156                                   " - Nickname\n"
157                                   " - any email address\n"
158                                   " - any additional attribute\n\n"
159                                   "Click OK to keep editing this contact.\n"
160                                   "Click Cancel to close without saving."),
161 #else
162                                 _("Adding a new person requires at least one of the\n"
163                                   "following values to be set:\n"
164                                   " - First Name\n"
165                                   " - Last Name\n"
166                                   " - any email address\n"
167                                   " - any additional attribute\n\n"
168                                   "Click OK to keep editing this contact.\n"
169                                   "Click Cancel to close without saving."),
170 #endif
171                                 GTK_STOCK_CANCEL, GTK_STOCK_OK, NULL, ALERTFOCUS_SECOND );
172                 if( val == G_ALERTDEFAULT ) {
173                         edit_person_cancel(widget, cancelled);
174                 }
175                 g_free( cn );
176                 return;
177         }
178         g_free( cn );
179
180         *cancelled = FALSE;
181         if (prefs_common.addressbook_use_editaddress_dialog)
182                 gtk_main_quit();
183         else
184                 addressbook_edit_person_close( *cancelled );
185 }
186
187 /* Updated up/down buttons sensitivity, depending on list
188  * cursor position */
189 static void edit_person_email_update_buttons()
190 {
191         GtkTreeModel *model;
192         GtkTreeIter iter, otheriter;
193         GtkTreePath *path;
194         gboolean has_prev;
195         ItemEMail *email;
196
197         email = gtkut_tree_view_get_selected_pointer(
198                         GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
199                         &model, NULL, &iter);
200
201         if (email) {
202                 if (!personeditdlg.read_only) {
203                         otheriter = iter;
204                         path = gtk_tree_model_get_path(model, &otheriter);
205                         has_prev = gtk_tree_path_prev(path);
206                         if (has_prev) {
207                                 gtk_tree_model_get_iter(model, &otheriter, path);
208                         }
209                         gtk_widget_set_sensitive(personeditdlg.email_up, has_prev);
210
211                         otheriter = iter;
212                         gtk_widget_set_sensitive(personeditdlg.email_down,
213                                         gtk_tree_model_iter_next(model, &otheriter));
214                 }
215         } else {
216                 gtk_widget_set_sensitive(personeditdlg.email_del, FALSE);
217                 gtk_widget_set_sensitive(personeditdlg.email_up, FALSE);
218                 gtk_widget_set_sensitive(personeditdlg.email_down, FALSE);
219         }
220 }
221
222 static void edit_person_email_cursor_changed(GtkTreeView *view,
223                 gpointer user_data)
224 {
225         GtkTreeModel *model;
226         GtkTreeIter iter;
227         ItemEMail *email;
228
229         email = gtkut_tree_view_get_selected_pointer(
230                         GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
231                         &model, NULL, &iter);
232
233         if (email != NULL) {
234                 if (email->address != NULL)
235                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_email),
236                                         email->address);
237                 if (ADDRITEM_NAME(email) != NULL)
238                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_alias),
239                                         ADDRITEM_NAME(email));
240                 if (email->remarks != NULL)
241                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_remarks),
242                                         email->remarks);
243         }
244
245         edit_person_email_update_buttons();
246 }
247
248
249 static gint edit_person_delete_event(GtkWidget *widget, GdkEventAny *event, gboolean *cancelled) {
250         *cancelled = TRUE;
251         if (prefs_common.addressbook_use_editaddress_dialog)
252                 gtk_main_quit();
253         else
254                 addressbook_edit_person_close( *cancelled );
255         return TRUE;
256 }
257
258 static gboolean edit_person_key_pressed(GtkWidget *widget, GdkEventKey *event, gboolean *cancelled) {
259         if (prefs_common.addressbook_use_editaddress_dialog) {
260         if (event && event->keyval == GDK_KEY_Escape) {
261                 *cancelled = TRUE;
262                 gtk_main_quit();
263         }
264         }
265         return FALSE;
266 }
267
268 static gchar *_title_new_ = NULL;
269 static gchar *_title_edit_ = NULL;
270
271 static void edit_person_set_widgets_title( gchar *text )
272 {
273         gchar *label = NULL;
274
275         cm_return_if_fail( text != NULL );
276
277         gtk_label_set_text(GTK_LABEL(personeditdlg.title), "");
278         label = g_markup_printf_escaped("<b>%s</b>", text);
279         gtk_label_set_markup(GTK_LABEL(personeditdlg.title), label);
280         g_free(label);
281 }
282
283 static void edit_person_set_window_title( gint pageNum ) {
284         gchar *sTitle;
285
286         if( _title_new_ == NULL ) {
287                 _title_new_ = g_strdup( _("Add New Person") );
288                 _title_edit_ = g_strdup( _("Edit Person Details") );
289         }
290
291         if( pageNum == PAGE_BASIC ) {
292                 if( personeditdlg.editNew ) {
293                         if (prefs_common.addressbook_use_editaddress_dialog)
294                                 gtk_window_set_title( GTK_WINDOW(personeditdlg.container), _title_new_ );
295                         else
296                                 edit_person_set_widgets_title( _title_new_ );
297                 }
298                 else {
299                         if (prefs_common.addressbook_use_editaddress_dialog)
300                                 gtk_window_set_title( GTK_WINDOW(personeditdlg.container), _title_edit_ );
301                         else
302                                 edit_person_set_widgets_title( _title_edit_ );
303                 }
304         }
305         else {
306                 if( personeditdlg.entry_name == NULL ) {
307                         sTitle = g_strdup( _title_edit_ );
308                 }
309                 else {
310                         gchar *name;
311                         name = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_name), 0, -1 );
312                         g_strstrip(name);
313                         if ( *name != '\0' )
314                                 sTitle = g_strdup_printf( "%s - %s", _title_edit_, name );
315                         else
316                                 sTitle = g_strdup( _title_edit_ );
317                         g_free( name );
318                 }
319                 if (prefs_common.addressbook_use_editaddress_dialog)
320                         gtk_window_set_title( GTK_WINDOW(personeditdlg.container), sTitle );
321                 else
322                         edit_person_set_widgets_title( sTitle );
323                 g_free( sTitle );
324         }
325 }
326
327 static void edit_person_email_clear( gpointer data ) {
328         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_email), "" );
329         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_alias), "" );
330         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_remarks), "" );
331 }
332
333 static void edit_person_attrib_clear( gpointer data ) {
334         if (!personeditdlg.ldap) {
335                 gtk_entry_set_text( GTK_ENTRY(gtk_bin_get_child(GTK_BIN((personeditdlg.entry_atname)))), "" );
336                 gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atvalue), "" );
337         }
338 }
339
340 static void edit_person_switch_page( GtkNotebook *notebook, gpointer page,
341                                         gint pageNum, gpointer user_data)
342 {
343         edit_person_set_window_title( pageNum );
344         edit_person_status_show( "" );
345 }
346
347 /*
348 * Load clist with a copy of person's email addresses.
349 */
350 static void edit_person_load_email( ItemPerson *person ) {
351         GList *node = person->listEMail;
352         GtkTreeModel *model = gtk_tree_view_get_model(
353                         GTK_TREE_VIEW(personeditdlg.view_email));
354         GtkTreeIter iter;
355
356         while( node ) {
357                 ItemEMail *emorig = ( ItemEMail * ) node->data;
358                 ItemEMail *email = addritem_copyfull_item_email( emorig );
359
360                 gtk_list_store_append(GTK_LIST_STORE(model), &iter);
361                 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
362                                 EMAIL_COL_EMAIL, email->address,
363 #ifndef GENERIC_UMPC
364                                 EMAIL_COL_ALIAS, email->obj.name,
365                                 EMAIL_COL_REMARKS, email->remarks,
366 #endif
367                                 EMAIL_COL_PTR, email,
368                                 -1);
369
370                 node = g_list_next( node );
371         }
372 }
373
374 static void edit_person_email_move_up( gpointer data ) {
375         GtkTreeModel *model;
376         GtkTreeIter iter, otheriter;
377         GtkTreePath *path;
378         ItemEMail *email;
379         gboolean has_prev;
380
381         edit_person_email_clear( NULL );
382         edit_person_status_show( NULL );
383
384         email = gtkut_tree_view_get_selected_pointer(
385                         GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
386                         &model, NULL, &iter);
387
388         if( email ) {
389                 otheriter = iter;
390                 /* GTK+2 does not have gtk_tree_model_iter_previous(), so
391                  * we have to go through GtkTreePath */
392                 path = gtk_tree_model_get_path(model, &otheriter);
393                 has_prev = gtk_tree_path_prev(path);
394                 if (has_prev) {
395                         gtk_tree_model_get_iter(model, &otheriter, path);
396                         gtk_list_store_move_before(GTK_LIST_STORE(model), &iter, &otheriter);
397                 }
398                 gtk_tree_path_free(path);
399         }
400
401         edit_person_email_update_buttons();
402 }
403
404 static void edit_person_email_move_down( gpointer data ) {
405         GtkTreeModel *model;
406         GtkTreeIter iter, otheriter;
407         ItemEMail *email;
408
409         edit_person_email_clear( NULL );
410         edit_person_status_show( NULL );
411
412         email = gtkut_tree_view_get_selected_pointer(
413                         GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
414                         &model, NULL, &iter);
415
416         if( email ) {
417                 otheriter = iter;
418                 if (gtk_tree_model_iter_next(model, &otheriter)) {
419                         gtk_list_store_move_after(GTK_LIST_STORE(model), &iter, &otheriter);
420                 }
421         }
422
423         edit_person_email_update_buttons();
424 }
425
426 static void edit_person_attrib_cursor_changed(GtkTreeView *view,
427                 gpointer user_data)
428 {
429         UserAttribute *attrib = gtkut_tree_view_get_selected_pointer(
430                         view, ATTRIB_COL_PTR, NULL, NULL, NULL);
431
432         if( attrib && !personeditdlg.read_only && !personeditdlg.ldap ) {
433                 gtk_entry_set_text( GTK_ENTRY(gtk_bin_get_child(GTK_BIN((personeditdlg.entry_atname))) ), attrib->name );
434                 gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atvalue), attrib->value );
435                 gtk_widget_set_sensitive(personeditdlg.attrib_del, TRUE);
436         } else {
437                 gtk_widget_set_sensitive(personeditdlg.attrib_del, FALSE);
438         }
439         edit_person_status_show( NULL );
440 }
441
442
443 static void edit_person_email_delete( gpointer data ) {
444         GtkTreeModel *model;
445         GtkTreeIter iter;
446         GtkTreeSelection *sel;
447         ItemEMail *email;
448         gboolean has_row = FALSE;
449         gint n;
450
451         edit_person_email_clear( NULL );
452         edit_person_status_show( NULL );
453
454         email = gtkut_tree_view_get_selected_pointer(
455                         GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
456                         &model, &sel, &iter);
457
458         if( email ) {
459                 /* Remove list entry and set iter to next row, if any */
460                 has_row = gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
461                 addritem_free_item_email( email );
462                 email = NULL;
463         }
464
465         /* Position hilite bar */
466         if (!has_row) {
467                 /* The removed row was the last in the list, so iter is not
468                  * valid. Find out if there is at least one row remaining
469                  * in the list, and select the last one if so. */
470                 n = gtk_tree_model_iter_n_children(model, NULL);
471                 if (n > 0 && gtk_tree_model_iter_nth_child(model, &iter, NULL, n-1)) {
472                         /* It exists */
473                         has_row = TRUE;
474                 }
475         }
476
477         if (has_row)
478                 gtk_tree_selection_select_iter(sel, &iter);
479
480         edit_person_email_cursor_changed(
481                         GTK_TREE_VIEW(personeditdlg.view_email), NULL);
482 }
483
484 static ItemEMail *edit_person_email_edit( gboolean *error, ItemEMail *email ) {
485         ItemEMail *retVal = NULL;
486         gchar *sEmail, *sAlias, *sRemarks, *sEmail_;
487
488         *error = TRUE;
489         sEmail_ = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_email), 0, -1 );
490         sAlias = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_alias), 0, -1 );
491         sRemarks = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_remarks), 0, -1 );
492         sEmail = mgu_email_check_empty( sEmail_ );
493         g_free( sEmail_ );
494
495         if( sEmail ) {
496                 if( email == NULL ) {
497                         email = addritem_create_item_email();
498                 }
499                 addritem_email_set_address( email, sEmail );
500                 addritem_email_set_alias( email, sAlias );
501                 addritem_email_set_remarks( email, sRemarks );
502                 retVal = email;
503                 *error = FALSE;
504         }
505         else {
506                 edit_person_status_show( _( "An Email address must be supplied." ) );
507         }
508
509         g_free( sEmail );
510         g_free( sAlias );
511         g_free( sRemarks );
512
513         return retVal;
514 }
515
516 static void edit_person_email_modify( gpointer data ) {
517         GtkTreeModel *model;
518         GtkTreeIter iter;
519         gboolean errFlg = FALSE;
520         ItemEMail *email;
521
522         email = gtkut_tree_view_get_selected_pointer(
523                         GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
524                         &model, NULL, &iter);
525
526         if( email ) {
527                 edit_person_email_edit( &errFlg, email );
528                 if( ! errFlg ) {
529                         gtk_list_store_set(GTK_LIST_STORE(model), &iter,
530                                         EMAIL_COL_EMAIL, email->address,
531 #ifndef GENERIC_UMPC
532                                         EMAIL_COL_ALIAS, email->obj.name,
533                                         EMAIL_COL_REMARKS, email->remarks,
534 #endif
535                                         -1);
536                         edit_person_email_clear( NULL );
537                 }
538         }
539 }
540
541 static void edit_person_email_add( gpointer data ) {
542         GtkTreeModel *model;
543         GtkTreeIter iter, otheriter;
544         GtkTreeSelection *sel;
545         gboolean errFlg = FALSE;
546         ItemEMail *email = NULL;
547
548         email = gtkut_tree_view_get_selected_pointer(
549                         GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
550                         &model, &sel, &otheriter);
551
552         email = edit_person_email_edit( &errFlg, NULL );
553         if( ! errFlg ) {
554                 gtk_list_store_insert_after(GTK_LIST_STORE(model), &iter, &otheriter);
555                 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
556                                         EMAIL_COL_EMAIL, email->address,
557 #ifndef GENERIC_UMPC
558                                         EMAIL_COL_ALIAS, email->obj.name,
559                                         EMAIL_COL_REMARKS, email->remarks,
560 #endif
561                                         EMAIL_COL_PTR, email,
562                                         -1);
563                 gtk_tree_selection_select_iter(sel, &iter);
564                 edit_person_email_update_buttons();
565
566                 edit_person_email_clear( NULL );
567         }
568 }
569
570 static gboolean list_find_email(const gchar *addr)
571 {
572         GtkWidget *view = personeditdlg.view_email;
573         GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
574         GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
575         GtkTreeIter iter;
576         ItemEMail *email;
577
578         if (!gtk_tree_model_get_iter_first(model, &iter))
579                 return FALSE;
580
581         do {
582                 gtk_tree_model_get(model, &iter, EMAIL_COL_PTR, &email, -1);
583                 if (!g_ascii_strcasecmp(email->address, addr)) {
584                         gtk_tree_selection_select_iter(sel, &iter);
585                         return TRUE;
586                 }
587         } while (gtk_tree_model_iter_next(model, &iter));
588
589         return FALSE;
590 }
591
592 static gboolean list_find_attribute(const gchar *attr)
593 {
594         GtkWidget *view = personeditdlg.view_attrib;
595         GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
596         GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
597         GtkTreeIter iter;
598         UserAttribute *attrib;
599
600         if (!gtk_tree_model_get_iter_first(model, &iter))
601                 return FALSE;
602
603         do {
604                 gtk_tree_model_get(model, &iter, ATTRIB_COL_PTR, &attrib, -1);
605                 if (!g_ascii_strcasecmp(attrib->name, attr)) {
606                         gtk_tree_selection_select_iter(sel, &iter);
607                         return TRUE;
608                 }
609         } while (gtk_tree_model_iter_next(model, &iter));
610
611         return FALSE;
612 }
613
614 /*
615 * Load list with a copy of person's email addresses.
616 */
617 static void edit_person_load_attrib( ItemPerson *person ) {
618         GList *node = person->listAttrib;
619         GtkWidget *view = personeditdlg.view_attrib;
620         GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
621         GtkTreeIter iter;
622
623         while( node ) {
624                 UserAttribute *atorig = ( UserAttribute * ) node->data;
625                 UserAttribute *attrib = addritem_copy_attribute( atorig );
626
627                 debug_print("name: %s value: %s\n", attrib->name, attrib->value);
628
629                 gtk_list_store_append(GTK_LIST_STORE(model), &iter);
630                 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
631                                 ATTRIB_COL_NAME, attrib->name,
632                                 ATTRIB_COL_VALUE, attrib->value,
633                                 ATTRIB_COL_PTR, attrib,
634                                 -1);
635
636                 node = g_list_next( node );
637         }
638 }
639
640 static void edit_person_attrib_delete(gpointer data) {
641         UserAttribute *attrib;
642         GtkTreeModel *model;
643         GtkTreeSelection *sel;
644         GtkTreeIter iter;
645         gboolean has_row = FALSE;
646         gint n;
647
648         edit_person_attrib_clear(NULL);
649         edit_person_status_show(NULL);
650
651         attrib = gtkut_tree_view_get_selected_pointer(
652                         GTK_TREE_VIEW(personeditdlg.view_attrib), ATTRIB_COL_PTR,
653                         &model, &sel, &iter);
654
655         if (attrib) {
656                 /* Remove list entry, and set iter to next row, if any */
657                 has_row = gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
658                 addritem_free_attribute(attrib);
659                 attrib = NULL;
660         }
661
662         /* Position hilite bar */
663         if (!has_row) {
664                 /* The removed row was the last in the list, so iter is not
665                  * valid. Find out if there is at least one row remaining
666                  * in the list, and select the last one if so. */
667                 n = gtk_tree_model_iter_n_children(model, NULL);
668                 if (n > 0 && gtk_tree_model_iter_nth_child(model, &iter, NULL, n-1)) {
669                         /* It exists. */
670                         has_row = TRUE;
671                 }
672         }
673
674         if (has_row)
675                 gtk_tree_selection_select_iter(sel, &iter);
676
677         edit_person_attrib_cursor_changed(
678                         GTK_TREE_VIEW(personeditdlg.view_attrib), NULL);
679 }
680
681 static UserAttribute *edit_person_attrib_edit( gboolean *error, UserAttribute *attrib ) {
682         UserAttribute *retVal = NULL;
683         gchar *sName, *sValue, *sName_, *sValue_;
684
685         *error = TRUE;
686         sName_ = gtk_editable_get_chars( GTK_EDITABLE(gtk_bin_get_child(GTK_BIN((personeditdlg.entry_atname)))), 0, -1 );
687         sValue_ = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_atvalue), 0, -1 );
688         sName = mgu_email_check_empty( sName_ );
689         sValue = mgu_email_check_empty( sValue_ );
690         g_free( sName_ );
691         g_free( sValue_ );
692
693         if( sName && sValue ) {
694                 if( attrib == NULL ) {
695                         attrib = addritem_create_attribute();
696                 }
697                 addritem_attrib_set_name( attrib, sName );
698                 addritem_attrib_set_value( attrib, sValue );
699                 retVal = attrib;
700                 *error = FALSE;
701         }
702         else {
703                 edit_person_status_show( _( "A Name and Value must be supplied." ) );
704         }
705
706         g_free( sName );
707         g_free( sValue );
708
709         return retVal;
710 }
711
712 static void edit_person_attrib_modify(gpointer data) {
713         gboolean errFlg = FALSE;
714         GtkTreeModel *model;
715         GtkTreeIter iter;
716         UserAttribute *attrib;
717
718         attrib = gtkut_tree_view_get_selected_pointer(
719                         GTK_TREE_VIEW(personeditdlg.view_attrib), ATTRIB_COL_PTR,
720                         &model, NULL, &iter);
721         if (attrib) {
722                 edit_person_attrib_edit(&errFlg, attrib);
723                 if (!errFlg) {
724                         gtk_list_store_set(GTK_LIST_STORE(model), &iter,
725                                         ATTRIB_COL_NAME, attrib->name,
726                                         ATTRIB_COL_VALUE, attrib->value,
727                                         -1);
728                         edit_person_attrib_clear(NULL);
729                 }
730         }
731 }
732
733 static void edit_person_attrib_add(gpointer data) {
734         gboolean errFlg = FALSE;
735         GtkTreeModel *model;
736         GtkTreeSelection *sel;
737         GtkTreeIter iter, iter2;
738         UserAttribute *attrib;
739
740         attrib = gtkut_tree_view_get_selected_pointer(
741                         GTK_TREE_VIEW(personeditdlg.view_attrib), ATTRIB_COL_PTR,
742                         &model, &sel, &iter);
743
744         if (attrib == NULL) {
745                 /* No row selected, or list empty, add it as first row. */
746                 gtk_list_store_insert(GTK_LIST_STORE(model), &iter, 0);
747         } else {
748                 /* Add it after the currently selected row. */
749                 gtk_list_store_insert_after(GTK_LIST_STORE(model), &iter2,
750                                 &iter);
751                 iter = iter2;
752         }
753
754         /* Grab the values from text entries, and fill out the new row. */
755         attrib = edit_person_attrib_edit(&errFlg, NULL);
756         if (!errFlg) {
757                 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
758                                 ATTRIB_COL_NAME, attrib->name,
759                                 ATTRIB_COL_VALUE, attrib->value,
760                                 ATTRIB_COL_PTR, attrib,
761                                 -1);
762                 gtk_tree_selection_select_iter(sel, &iter);
763                 edit_person_attrib_clear(NULL);
764         }
765 }
766
767 /*!
768  *\brief        Save Gtk object size to prefs dataset
769  */
770 static void edit_person_size_allocate_cb(GtkWidget *widget,
771                                          GtkAllocation *allocation)
772 {
773         cm_return_if_fail(allocation != NULL);
774
775         prefs_common.addressbookeditpersonwin_width = allocation->width;
776         prefs_common.addressbookeditpersonwin_height = allocation->height;
777 }
778
779 /* build edit person widgets, return a pointer to the main container of the widgetset (a vbox) */
780 static GtkWidget* addressbook_edit_person_widgets_create( GtkWidget* container, gboolean *cancelled )
781 {
782         GtkWidget *vbox;
783         GtkWidget *vnbox;
784         GtkWidget *notebook;
785         GtkWidget *hbbox;
786         GtkWidget *ok_btn;
787         GtkWidget *cancel_btn;
788
789         vbox = gtk_vbox_new(FALSE, 4);
790          gtk_container_set_border_width(GTK_CONTAINER(vbox), BORDER_WIDTH); 
791         gtk_widget_show(vbox);
792         gtk_container_add(GTK_CONTAINER(container), vbox);
793
794         vnbox = gtk_vbox_new(FALSE, 4);
795         gtk_container_set_border_width(GTK_CONTAINER(vnbox), 4);
796         gtk_widget_show(vnbox);
797         gtk_box_pack_start(GTK_BOX(vbox), vnbox, TRUE, TRUE, 0);
798
799         /* Notebook */
800         notebook = gtk_notebook_new();
801         gtk_widget_show(notebook);
802         gtk_box_pack_start(GTK_BOX(vnbox), notebook, TRUE, TRUE, 0);
803         gtk_container_set_border_width(GTK_CONTAINER(notebook), 6);
804
805         /* Button panel */
806         if (prefs_common.addressbook_use_editaddress_dialog)
807         gtkut_stock_button_set_create(&hbbox, &cancel_btn, GTK_STOCK_CANCEL,
808                                       &ok_btn, GTK_STOCK_OK,
809                                       NULL, NULL);
810         else
811                 gtkut_stock_with_text_button_set_create(&hbbox,
812                                           &cancel_btn, GTK_STOCK_CANCEL, _("Discard"),
813                                       &ok_btn, GTK_STOCK_OK, _("Apply"),
814                                       NULL, NULL, NULL);
815         gtk_box_pack_end(GTK_BOX(vnbox), hbbox, FALSE, FALSE, 0);
816         gtk_widget_grab_default(ok_btn);
817
818         g_signal_connect(G_OBJECT(ok_btn), "clicked",
819                          G_CALLBACK(edit_person_ok), cancelled);
820         g_signal_connect(G_OBJECT(cancel_btn), "clicked",
821                          G_CALLBACK(edit_person_cancel), cancelled);
822         g_signal_connect(G_OBJECT(notebook), "switch_page",
823                          G_CALLBACK(edit_person_switch_page), NULL );
824
825         gtk_widget_show_all(vbox);
826
827         personeditdlg.notebook   = notebook;
828         personeditdlg.ok_btn     = ok_btn;
829         personeditdlg.cancel_btn = cancel_btn;
830
831         return vbox;
832 }
833
834 static void addressbook_edit_person_dialog_create( gboolean *cancelled ) {
835         GtkWidget *window;
836         GtkWidget *hsbox;
837         GtkWidget *vbox;
838         GtkWidget *statusbar;
839         static GdkGeometry geometry;
840
841         window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "editaddress");
842         /* gtk_container_set_border_width(GTK_CONTAINER(window), 0); */
843         gtk_window_set_title(GTK_WINDOW(window), _("Edit Person Data"));
844         gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
845         gtk_window_set_modal(GTK_WINDOW(window), TRUE); 
846         g_signal_connect(G_OBJECT(window), "delete_event",
847                          G_CALLBACK(edit_person_delete_event),
848                          cancelled);
849         g_signal_connect(G_OBJECT(window), "size_allocate",
850                          G_CALLBACK(edit_person_size_allocate_cb),
851                         cancelled);
852         g_signal_connect(G_OBJECT(window), "key_press_event",
853                          G_CALLBACK(edit_person_key_pressed),
854                          cancelled);
855
856         vbox = addressbook_edit_person_widgets_create(window, cancelled);
857
858         /* Status line */
859         hsbox = gtk_hbox_new(FALSE, 0);
860         gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
861         statusbar = gtk_statusbar_new();
862         gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
863
864         if (!geometry.min_height) {
865                 geometry.min_width = EDITPERSON_WIDTH;
866                 geometry.min_height = EDITPERSON_HEIGHT;
867         }
868
869         gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
870                                       GDK_HINT_MIN_SIZE);
871         gtk_widget_set_size_request(window, prefs_common.addressbookeditpersonwin_width,
872                                     prefs_common.addressbookeditpersonwin_height);
873
874         personeditdlg.container  = window;
875         personeditdlg.statusbar  = statusbar;
876         personeditdlg.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Edit Person Dialog" );
877
878 }
879
880 /* parent must be a box */
881 static void addressbook_edit_person_widgetset_create( GtkWidget *parent, gboolean *cancelled )
882 {
883         GtkWidget *vbox;
884         GtkWidget *label;
885
886         if ( parent == NULL )
887                 g_warning("addressbook_edit_person_widgetset_create: parent is NULL");
888
889         vbox = gtk_vbox_new(FALSE, 0);
890         gtk_box_pack_end(GTK_BOX(parent), vbox, TRUE, TRUE, 0);
891
892         label = gtk_label_new(_("Edit Person Data"));
893         gtk_label_set_justify( GTK_LABEL(label), GTK_JUSTIFY_CENTER);
894         gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
895
896         addressbook_edit_person_widgets_create(vbox, cancelled);
897
898         gtk_widget_set_size_request(vbox, EDITPERSON_WIDTH, EDITPERSON_HEIGHT);
899
900         personeditdlg.container = vbox;
901         personeditdlg.title = label;
902         personeditdlg.statusbar  = NULL;
903         personeditdlg.status_cid = 0;
904 }
905
906 void addressbook_edit_person_widgetset_hide( void )
907 {
908         if ( personeditdlg.container )
909                 gtk_widget_hide( personeditdlg.container );
910 }
911
912 static void addressbook_edit_person_set_picture(void)
913 {
914         GError *error = NULL;
915         gchar *filename;
916         int width, height, scalewidth, scaleheight;
917
918         if (personeditdlg.ldap)
919                 return;
920
921         if ( (filename = filesel_select_file_open(_("Choose a picture"), NULL)) ) {
922                 GdkPixbuf *pixbuf = NULL;
923                 gdk_pixbuf_get_file_info(filename, &width, &height);
924
925                 if ( width > 128 || height > 128 ) {
926                         if (width > height) {
927                                 scaleheight = (height * 128) / width;
928                                 scalewidth = 128;
929                         }
930                         else {
931                                 scalewidth = (width * 128) / height;
932                                 scaleheight = 128;
933                         }
934                         pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, 
935                                         scalewidth, scaleheight, TRUE, &error);
936                 } else {
937                         pixbuf = gdk_pixbuf_new_from_file(filename, &error);
938                 }
939                 if (error) {
940                         alertpanel_error(_("Failed to import image: \n%s"),
941                                         error->message);
942                         g_error_free(error);
943                         error = NULL;
944                         /* keep the previous picture if any */
945                         g_free(filename);
946                         if (pixbuf)
947                                 g_object_unref(pixbuf);
948                         return;
949                 }
950                 personeditdlg.picture_set = TRUE;
951                 cm_menu_set_sensitive("EditAddressPopup/UnsetPicture", personeditdlg.picture_set);
952                 g_free(filename);
953                 gtk_image_set_from_pixbuf(GTK_IMAGE(personeditdlg.image), pixbuf);
954                 g_object_unref(pixbuf);
955         }
956 }       
957
958 static void addressbook_edit_person_clear_picture(void)
959 {
960         GdkPixbuf *pixbuf;
961
962         stock_pixbuf_gdk(STOCK_PIXMAP_ANONYMOUS, &pixbuf);
963         personeditdlg.picture_set = FALSE;
964         cm_menu_set_sensitive("EditAddressPopup/UnsetPicture", personeditdlg.picture_set);
965         gtk_image_set_from_pixbuf(GTK_IMAGE(personeditdlg.image), pixbuf);
966 }
967
968 static void addressbook_edit_person_set_picture_menu_cb (GtkAction *action, gpointer data)
969 {
970         addressbook_edit_person_set_picture();
971 }
972
973 static void addressbook_edit_person_unset_picture_menu_cb (GtkAction *action, gpointer data)
974 {
975         addressbook_edit_person_clear_picture();
976 }
977
978 static GtkWidget *editaddr_popup_menu = NULL;
979 static GtkActionEntry editaddr_popup_entries[] =
980 {
981         {"EditAddressPopup",                    NULL, "EditAddressPopup" },
982         {"EditAddressPopup/SetPicture",         NULL, N_("_Set picture"), NULL, NULL, G_CALLBACK(addressbook_edit_person_set_picture_menu_cb) },
983         {"EditAddressPopup/UnsetPicture",       NULL, N_("_Unset picture"), NULL, NULL, G_CALLBACK(addressbook_edit_person_unset_picture_menu_cb) },
984 };
985
986 static void addressbook_edit_person_set_picture_cb(GtkWidget *widget, 
987                 GdkEventButton *event, gpointer data)
988 {       
989         if (event->button == 1) {
990                 addressbook_edit_person_set_picture();
991         } else {
992                 gtk_menu_popup(GTK_MENU(editaddr_popup_menu), 
993                                NULL, NULL, NULL, NULL, 
994                                event->button, event->time);
995         }
996 }
997
998 static gboolean addressbook_edit_person_picture_popup_menu(GtkWidget *widget, gpointer data)
999 {
1000         GdkEventButton event;
1001         
1002         event.button = 3;
1003         event.time = gtk_get_current_event_time();
1004         
1005         addressbook_edit_person_set_picture_cb(NULL, &event, data);
1006
1007         return TRUE;
1008 }
1009
1010 static void addressbook_edit_person_page_basic( gint pageNum, gchar *pageLbl ) {
1011         GtkWidget *vbox;
1012         GtkWidget *hbox;
1013         GtkWidget *table;
1014         GtkWidget *label;
1015         GtkWidget *ebox_picture;
1016         GtkWidget *frame_picture;
1017         GtkWidget *entry_name;
1018         GtkWidget *entry_fn;
1019         GtkWidget *entry_ln;
1020         GtkWidget *entry_nn;
1021         const gchar *locale;
1022         gint top = 0;
1023
1024         vbox = gtk_vbox_new( FALSE, 20 );
1025         hbox = gtk_hbox_new( FALSE, 8 );
1026
1027         gtk_widget_show( vbox );        
1028
1029         if (!editaddr_popup_menu) {
1030                 cm_menu_create_action_group("EditAddressPopup", editaddr_popup_entries,
1031                         G_N_ELEMENTS(editaddr_popup_entries), (gpointer)NULL);
1032                 MENUITEM_ADDUI("/Menus", "EditAddressPopup", "EditAddressPopup", GTK_UI_MANAGER_MENU)
1033                 MENUITEM_ADDUI("/Menus/EditAddressPopup", "SetPicture", "EditAddressPopup/SetPicture", GTK_UI_MANAGER_MENUITEM)
1034                 MENUITEM_ADDUI("/Menus/EditAddressPopup", "UnsetPicture", "EditAddressPopup/UnsetPicture", GTK_UI_MANAGER_MENUITEM)
1035
1036                 editaddr_popup_menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1037                         gtk_ui_manager_get_widget(gtkut_ui_manager(), "/Menus/EditAddressPopup")) );
1038         }
1039         /* User's picture */
1040         ebox_picture = gtk_event_box_new();
1041         frame_picture = gtk_frame_new(_("Photo"));
1042         
1043         /* Room for a photo */
1044         personeditdlg.image = gtk_image_new();
1045         addressbook_edit_person_clear_picture();
1046
1047         gtk_container_add(GTK_CONTAINER(ebox_picture), personeditdlg.image);
1048         gtk_container_add(GTK_CONTAINER(frame_picture), ebox_picture);  
1049         gtk_container_add(GTK_CONTAINER( personeditdlg.notebook ), hbox );
1050         gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
1051         gtk_container_set_border_width( GTK_CONTAINER (hbox), BORDER_WIDTH );
1052
1053         label = gtk_label_new_with_mnemonic( pageLbl );
1054         gtk_widget_show( label );
1055         
1056         gtk_box_pack_start(GTK_BOX(hbox), frame_picture, TRUE, TRUE, 0);
1057         
1058         gtk_notebook_set_tab_label(
1059                 GTK_NOTEBOOK( personeditdlg.notebook ),
1060                 gtk_notebook_get_nth_page( GTK_NOTEBOOK( personeditdlg.notebook ), pageNum ), label );
1061         
1062         g_signal_connect(G_OBJECT(ebox_picture), "popup-menu",
1063                          G_CALLBACK(addressbook_edit_person_picture_popup_menu), NULL);
1064         g_signal_connect(G_OBJECT(ebox_picture), "button_press_event", 
1065                         G_CALLBACK(addressbook_edit_person_set_picture_cb), NULL);
1066
1067         table = gtk_table_new( 3, 3, FALSE);
1068
1069 #define ATTACH_ROW(text, entry) \
1070 { \
1071         label = gtk_label_new(text); \
1072         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), \
1073                          GTK_FILL, 0, 0, 0); \
1074         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); \
1075  \
1076         entry = gtk_entry_new(); \
1077         gtk_table_attach(GTK_TABLE(table), entry, 1, 2, top, (top + 1), \
1078                          GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); \
1079         top++; \
1080 }
1081
1082 #define ATTACH_HIDDEN_ROW(text, entry) \
1083 { \
1084         entry = gtk_entry_new(); \
1085 }
1086
1087 #ifndef GENERIC_UMPC
1088         ATTACH_ROW(_("Display Name"), entry_name);
1089 #else
1090         ATTACH_HIDDEN_ROW(_("Display Name"), entry_name);
1091 #endif
1092         locale = conv_get_current_locale();
1093         if (locale &&
1094             (!g_ascii_strncasecmp(locale, "hu", 2) ||
1095              !g_ascii_strncasecmp(locale, "ja", 2) ||
1096              !g_ascii_strncasecmp(locale, "ko", 2) ||
1097              !g_ascii_strncasecmp(locale, "vi", 2) ||
1098              !g_ascii_strncasecmp(locale, "zh", 2))) {
1099                 ATTACH_ROW(_("Last Name"), entry_ln);
1100                 ATTACH_ROW(_("First Name"), entry_fn);
1101         } else {
1102                 ATTACH_ROW(_("First Name"), entry_fn);
1103                 ATTACH_ROW(_("Last Name"), entry_ln);
1104         }
1105 #ifndef GENERIC_UMPC
1106         ATTACH_ROW(_("Nickname"), entry_nn);
1107 #else
1108         ATTACH_HIDDEN_ROW(_("Nickname"), entry_nn);
1109 #endif
1110
1111 #undef ATTACH_ROW
1112 #undef ATTACH_HIDDEN_ROW
1113         gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
1114         gtk_box_pack_end(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
1115         gtk_container_set_border_width( GTK_CONTAINER(table), 8 );
1116         gtk_table_set_row_spacings(GTK_TABLE(table), 15);
1117         gtk_table_set_col_spacings(GTK_TABLE(table), 8);
1118
1119         gtk_widget_show_all(vbox);
1120         personeditdlg.entry_name  = entry_name;
1121         personeditdlg.entry_first = entry_fn;
1122         personeditdlg.entry_last  = entry_ln;
1123         personeditdlg.entry_nick  = entry_nn;
1124 }
1125
1126 static gboolean email_adding = FALSE, email_saving = FALSE;
1127
1128 static void edit_person_entry_email_changed (GtkWidget *entry, gpointer data)
1129 {
1130         GtkTreeModel *model = gtk_tree_view_get_model(
1131                         GTK_TREE_VIEW(personeditdlg.view_email));
1132         gboolean non_empty = (gtk_tree_model_iter_n_children(model, NULL) > 0);
1133
1134         if (personeditdlg.read_only)
1135                 return;
1136
1137         if (gtk_entry_get_text(GTK_ENTRY(personeditdlg.entry_email)) == NULL
1138         ||  strlen(gtk_entry_get_text(GTK_ENTRY(personeditdlg.entry_email))) == 0) {
1139                 gtk_widget_set_sensitive(personeditdlg.email_add,FALSE);
1140                 gtk_widget_set_sensitive(personeditdlg.email_mod,FALSE);
1141                 email_adding = FALSE;
1142                 email_saving = FALSE;
1143         } else if (list_find_email(gtk_entry_get_text(GTK_ENTRY(personeditdlg.entry_email)))) {
1144                 gtk_widget_set_sensitive(personeditdlg.email_add,FALSE);
1145                 gtk_widget_set_sensitive(personeditdlg.email_mod,non_empty);
1146                 email_adding = FALSE;
1147                 email_saving = non_empty;
1148         } else {
1149                 gtk_widget_set_sensitive(personeditdlg.email_add,TRUE);
1150                 gtk_widget_set_sensitive(personeditdlg.email_mod,non_empty);
1151                 email_adding = TRUE;
1152                 email_saving = non_empty;
1153         }
1154 }
1155
1156 static gboolean edit_person_entry_email_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
1157 {
1158         if (event && event->keyval == GDK_KEY_Return) {
1159                 if (email_saving)
1160                         edit_person_email_modify(NULL);         
1161                 else if (email_adding)
1162                         edit_person_email_add(NULL);
1163         }
1164         return FALSE;
1165 }
1166
1167
1168 static void addressbook_edit_person_page_email( gint pageNum, gchar *pageLbl ) {
1169         GtkWidget *vbox;
1170         GtkWidget *hbox;
1171         GtkWidget *vboxl;
1172         GtkWidget *vboxb;
1173         GtkWidget *vbuttonbox;
1174         GtkWidget *buttonUp;
1175         GtkWidget *buttonDown;
1176         GtkWidget *buttonDel;
1177         GtkWidget *buttonMod;
1178         GtkWidget *buttonAdd;
1179
1180         GtkWidget *table;
1181         GtkWidget *label;
1182         GtkWidget *scrollwin;
1183         GtkWidget *view;
1184         GtkWidget *entry_email;
1185         GtkWidget *entry_alias;
1186         GtkWidget *entry_remarks;
1187         gint top;
1188         GtkListStore *store;
1189         GtkTreeViewColumn *col;
1190         GtkCellRenderer *rdr;
1191         GtkTreeSelection *sel;
1192
1193         vbox = gtk_vbox_new( FALSE, 8 );
1194         gtk_widget_show( vbox );
1195         gtk_container_add( GTK_CONTAINER( personeditdlg.notebook ), vbox );
1196         gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
1197
1198         label = gtk_label_new_with_mnemonic( pageLbl );
1199         gtk_widget_show( label );
1200         gtk_notebook_set_tab_label(
1201                 GTK_NOTEBOOK( personeditdlg.notebook ),
1202                 gtk_notebook_get_nth_page( GTK_NOTEBOOK( personeditdlg.notebook ), pageNum ), label );
1203
1204         /* Split into two areas */
1205         hbox = gtk_hbox_new( FALSE, 0 );
1206         gtk_container_add( GTK_CONTAINER( vbox ), hbox );
1207
1208         /* Address list */
1209         vboxl = gtk_vbox_new( FALSE, 4 );
1210         gtk_container_add( GTK_CONTAINER( hbox ), vboxl );
1211         gtk_container_set_border_width( GTK_CONTAINER(vboxl), 4 );
1212
1213         scrollwin = gtk_scrolled_window_new( NULL, NULL );
1214         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
1215                                        GTK_POLICY_AUTOMATIC,
1216                                        GTK_POLICY_AUTOMATIC);
1217
1218         store = gtk_list_store_new(EMAIL_N_COLS,
1219                         G_TYPE_STRING,
1220 #ifndef GENERIC_UMPC
1221                         G_TYPE_STRING,
1222                         G_TYPE_STRING,
1223 #endif
1224                         G_TYPE_POINTER,
1225                         -1);
1226
1227         view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1228         g_object_unref(store);
1229 #ifndef GENERIC_UMPC
1230         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), TRUE);
1231 #else
1232         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
1233 #endif
1234         sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
1235         gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
1236
1237         rdr = gtk_cell_renderer_text_new();
1238         col = gtk_tree_view_column_new_with_attributes(_("Email Address"), rdr,
1239                         "markup", EMAIL_COL_EMAIL, NULL);
1240         gtk_tree_view_column_set_min_width(col, EMAIL_COL_WIDTH_EMAIL);
1241         gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
1242
1243 #ifndef GENERIC_UMPC
1244         col = gtk_tree_view_column_new_with_attributes(_("Alias"), rdr,
1245                         "markup", EMAIL_COL_ALIAS, NULL);
1246         gtk_tree_view_column_set_min_width(col, EMAIL_COL_WIDTH_ALIAS);
1247         gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
1248
1249         col = gtk_tree_view_column_new_with_attributes(_("Remarks"), rdr,
1250                         "markup", EMAIL_COL_REMARKS, NULL);
1251         gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
1252 #endif
1253
1254         gtk_container_add( GTK_CONTAINER(scrollwin), view );
1255
1256         /* Data entry area */
1257         table = gtk_table_new( 4, 2, FALSE);
1258
1259 #ifndef GENERIC_UMPC
1260         gtk_container_add( GTK_CONTAINER(vboxl), scrollwin );
1261         gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0);
1262 #else
1263         gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0);
1264         gtk_container_add( GTK_CONTAINER(vboxl), scrollwin );
1265 #endif
1266         gtk_container_set_border_width( GTK_CONTAINER(table), 4 );
1267         gtk_table_set_row_spacings(GTK_TABLE(table), 4);
1268         gtk_table_set_col_spacings(GTK_TABLE(table), 4);
1269
1270         entry_email = gtk_entry_new();
1271         entry_alias = gtk_entry_new();
1272         entry_remarks = gtk_entry_new();
1273
1274         /* First row */
1275         top = 0;
1276         label = gtk_label_new(_("Email Address"));
1277         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
1278         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1279
1280         gtk_table_attach(GTK_TABLE(table), entry_email, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
1281
1282 #ifndef GENERIC_UMPC
1283         /* Next row */
1284         ++top;
1285         label = gtk_label_new(_("Alias"));
1286         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
1287         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1288
1289         gtk_table_attach(GTK_TABLE(table), entry_alias, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
1290
1291         /* Next row */
1292         ++top;
1293         label = gtk_label_new(_("Remarks"));
1294         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
1295         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1296
1297         gtk_table_attach(GTK_TABLE(table), entry_remarks, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
1298 #endif
1299
1300         /* Button box */
1301         vboxb = gtk_vbox_new( FALSE, 4 );
1302         gtk_box_pack_start(GTK_BOX(hbox), vboxb, FALSE, FALSE, 2);
1303
1304         vbuttonbox = gtk_vbutton_box_new();
1305         gtk_button_box_set_layout( GTK_BUTTON_BOX(vbuttonbox), GTK_BUTTONBOX_START );
1306         gtk_box_set_spacing( GTK_BOX(vbuttonbox), 8 );
1307         gtk_container_set_border_width( GTK_CONTAINER(vbuttonbox), 4 );
1308         gtk_container_add( GTK_CONTAINER(vboxb), vbuttonbox );
1309
1310         /* Buttons */
1311         buttonUp = gtk_button_new_from_stock(GTK_STOCK_GO_UP);
1312         buttonDown = gtk_button_new_from_stock(GTK_STOCK_GO_DOWN);
1313         buttonDel = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1314         buttonMod = gtk_button_new_from_stock(GTK_STOCK_SAVE);
1315         buttonAdd = gtk_button_new_from_stock(GTK_STOCK_ADD);
1316         
1317
1318 #ifndef GENERIC_UMPC
1319         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonUp );
1320
1321         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDown );
1322 #endif
1323         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDel );
1324
1325         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonMod );
1326
1327         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonAdd );
1328
1329         gtk_widget_show_all(vbox);
1330
1331         /* Event handlers */
1332         g_signal_connect( G_OBJECT(view), "cursor-changed",
1333                           G_CALLBACK( edit_person_email_cursor_changed ), NULL );
1334         g_signal_connect( G_OBJECT(buttonUp), "clicked",
1335                           G_CALLBACK( edit_person_email_move_up ), NULL );
1336         g_signal_connect( G_OBJECT(buttonDown), "clicked",
1337                           G_CALLBACK( edit_person_email_move_down ), NULL );
1338         g_signal_connect( G_OBJECT(buttonDel), "clicked",
1339                           G_CALLBACK( edit_person_email_delete ), NULL );
1340         g_signal_connect( G_OBJECT(buttonMod), "clicked",
1341                           G_CALLBACK( edit_person_email_modify ), NULL );
1342         g_signal_connect( G_OBJECT(buttonAdd), "clicked",
1343                           G_CALLBACK( edit_person_email_add ), NULL );
1344         g_signal_connect(G_OBJECT(entry_email), "changed",
1345                          G_CALLBACK(edit_person_entry_email_changed), NULL);
1346         g_signal_connect(G_OBJECT(entry_email), "key_press_event",
1347                          G_CALLBACK(edit_person_entry_email_pressed), NULL);
1348         g_signal_connect(G_OBJECT(entry_alias), "key_press_event",
1349                          G_CALLBACK(edit_person_entry_email_pressed), NULL);
1350         g_signal_connect(G_OBJECT(entry_remarks), "key_press_event",
1351                          G_CALLBACK(edit_person_entry_email_pressed), NULL);
1352
1353         personeditdlg.view_email   = view;
1354         personeditdlg.entry_email   = entry_email;
1355         personeditdlg.entry_alias   = entry_alias;
1356         personeditdlg.entry_remarks = entry_remarks;
1357         personeditdlg.email_up = buttonUp;
1358         personeditdlg.email_down = buttonDown;
1359         personeditdlg.email_del = buttonDel;
1360         personeditdlg.email_mod = buttonMod;
1361         personeditdlg.email_add = buttonAdd;
1362 }
1363
1364 static gboolean attrib_adding = FALSE, attrib_saving = FALSE;
1365
1366 static void edit_person_entry_att_changed (GtkWidget *entry, gpointer data)
1367 {
1368         GtkTreeModel *model = gtk_tree_view_get_model(
1369                         GTK_TREE_VIEW(personeditdlg.view_attrib));
1370         gboolean non_empty = (gtk_tree_model_iter_n_children(model, NULL) > 0);
1371         const gchar *atname;
1372
1373         if (personeditdlg.read_only || personeditdlg.ldap)
1374                 return;
1375
1376         atname = gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN((personeditdlg.entry_atname)))));
1377         if ( atname == NULL
1378         ||  strlen(atname) == 0) {
1379                 gtk_widget_set_sensitive(personeditdlg.attrib_add,FALSE);
1380                 gtk_widget_set_sensitive(personeditdlg.attrib_mod,FALSE);
1381                 attrib_adding = FALSE;
1382                 attrib_saving = FALSE;
1383         } else if (list_find_attribute(atname)) {
1384                 gtk_widget_set_sensitive(personeditdlg.attrib_add,FALSE);
1385                 gtk_widget_set_sensitive(personeditdlg.attrib_mod,non_empty);
1386                 attrib_adding = FALSE;
1387                 attrib_saving = non_empty;
1388         } else {
1389                 gtk_widget_set_sensitive(personeditdlg.attrib_add,TRUE);
1390                 gtk_widget_set_sensitive(personeditdlg.attrib_mod,non_empty);
1391                 attrib_adding = TRUE;
1392                 attrib_saving = non_empty;
1393         }
1394 }
1395
1396 static gboolean edit_person_entry_att_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
1397 {
1398         if (event && event->keyval == GDK_KEY_Return) {
1399                 if (attrib_saving)
1400                         edit_person_attrib_modify(NULL);
1401                 else if (attrib_adding)
1402                         edit_person_attrib_add(NULL);
1403         }
1404         return FALSE;
1405 }
1406
1407 static void addressbook_edit_person_page_attrib( gint pageNum, gchar *pageLbl ) {
1408         GtkWidget *vbox;
1409         GtkWidget *hbox;
1410         GtkWidget *vboxl;
1411         GtkWidget *vboxb;
1412         GtkWidget *vbuttonbox;
1413         GtkWidget *buttonDel;
1414         GtkWidget *buttonMod;
1415         GtkWidget *buttonAdd;
1416
1417         GtkWidget *table;
1418         GtkWidget *label;
1419         GtkWidget *scrollwin;
1420         GtkWidget *view;
1421         GtkWidget *entry_name;
1422         GtkWidget *entry_value;
1423         gint top;
1424         GtkListStore *store;
1425         GtkTreeViewColumn *col;
1426         GtkCellRenderer *rdr;
1427         GtkTreeSelection *sel;
1428
1429         vbox = gtk_vbox_new( FALSE, 8 );
1430         gtk_widget_show( vbox );
1431         gtk_container_add( GTK_CONTAINER( personeditdlg.notebook ), vbox );
1432         gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
1433
1434         label = gtk_label_new_with_mnemonic( pageLbl );
1435         gtk_widget_show( label );
1436         gtk_notebook_set_tab_label(
1437                 GTK_NOTEBOOK( personeditdlg.notebook ),
1438                 gtk_notebook_get_nth_page( GTK_NOTEBOOK( personeditdlg.notebook ), pageNum ), label );
1439
1440         /* Split into two areas */
1441         hbox = gtk_hbox_new( FALSE, 0 );
1442         gtk_container_add( GTK_CONTAINER( vbox ), hbox );
1443
1444         /* Attribute list */
1445         vboxl = gtk_vbox_new( FALSE, 4 );
1446         gtk_container_add( GTK_CONTAINER( hbox ), vboxl );
1447         gtk_container_set_border_width( GTK_CONTAINER(vboxl), 4 );
1448
1449         scrollwin = gtk_scrolled_window_new( NULL, NULL );
1450         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
1451                                        GTK_POLICY_AUTOMATIC,
1452                                        GTK_POLICY_AUTOMATIC);
1453
1454         store = gtk_list_store_new(ATTRIB_N_COLS,
1455                         G_TYPE_STRING, G_TYPE_STRING,
1456                         G_TYPE_POINTER, -1);
1457
1458         view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1459         g_object_unref(store);
1460         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), TRUE);
1461         sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
1462         gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
1463
1464         rdr = gtk_cell_renderer_text_new();
1465         col = gtk_tree_view_column_new_with_attributes(_("Name"), rdr,
1466                         "markup", ATTRIB_COL_NAME, NULL);
1467         gtk_tree_view_column_set_min_width(col, ATTRIB_COL_WIDTH_NAME);
1468         gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
1469
1470         col = gtk_tree_view_column_new_with_attributes(_("Value"), rdr,
1471                         "markup", ATTRIB_COL_VALUE, NULL);
1472         gtk_tree_view_column_set_min_width(col, ATTRIB_COL_WIDTH_VALUE);
1473         gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
1474
1475         gtk_container_add( GTK_CONTAINER(scrollwin), view );
1476
1477         /* Data entry area */
1478 #ifndef GENERIC_UMPC
1479         table = gtk_table_new( 4, 2, FALSE);
1480         gtk_container_add( GTK_CONTAINER(vboxl), scrollwin );
1481         gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0);
1482 #else
1483         table = gtk_table_new( 2, 4, FALSE);
1484         gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0);
1485         gtk_container_add( GTK_CONTAINER(vboxl), scrollwin );
1486 #endif
1487         gtk_container_set_border_width( GTK_CONTAINER(table), 4 );
1488         gtk_table_set_row_spacings(GTK_TABLE(table), 4);
1489         gtk_table_set_col_spacings(GTK_TABLE(table), 4);
1490
1491         /* First row */
1492         top = 0;
1493 #ifndef GENERIC_UMPC
1494         label = gtk_label_new(_("Name"));
1495         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
1496         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1497
1498         entry_name = gtk_combo_box_text_new_with_entry ();
1499         gtk_table_attach(GTK_TABLE(table), entry_name, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
1500
1501         /* Next row */
1502         ++top;
1503         label = gtk_label_new(_("Value"));
1504         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
1505         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1506
1507         entry_value = gtk_entry_new();
1508         gtk_table_attach(GTK_TABLE(table), entry_value, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
1509 #else
1510         label = gtk_label_new(_("Name"));
1511         gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
1512         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1513
1514         entry_name = gtk_combo_box_text_new_with_entry ();
1515         gtk_table_attach(GTK_TABLE(table), entry_name, 1, 2, 0, 1, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
1516
1517         /* Next row */
1518         ++top;
1519         label = gtk_label_new(_("Value"));
1520         gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1, GTK_FILL, 0, 0, 0);
1521         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1522
1523         entry_value = gtk_entry_new();
1524         gtk_table_attach(GTK_TABLE(table), entry_value, 3, 4, 0, 1, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
1525 #endif
1526         gtk_combo_box_set_active(GTK_COMBO_BOX(entry_name), -1);
1527         if (prefs_common.addressbook_custom_attributes)
1528                 combobox_set_popdown_strings(GTK_COMBO_BOX_TEXT(entry_name),
1529                                 prefs_common.addressbook_custom_attributes);            
1530         /* Button box */
1531         vboxb = gtk_vbox_new( FALSE, 4 );
1532         gtk_box_pack_start(GTK_BOX(hbox), vboxb, FALSE, FALSE, 2);
1533
1534         vbuttonbox = gtk_vbutton_box_new();
1535         gtk_button_box_set_layout( GTK_BUTTON_BOX(vbuttonbox), GTK_BUTTONBOX_START );
1536         gtk_box_set_spacing( GTK_BOX(vbuttonbox), 8 );
1537         gtk_container_set_border_width( GTK_CONTAINER(vbuttonbox), 4 );
1538         gtk_container_add( GTK_CONTAINER(vboxb), vbuttonbox );
1539
1540         /* Buttons */
1541         buttonDel = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1542         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDel );
1543
1544         buttonMod = gtk_button_new_from_stock(GTK_STOCK_SAVE);
1545         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonMod );
1546
1547         buttonAdd = gtk_button_new_from_stock(GTK_STOCK_ADD);
1548         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonAdd );
1549         
1550         gtk_widget_set_sensitive(buttonDel,FALSE);
1551         gtk_widget_set_sensitive(buttonMod,FALSE);
1552         gtk_widget_set_sensitive(buttonAdd,FALSE);
1553
1554         gtk_widget_show_all(vbox);
1555
1556         /* Event handlers */
1557         g_signal_connect( G_OBJECT(view), "cursor-changed",
1558                           G_CALLBACK( edit_person_attrib_cursor_changed ), NULL );
1559         g_signal_connect( G_OBJECT(buttonDel), "clicked",
1560                           G_CALLBACK( edit_person_attrib_delete ), NULL );
1561         g_signal_connect( G_OBJECT(buttonMod), "clicked",
1562                           G_CALLBACK( edit_person_attrib_modify ), NULL );
1563         g_signal_connect( G_OBJECT(buttonAdd), "clicked",
1564                           G_CALLBACK( edit_person_attrib_add ), NULL );
1565         g_signal_connect(G_OBJECT(entry_name), "changed",
1566                          G_CALLBACK(edit_person_entry_att_changed), NULL);
1567         g_signal_connect(G_OBJECT(entry_name), "key_press_event",
1568                          G_CALLBACK(edit_person_entry_att_pressed), NULL);
1569         g_signal_connect(G_OBJECT(entry_value), "key_press_event",
1570                          G_CALLBACK(edit_person_entry_att_pressed), NULL);
1571
1572         personeditdlg.view_attrib  = view;
1573         personeditdlg.entry_atname  = entry_name;
1574         personeditdlg.entry_atvalue = entry_value;
1575         personeditdlg.attrib_add = buttonAdd;
1576         personeditdlg.attrib_del = buttonDel;
1577         personeditdlg.attrib_mod = buttonMod;
1578 }
1579
1580 static void addressbook_edit_person_create( GtkWidget *parent, gboolean *cancelled ) {
1581         if (prefs_common.addressbook_use_editaddress_dialog)
1582                 addressbook_edit_person_dialog_create( cancelled );
1583         else
1584                 addressbook_edit_person_widgetset_create( parent, cancelled );
1585         addressbook_edit_person_page_basic( PAGE_BASIC, _( "_User Data" ) );
1586         addressbook_edit_person_page_email( PAGE_EMAIL, _( "_Email Addresses" ) );
1587 #ifdef USE_LDAP
1588         if (personeditdlg.ldap)
1589                 addressbook_edit_person_page_attrib_ldap(&personeditdlg, PAGE_ATTRIBUTES, _("O_ther Attributes"));
1590         else
1591 #endif
1592                 addressbook_edit_person_page_attrib( PAGE_ATTRIBUTES, _( "O_ther Attributes" ) );
1593         gtk_widget_show_all( personeditdlg.container );
1594 }
1595
1596 /*
1597 * Return list of email items.
1598 */
1599 static GList *edit_person_build_email_list() {
1600         GtkWidget *view = personeditdlg.view_email;
1601         GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
1602         GtkTreeIter iter;
1603         GList *listEMail = NULL;
1604         ItemEMail *email;
1605
1606         if (!gtk_tree_model_get_iter_first(model, &iter))
1607                 return NULL;
1608
1609         do {
1610                 gtk_tree_model_get(model, &iter, EMAIL_COL_PTR, &email, -1);
1611                 listEMail = g_list_append( listEMail, email );
1612         } while (gtk_tree_model_iter_next(model, &iter));
1613
1614         return listEMail;
1615 }
1616
1617 /*
1618 * Return list of attributes.
1619 */
1620 static GList *edit_person_build_attrib_list() {
1621         GtkTreeModel *model = gtk_tree_view_get_model(
1622                         GTK_TREE_VIEW(personeditdlg.view_attrib));
1623         GtkTreeIter iter;
1624         GList *listAttrib = NULL;
1625         UserAttribute *attrib;
1626
1627         /* Iterate through all the rows, selecting the one that
1628          * matches. */
1629         if (!gtk_tree_model_get_iter_first(model, &iter))
1630                 return FALSE;
1631
1632         do {
1633                 gtk_tree_model_get(model, &iter, ATTRIB_COL_PTR, &attrib, -1);
1634                 listAttrib = g_list_append( listAttrib, attrib );
1635         } while (gtk_tree_model_iter_next(model, &iter));
1636
1637         return listAttrib;
1638 }
1639
1640 static void update_sensitivity(void)
1641 {
1642         gtk_widget_set_sensitive(personeditdlg.entry_name,    !personeditdlg.read_only);
1643         gtk_widget_set_sensitive(personeditdlg.entry_first,   !personeditdlg.read_only);
1644         gtk_widget_set_sensitive(personeditdlg.entry_last,    !personeditdlg.read_only);
1645         gtk_widget_set_sensitive(personeditdlg.entry_nick,    !personeditdlg.read_only && !personeditdlg.ldap);
1646         gtk_widget_set_sensitive(personeditdlg.entry_email,   !personeditdlg.read_only);
1647         gtk_widget_set_sensitive(personeditdlg.entry_alias,   !personeditdlg.read_only && !personeditdlg.ldap);
1648         gtk_widget_set_sensitive(personeditdlg.entry_remarks, !personeditdlg.read_only && !personeditdlg.ldap);
1649         gtk_widget_set_sensitive(personeditdlg.email_up,      !personeditdlg.read_only);
1650         gtk_widget_set_sensitive(personeditdlg.email_down,    !personeditdlg.read_only);
1651         gtk_widget_set_sensitive(personeditdlg.email_del,     !personeditdlg.read_only);
1652         gtk_widget_set_sensitive(personeditdlg.email_mod,     !personeditdlg.read_only);
1653         gtk_widget_set_sensitive(personeditdlg.email_add,     !personeditdlg.read_only);
1654         gtk_widget_set_sensitive(personeditdlg.entry_atname,  !personeditdlg.read_only);
1655         gtk_widget_set_sensitive(personeditdlg.entry_atvalue, !personeditdlg.read_only);
1656         gtk_widget_set_sensitive(personeditdlg.attrib_add,    !personeditdlg.read_only);
1657         gtk_widget_set_sensitive(personeditdlg.attrib_del,    !personeditdlg.read_only);
1658         gtk_widget_set_sensitive(personeditdlg.attrib_mod,    !personeditdlg.read_only);
1659 }
1660
1661 static void addressbook_edit_person_flush_transient( void )
1662 {
1663         ItemPerson *person = current_person;
1664         EditAddressPostUpdateCallback callback = edit_person_close_post_update_cb;
1665
1666         /* reset transient data */
1667         current_abf = NULL;
1668         current_person = NULL;
1669         current_parent_folder = NULL;
1670         edit_person_close_post_update_cb = NULL;
1671
1672         /* post action to perform on addressbook side */
1673         if (callback)
1674                 callback( person );
1675 }
1676
1677 void addressbook_edit_person_invalidate( AddressBookFile *abf, ItemFolder *parent_folder,
1678                                                                                  ItemPerson *person )
1679 {
1680         if (current_abf == NULL &&
1681                 current_person == NULL &&
1682                 current_parent_folder == NULL)
1683                 /* edit address form is already hidden */
1684                 return;
1685
1686         /* unconditional invalidation or invalidating the currently edited item */
1687         if ( ( abf == NULL && person == NULL && parent_folder == NULL )
1688                 || (current_abf == abf ||
1689                         current_person == person ||
1690                         current_parent_folder == parent_folder))
1691                 addressbook_edit_person_close( TRUE );
1692 }
1693
1694 static gboolean addressbook_edit_person_close( gboolean cancelled )
1695 {
1696         GList *listEMail = NULL;
1697         GList *listAttrib = NULL;
1698         GError *error = NULL;
1699         GtkTreeModel *model;
1700
1701         listEMail = edit_person_build_email_list();
1702         listAttrib = edit_person_build_attrib_list();
1703         if( cancelled ) {
1704                 addritem_free_list_email( listEMail );
1705                 addritem_free_list_attribute( listAttrib );
1706                 model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_email));
1707                 gtk_list_store_clear(GTK_LIST_STORE(model));
1708                 model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_attrib));
1709                 gtk_list_store_clear(GTK_LIST_STORE(model));
1710
1711                 if (!prefs_common.addressbook_use_editaddress_dialog)
1712                         gtk_widget_hide( personeditdlg.container );
1713
1714                 /* no callback, as we're discarding the form */
1715                 edit_person_close_post_update_cb = NULL;
1716                 addressbook_edit_person_flush_transient();
1717                 current_person = NULL;
1718
1719                 /* set focus to the address list (this is done by the post_update_cb usually) */
1720                 addressbook_address_list_set_focus();
1721                 return FALSE;
1722         }
1723
1724         if( current_person && current_abf ) {
1725                 /* Update email/attribute list for existing current_person */
1726                 addrbook_update_address_list( current_abf, current_person, listEMail );
1727                 addrbook_update_attrib_list( current_abf, current_person, listAttrib );
1728         }
1729         else {
1730                 /* Create new current_person and email/attribute list */
1731                 if( ! cancelled && current_abf ) {
1732                         current_person = addrbook_add_address_list( current_abf, current_parent_folder, listEMail );
1733                         addrbook_add_attrib_list( current_abf, current_person, listAttrib );
1734                 }
1735         }
1736         listEMail = NULL;
1737         listAttrib = NULL;
1738
1739         if(!cancelled && current_person != NULL) {
1740                 /* Set current_person stuff */          
1741
1742                 gchar *name;
1743                 gchar *cn = edit_person_get_common_name_from_widgets();
1744
1745                 addritem_person_set_common_name( current_person, cn );
1746                 g_free( cn );
1747
1748                 if (personeditdlg.picture_set) { 
1749                         GdkPixbuf * pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(personeditdlg.image));
1750
1751                         if (!current_person->picture)
1752                                 name = g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, G_DIR_SEPARATOR_S, 
1753                                                 ADDRITEM_ID(current_person), ".png", NULL );
1754                         else 
1755                                 name = g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, G_DIR_SEPARATOR_S, 
1756                                                 current_person->picture, ".png", NULL );
1757
1758                         gdk_pixbuf_save(pixbuf, name, "png", &error, NULL);
1759                         if (error) {
1760                                 alertpanel_error(_("Failed to save image: \n%s"),
1761                                                 error->message);
1762                                 g_error_free(error);
1763                         } else {
1764                                 debug_print("saved picture to %s\n", name);
1765                         }
1766                         if (!current_person->picture)
1767                                 addritem_person_set_picture( current_person, ADDRITEM_ID(current_person) ) ;
1768                         g_free( name );
1769                 } else {
1770                         if (!current_person->picture)
1771                                 name = g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, G_DIR_SEPARATOR_S, 
1772                                                 ADDRITEM_ID(current_person), ".png", NULL );
1773                         else 
1774                                 name = g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, G_DIR_SEPARATOR_S, 
1775                                                 current_person->picture, ".png", NULL );
1776                         claws_unlink(name);
1777                         g_free(name);
1778                 }
1779                 name = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_first), 0, -1 );
1780                 addritem_person_set_first_name( current_person, name );
1781                 g_free( name );
1782                 name = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_last), 0, -1 );
1783                 addritem_person_set_last_name( current_person, name );
1784                 g_free( name );
1785                 name = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_nick), 0, -1 );
1786                 addritem_person_set_nick_name( current_person, name );
1787                 g_free( name );
1788         }
1789
1790         model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_email));
1791         gtk_list_store_clear(GTK_LIST_STORE(model));
1792         model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_attrib));
1793         gtk_list_store_clear(GTK_LIST_STORE(model));
1794
1795         if (!prefs_common.addressbook_use_editaddress_dialog)
1796                 gtk_widget_hide( personeditdlg.container );
1797
1798         addressbook_edit_person_flush_transient();
1799
1800         return TRUE;
1801 }
1802  
1803 /*
1804 * Edit person.
1805 * Enter: abf    Address book.
1806 *        parent Parent folder for person (or NULL if adding to root folder). Argument is
1807 *               only required for new objects).
1808 *        person Person to edit, or NULL for a new person object.
1809 *        pgMail If TRUE, E-Mail page will be activated.
1810 * Return: Edited object, or NULL if cancelled.*/
1811 ItemPerson *addressbook_edit_person( AddressBookFile *abf, ItemFolder *parent_folder, ItemPerson *person,
1812                                                                          gboolean pgMail, GtkWidget *parent_container,
1813                                                                          void (*post_update_cb) (ItemPerson *person),
1814                                                                          gboolean get_focus) {
1815         static gboolean cancelled;
1816         GError *error = NULL;
1817         GdkPixbuf *pixbuf = NULL;
1818         GtkTreeModel *model;
1819         GtkTreeSelection *sel;
1820         GtkTreeIter iter;
1821
1822         /* set transient data */
1823         current_abf = abf;
1824         current_person = person;
1825         current_parent_folder = parent_folder;
1826         edit_person_close_post_update_cb = post_update_cb;
1827         personeditdlg.ldap = (abf && abf->type == ADBOOKTYPE_LDAP)? TRUE : FALSE;
1828
1829         if( personeditdlg.container ) {
1830                 gtk_widget_destroy(personeditdlg.container);
1831                 personeditdlg.container = NULL;
1832         }
1833         addressbook_edit_person_create(parent_container, &cancelled);
1834
1835         /* typically, get focus when dialog mode is enabled, or when editing a new address */
1836         if( get_focus ) {
1837                 gtk_widget_grab_focus(personeditdlg.ok_btn);
1838                 gtk_widget_grab_focus(personeditdlg.entry_name);
1839         }
1840         
1841         personeditdlg.read_only = (current_abf == NULL);
1842         update_sensitivity();
1843
1844         gtk_widget_show(personeditdlg.container);
1845         if (prefs_common.addressbook_use_editaddress_dialog)
1846                 manage_window_set_transient(GTK_WINDOW(personeditdlg.container));
1847         else
1848                 if (get_focus)
1849                         addressbook_address_list_disable_some_actions();
1850
1851         /* Clear all fields */
1852         edit_person_status_show( "" );
1853
1854         model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_email));
1855         gtk_list_store_clear(GTK_LIST_STORE(model));
1856         model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_attrib));
1857         gtk_list_store_clear(GTK_LIST_STORE(model));
1858
1859         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_name), "" );
1860         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_first), "" );
1861         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_last), "" );
1862         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_nick), "" );
1863
1864         personeditdlg.editNew = FALSE;
1865         if( current_person ) {
1866                 gchar *filename = NULL;
1867
1868                 if( ADDRITEM_NAME(current_person) )
1869                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_name), ADDRITEM_NAME(person) );
1870
1871                 cm_menu_set_sensitive("EditAddressPopup/SetPicture", !personeditdlg.ldap);
1872                 cm_menu_set_sensitive("EditAddressPopup/UnsetPicture", !personeditdlg.ldap);
1873                 if( current_person->picture ) { 
1874                         filename = g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S, ADDRBOOK_DIR, G_DIR_SEPARATOR_S, 
1875                                                         current_person->picture, ".png", NULL );
1876                         if (is_file_exist(filename)) {
1877                                 pixbuf = gdk_pixbuf_new_from_file(filename, &error);
1878                                 if (error) {
1879                                         debug_print("Failed to import image: %s\n",
1880                                                         error->message);
1881                                         g_error_free(error);
1882                                         goto no_img;
1883                                 }
1884                                 personeditdlg.picture_set = TRUE;
1885                                 cm_menu_set_sensitive("EditAddressPopup/UnsetPicture", !personeditdlg.ldap && personeditdlg.picture_set);
1886                         } else {
1887                                 goto no_img;
1888                         }
1889                         gtk_image_set_from_pixbuf(GTK_IMAGE(personeditdlg.image), pixbuf);
1890                 } else {
1891 no_img:
1892                         addressbook_edit_person_clear_picture();
1893                 }
1894                 
1895                 g_free(filename);
1896                 if (pixbuf) {
1897                         g_object_unref(pixbuf);
1898                         pixbuf = NULL;
1899                 }
1900
1901                 if( current_person->firstName )
1902                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_first), current_person->firstName );
1903                 if( current_person->lastName )
1904                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_last), current_person->lastName );
1905                 if( current_person->nickName )
1906                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_nick), current_person->nickName );
1907                 edit_person_load_email( current_person );
1908                 edit_person_load_attrib( current_person );
1909                 gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_atvalue), "");
1910         }
1911         else {
1912                 personeditdlg.editNew = TRUE;
1913         }
1914
1915         /* Select appropriate start page */
1916         if( pgMail ) {
1917                 gtk_notebook_set_current_page( GTK_NOTEBOOK(personeditdlg.notebook), PAGE_EMAIL );
1918         }
1919         else {
1920                 gtk_notebook_set_current_page( GTK_NOTEBOOK(personeditdlg.notebook), PAGE_BASIC );
1921         }
1922
1923         sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(personeditdlg.view_email));
1924         model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_email));
1925         if (gtk_tree_model_get_iter_first(model, &iter)) {
1926                 gtk_tree_selection_select_iter(sel, &iter);
1927                 edit_person_email_cursor_changed(
1928                                 GTK_TREE_VIEW(personeditdlg.view_email), NULL);
1929         }
1930
1931         sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(personeditdlg.view_attrib));
1932         model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_attrib));
1933         if (gtk_tree_model_get_iter_first(model, &iter))
1934                 gtk_tree_selection_select_iter(sel, &iter);
1935                 edit_person_attrib_cursor_changed(
1936                                 GTK_TREE_VIEW(personeditdlg.view_attrib), NULL);
1937
1938         edit_person_email_clear( NULL );
1939         edit_person_attrib_clear( NULL );
1940
1941         if (prefs_common.addressbook_use_editaddress_dialog) {
1942                 gtk_main();
1943                 gtk_widget_hide( personeditdlg.container );
1944
1945                 if (!addressbook_edit_person_close( cancelled )) {
1946                         return NULL;
1947                 }
1948         }
1949         
1950         return person;
1951 }
1952
1953 void addressbook_edit_reload_attr_list( void )
1954 {
1955         if (personeditdlg.entry_atname) {
1956                 combobox_unset_popdown_strings(GTK_COMBO_BOX_TEXT(personeditdlg.entry_atname));
1957                 if (prefs_common.addressbook_custom_attributes)
1958                         combobox_set_popdown_strings(GTK_COMBO_BOX_TEXT(personeditdlg.entry_atname),
1959                                         prefs_common.addressbook_custom_attributes);
1960         }
1961 }
1962
1963 /*
1964 * End of Source.
1965 */
1966