2007-07-10 [colin] 2.10.0cvs13
[claws.git] / src / editaddress.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2007 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 2 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, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.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/gtkwindow.h>
30 #include <gtk/gtksignal.h>
31 #include <gtk/gtklabel.h>
32 #include <gtk/gtkvbox.h>
33 #include <gtk/gtkentry.h>
34 #include <gtk/gtktable.h>
35
36 #include "mgutils.h"
37 #include "addressbook.h"
38 #include "addressitem.h"
39 #include "addritem.h"
40 #include "addrbook.h"
41 #include "manage_window.h"
42 #include "gtkutils.h"
43 #include "codeconv.h"
44 #include "editaddress.h"
45 #include "editaddress_other_attributes_ldap.h"
46 #include "prefs_common.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   = 0,
57         EMAIL_COL_ALIAS   = 1,
58         EMAIL_COL_REMARKS = 2
59 } PersonEditEMailColumnPos;
60
61 typedef enum {
62         ATTRIB_COL_NAME    = 0,
63         ATTRIB_COL_VALUE   = 1
64 } PersonEditAttribColumnPos;
65
66 #define EDITPERSON_WIDTH      520
67 #define EDITPERSON_HEIGHT     320
68
69 #define EMAIL_N_COLS          3
70 #define EMAIL_COL_WIDTH_EMAIL 180
71 #define EMAIL_COL_WIDTH_ALIAS 80
72
73 #define ATTRIB_N_COLS          2
74 #define ATTRIB_COL_WIDTH_NAME  120
75 #define ATTRIB_COL_WIDTH_VALUE 180
76
77 #define PAGE_BASIC             0
78 #define PAGE_EMAIL             1
79 #define PAGE_ATTRIBUTES        2
80
81 static gboolean addressbook_edit_person_close( gboolean cancelled );
82
83 static void edit_person_status_show( gchar *msg ) {
84         if( personeditdlg.statusbar != NULL ) {
85                 gtk_statusbar_pop( GTK_STATUSBAR(personeditdlg.statusbar), personeditdlg.status_cid );
86                 if( msg ) {
87                         gtk_statusbar_push( GTK_STATUSBAR(personeditdlg.statusbar), personeditdlg.status_cid, msg );
88                 }
89         }
90 }
91
92 static void edit_person_ok(GtkWidget *widget, gboolean *cancelled) {
93         *cancelled = FALSE;
94         if (prefs_common.addressbook_use_editaddress_dialog)
95                 gtk_main_quit();
96         else
97                 addressbook_edit_person_close( *cancelled );
98 }
99
100 static void edit_person_cancel(GtkWidget *widget, gboolean *cancelled) {
101         *cancelled = TRUE;
102         if (prefs_common.addressbook_use_editaddress_dialog)
103                 gtk_main_quit();
104         else
105                 addressbook_edit_person_close( *cancelled );
106 }
107
108 static gint edit_person_delete_event(GtkWidget *widget, GdkEventAny *event, gboolean *cancelled) {
109         *cancelled = TRUE;
110         if (prefs_common.addressbook_use_editaddress_dialog)
111                 gtk_main_quit();
112         else
113                 addressbook_edit_person_close( *cancelled );
114         return TRUE;
115 }
116
117 static gboolean edit_person_key_pressed(GtkWidget *widget, GdkEventKey *event, gboolean *cancelled) {
118         if (prefs_common.addressbook_use_editaddress_dialog) {
119         if (event && event->keyval == GDK_Escape) {
120                 *cancelled = TRUE;
121                 gtk_main_quit();
122         }
123         }
124         return FALSE;
125 }
126
127 static gchar *_title_new_ = NULL;
128 static gchar *_title_edit_ = NULL;
129
130 static void edit_person_set_widgets_title( gchar *text )
131 {
132         gchar *label = NULL;
133
134         g_return_if_fail( text != NULL );
135
136         gtk_label_set_text(GTK_LABEL(personeditdlg.title), "");
137         label = g_markup_printf_escaped("<b>%s</b>", text);
138         gtk_label_set_markup(GTK_LABEL(personeditdlg.title), label);
139         g_free(label);
140 }
141
142 static void edit_person_set_window_title( gint pageNum ) {
143         gchar *sTitle;
144
145         if( _title_new_ == NULL ) {
146                 _title_new_ = g_strdup( _("Add New Person") );
147                 _title_edit_ = g_strdup( _("Edit Person Details") );
148         }
149
150         if( pageNum == PAGE_BASIC ) {
151                 if( personeditdlg.editNew ) {
152                         if (prefs_common.addressbook_use_editaddress_dialog)
153                                 gtk_window_set_title( GTK_WINDOW(personeditdlg.container), _title_new_ );
154                         else
155                                 edit_person_set_widgets_title( _title_new_ );
156                 }
157                 else {
158                         if (prefs_common.addressbook_use_editaddress_dialog)
159                                 gtk_window_set_title( GTK_WINDOW(personeditdlg.container), _title_edit_ );
160                         else
161                                 edit_person_set_widgets_title( _title_edit_ );
162                 }
163         }
164         else {
165                 if( personeditdlg.entry_name == NULL ) {
166                         sTitle = g_strdup( _title_edit_ );
167                 }
168                 else {
169                         gchar *name;
170                         name = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_name), 0, -1 );
171                         sTitle = g_strdup_printf( "%s - %s", _title_edit_, name );
172                         g_free( name );
173                 }
174                 if (prefs_common.addressbook_use_editaddress_dialog)
175                         gtk_window_set_title( GTK_WINDOW(personeditdlg.container), sTitle );
176                 else
177                         edit_person_set_widgets_title( sTitle );
178                 g_free( sTitle );
179         }
180 }
181
182 static void edit_person_email_clear( gpointer data ) {
183         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_email), "" );
184         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_alias), "" );
185         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_remarks), "" );
186 }
187
188 static void edit_person_attrib_clear( gpointer data ) {
189         if (!personeditdlg.ldap) {
190                 gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atname), "" );
191                 gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atvalue), "" );
192         }
193 }
194
195 static void edit_person_switch_page( GtkNotebook *notebook, GtkNotebookPage *page,
196                                         gint pageNum, gpointer user_data)
197 {
198         edit_person_set_window_title( pageNum );
199         edit_person_status_show( "" );
200 }
201
202 /*
203 * Load clist with a copy of person's email addresses.
204 */
205 static void edit_person_load_email( ItemPerson *person ) {
206         GList *node = person->listEMail;
207         GtkCList *clist = GTK_CLIST(personeditdlg.clist_email);
208         gchar *text[ EMAIL_N_COLS ];
209         while( node ) {
210                 ItemEMail *emorig = ( ItemEMail * ) node->data;
211                 ItemEMail *email = addritem_copyfull_item_email( emorig );
212                 gint row;
213                 text[ EMAIL_COL_EMAIL   ] = email->address;
214                 text[ EMAIL_COL_ALIAS   ] = email->obj.name;
215                 text[ EMAIL_COL_REMARKS ] = email->remarks;
216
217                 row = gtk_clist_append( clist, text );
218                 gtk_clist_set_row_data( clist, row, email );
219                 node = g_list_next( node );
220         }
221 }
222
223 static void edit_person_email_list_selected( GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer data ) {
224         ItemEMail *email = gtk_clist_get_row_data( clist, row );
225         if( email ) {
226                 if( email->address )
227                         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_email), email->address );
228                 if( ADDRITEM_NAME(email) )
229                         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_alias), ADDRITEM_NAME(email) );
230                 if( email->remarks )
231                         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_remarks), email->remarks );
232                 if (!personeditdlg.read_only) {
233                         gtk_widget_set_sensitive(personeditdlg.email_del, TRUE);
234                         gtk_widget_set_sensitive(personeditdlg.email_up, row > 0);
235                         gtk_widget_set_sensitive(personeditdlg.email_down, gtk_clist_get_row_data(clist, row + 1) != NULL);
236                 }
237         } else {
238                 gtk_widget_set_sensitive(personeditdlg.email_del, FALSE);
239                 gtk_widget_set_sensitive(personeditdlg.email_up, FALSE);
240                 gtk_widget_set_sensitive(personeditdlg.email_down, FALSE);
241         }
242         personeditdlg.rowIndEMail = row;
243         edit_person_status_show( NULL );
244 }
245
246 static void edit_person_email_move( gint dir ) {
247         GtkCList *clist = GTK_CLIST(personeditdlg.clist_email);
248         gint row = personeditdlg.rowIndEMail + dir;
249         ItemEMail *email = gtk_clist_get_row_data( clist, row );
250         if( email ) {
251                 gtk_clist_row_move( clist, personeditdlg.rowIndEMail, row );
252                 personeditdlg.rowIndEMail = row;
253                 if (!personeditdlg.read_only) {
254                         gtk_widget_set_sensitive(personeditdlg.email_up, row > 0);
255                         gtk_widget_set_sensitive(personeditdlg.email_down, gtk_clist_get_row_data(clist, row + 1) != NULL);
256                 }
257         } else {
258                 gtk_widget_set_sensitive(personeditdlg.email_up, FALSE);
259                 gtk_widget_set_sensitive(personeditdlg.email_down, FALSE);
260         }
261         edit_person_email_clear( NULL );
262         edit_person_status_show( NULL );
263 }
264
265 static void edit_person_email_move_up( gpointer data ) {
266         edit_person_email_move( -1 );
267 }
268
269 static void edit_person_email_move_down( gpointer data ) {
270         edit_person_email_move( +1 );
271 }
272
273 static void edit_person_email_delete( gpointer data ) {
274         GtkCList *clist = GTK_CLIST(personeditdlg.clist_email);
275         gint row = personeditdlg.rowIndEMail;
276         ItemEMail *email = gtk_clist_get_row_data( clist, row );
277         edit_person_email_clear( NULL );
278         if( email ) {
279                 /* Remove list entry */
280                 gtk_clist_remove( clist, row );
281                 addritem_free_item_email( email );
282                 email = NULL;
283         }
284
285         /* Position hilite bar */
286         email = gtk_clist_get_row_data( clist, row );
287         if( ! email ) {
288                 personeditdlg.rowIndEMail = -1 + row;
289         }
290         if (!personeditdlg.read_only) {
291                 gtk_widget_set_sensitive(personeditdlg.email_del, gtk_clist_get_row_data(clist, 0) != NULL);
292                 gtk_widget_set_sensitive(personeditdlg.email_up, gtk_clist_get_row_data(clist, personeditdlg.rowIndEMail + 1) != NULL);
293                 gtk_widget_set_sensitive(personeditdlg.email_down, gtk_clist_get_row_data(clist, personeditdlg.rowIndEMail - 1) != NULL);
294         }
295         edit_person_status_show( NULL );
296 }
297
298 static ItemEMail *edit_person_email_edit( gboolean *error, ItemEMail *email ) {
299         ItemEMail *retVal = NULL;
300         gchar *sEmail, *sAlias, *sRemarks, *sEmail_;
301
302         *error = TRUE;
303         sEmail_ = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_email), 0, -1 );
304         sAlias = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_alias), 0, -1 );
305         sRemarks = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_remarks), 0, -1 );
306         sEmail = mgu_email_check_empty( sEmail_ );
307         g_free( sEmail_ );
308
309         if( sEmail ) {
310                 if( email == NULL ) {
311                         email = addritem_create_item_email();
312                 }
313                 addritem_email_set_address( email, sEmail );
314                 addritem_email_set_alias( email, sAlias );
315                 addritem_email_set_remarks( email, sRemarks );
316                 retVal = email;
317                 *error = FALSE;
318         }
319         else {
320                 edit_person_status_show( _( "An Email address must be supplied." ) );
321         }
322
323         g_free( sEmail );
324         g_free( sAlias );
325         g_free( sRemarks );
326
327         return retVal;
328 }
329
330 static void edit_person_email_modify( gpointer data ) {
331         gboolean errFlg = FALSE;
332         GtkCList *clist = GTK_CLIST(personeditdlg.clist_email);
333         gint row = personeditdlg.rowIndEMail;
334         ItemEMail *email = gtk_clist_get_row_data( clist, row );
335         if( email ) {
336                 edit_person_email_edit( &errFlg, email );
337                 if( ! errFlg ) {
338                         gtk_clist_set_text( clist, row, EMAIL_COL_EMAIL, email->address );
339                         gtk_clist_set_text( clist, row, EMAIL_COL_ALIAS, email->obj.name );
340                         gtk_clist_set_text( clist, row, EMAIL_COL_REMARKS, email->remarks );
341                         edit_person_email_clear( NULL );
342                 }
343         }
344 }
345
346 static void edit_person_email_add( gpointer data ) {
347         GtkCList *clist = GTK_CLIST(personeditdlg.clist_email);
348         gboolean errFlg = FALSE;
349         ItemEMail *email = NULL;
350         gint row = personeditdlg.rowIndEMail;
351         if( gtk_clist_get_row_data( clist, row ) == NULL ) row = 0;
352
353         email = edit_person_email_edit( &errFlg, NULL );
354         if( ! errFlg ) {
355                 gchar *text[ EMAIL_N_COLS ];
356                 text[ EMAIL_COL_EMAIL   ] = email->address;
357                 text[ EMAIL_COL_ALIAS   ] = email->obj.name;
358                 text[ EMAIL_COL_REMARKS ] = email->remarks;
359
360                 row = gtk_clist_insert( clist, 1 + row, text );
361                 gtk_clist_set_row_data( clist, row, email );
362                 gtk_clist_select_row( clist, row, 0 );
363                 edit_person_email_clear( NULL );
364         }
365 }
366
367 /*
368 * Comparison using cell contents (text in first column). Used for sort
369 * address index widget.
370 */
371 static gint edit_person_attrib_compare_func(
372         GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
373 {
374         GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
375         GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
376         gchar *name1 = NULL, *name2 = NULL;
377
378         if( cell1 ) name1 = cell1->u.text;
379         if( cell2 ) name2 = cell2->u.text;
380         if( ! name1 ) return ( name2 != NULL );
381         if( ! name2 ) return -1;
382         return g_utf8_collate( name1, name2 );
383 }
384
385 static gboolean list_find_attribute(const gchar *attr)
386 {
387         GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib);
388         UserAttribute *attrib;
389         gint row = 0;
390         while( (attrib = gtk_clist_get_row_data( clist, row )) ) {
391                 if (!g_ascii_strcasecmp(attrib->name, attr)) {
392                         gtk_clist_select_row(clist, row, 0);
393                         return TRUE;
394                 }
395                 row++;
396         }
397         return FALSE;
398 }
399
400 static gboolean list_find_email(const gchar *addr)
401 {
402         GtkCList *clist = GTK_CLIST(personeditdlg.clist_email);
403         ItemEMail *email;
404         gint row = 0;
405         while( (email = gtk_clist_get_row_data( clist, row )) ) {
406                 if (!g_ascii_strcasecmp(email->address, addr)) {
407                         gtk_clist_select_row(clist, row, 0);
408                         return TRUE;
409                 }
410                 row++;
411         }
412         return FALSE;
413 }
414
415 /*
416 * Load clist with a copy of person's email addresses.
417 */
418 static void edit_person_load_attrib( ItemPerson *person ) {
419         GList *node = person->listAttrib;
420         GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib);
421         gchar *text[ ATTRIB_N_COLS ];
422         while( node ) {
423                 UserAttribute *atorig = ( UserAttribute * ) node->data;
424                 UserAttribute *attrib = addritem_copy_attribute( atorig );
425                 gint row;
426                 text[ ATTRIB_COL_NAME  ] = attrib->name;
427                 text[ ATTRIB_COL_VALUE ] = attrib->value;
428
429                 row = gtk_clist_append( clist, text );
430                 gtk_clist_set_row_data( clist, row, attrib );
431                 node = g_list_next( node );
432         }
433 }
434
435 static void edit_person_attrib_list_selected( GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer data ) {
436         UserAttribute *attrib = gtk_clist_get_row_data( clist, row );
437         if( attrib && !personeditdlg.read_only && !personeditdlg.ldap ) {
438                 gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atname), attrib->name );
439                 gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atvalue), attrib->value );
440                 gtk_widget_set_sensitive(personeditdlg.attrib_del, TRUE);
441         } else {
442                 gtk_widget_set_sensitive(personeditdlg.attrib_del, FALSE);
443         }
444         personeditdlg.rowIndAttrib = row;
445         edit_person_status_show( NULL );
446 }
447
448 static void edit_person_attrib_delete( gpointer data ) {
449         GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib);
450         gint row = personeditdlg.rowIndAttrib;
451         UserAttribute *attrib = gtk_clist_get_row_data( clist, row );
452         edit_person_attrib_clear( NULL );
453         if( attrib ) {
454                 /* Remove list entry */
455                 gtk_clist_remove( clist, row );
456                 addritem_free_attribute( attrib );
457                 attrib = NULL;
458         }
459
460         /* Position hilite bar */
461         attrib = gtk_clist_get_row_data( clist, row );
462         if( ! attrib ) {
463                 personeditdlg.rowIndAttrib = -1 + row;
464         } 
465         
466         if (!personeditdlg.read_only && !personeditdlg.ldap)
467                 gtk_widget_set_sensitive(personeditdlg.attrib_del, gtk_clist_get_row_data(clist, 0) != NULL);
468         
469         edit_person_status_show( NULL );
470 }
471
472 static UserAttribute *edit_person_attrib_edit( gboolean *error, UserAttribute *attrib ) {
473         UserAttribute *retVal = NULL;
474         gchar *sName, *sValue, *sName_, *sValue_;
475
476         *error = TRUE;
477         sName_ = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_atname), 0, -1 );
478         sValue_ = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_atvalue), 0, -1 );
479         sName = mgu_email_check_empty( sName_ );
480         sValue = mgu_email_check_empty( sValue_ );
481         g_free( sName_ );
482         g_free( sValue_ );
483
484         if( sName && sValue ) {
485                 if( attrib == NULL ) {
486                         attrib = addritem_create_attribute();
487                 }
488                 addritem_attrib_set_name( attrib, sName );
489                 addritem_attrib_set_value( attrib, sValue );
490                 retVal = attrib;
491                 *error = FALSE;
492         }
493         else {
494                 edit_person_status_show( _( "A Name and Value must be supplied." ) );
495         }
496
497         g_free( sName );
498         g_free( sValue );
499
500         return retVal;
501 }
502
503 static void edit_person_attrib_modify( gpointer data ) {
504         gboolean errFlg = FALSE;
505         GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib);
506         gint row = personeditdlg.rowIndAttrib;
507         UserAttribute *attrib = gtk_clist_get_row_data( clist, row );
508         if( attrib ) {
509                 edit_person_attrib_edit( &errFlg, attrib );
510                 if( ! errFlg ) {
511                         gtk_clist_set_text( clist, row, ATTRIB_COL_NAME, attrib->name );
512                         gtk_clist_set_text( clist, row, ATTRIB_COL_VALUE, attrib->value );
513                         edit_person_attrib_clear( NULL );
514                 }
515         }
516 }
517
518 static void edit_person_attrib_add( gpointer data ) {
519         GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib);
520         gboolean errFlg = FALSE;
521         UserAttribute *attrib = NULL;
522         gint row = personeditdlg.rowIndAttrib;
523         if( gtk_clist_get_row_data( clist, row ) == NULL ) row = 0;
524
525         attrib = edit_person_attrib_edit( &errFlg, NULL );
526         if( ! errFlg ) {
527                 gchar *text[ EMAIL_N_COLS ];
528                 text[ ATTRIB_COL_NAME  ] = attrib->name;
529                 text[ ATTRIB_COL_VALUE ] = attrib->value;
530
531                 row = gtk_clist_insert( clist, 1 + row, text );
532                 gtk_clist_set_row_data( clist, row, attrib );
533                 gtk_clist_select_row( clist, row, 0 );
534                 edit_person_attrib_clear( NULL );
535         }
536 }
537
538 /*!
539  *\brief        Save Gtk object size to prefs dataset
540  */
541 static void edit_person_size_allocate_cb(GtkWidget *widget,
542                                          GtkAllocation *allocation)
543 {
544         g_return_if_fail(allocation != NULL);
545
546         prefs_common.addressbookeditpersonwin_width = allocation->width;
547         prefs_common.addressbookeditpersonwin_height = allocation->height;
548 }
549
550 /* build edit person widgets, return a pointer to the main container of the widgetset (a vbox) */
551 static GtkWidget* addressbook_edit_person_widgets_create( GtkWidget* container, gboolean *cancelled )
552 {
553         GtkWidget *vbox;
554         GtkWidget *vnbox;
555         GtkWidget *notebook;
556         GtkWidget *hbbox;
557         GtkWidget *ok_btn;
558         GtkWidget *cancel_btn;
559
560         vbox = gtk_vbox_new(FALSE, 4);
561         /* gtk_container_set_border_width(GTK_CONTAINER(vbox), BORDER_WIDTH); */
562         gtk_widget_show(vbox);
563         gtk_container_add(GTK_CONTAINER(container), vbox);
564
565         vnbox = gtk_vbox_new(FALSE, 4);
566         gtk_container_set_border_width(GTK_CONTAINER(vnbox), 4);
567         gtk_widget_show(vnbox);
568         gtk_box_pack_start(GTK_BOX(vbox), vnbox, TRUE, TRUE, 0);
569
570         /* Notebook */
571         notebook = gtk_notebook_new();
572         gtk_widget_show(notebook);
573         gtk_box_pack_start(GTK_BOX(vnbox), notebook, TRUE, TRUE, 0);
574         gtk_container_set_border_width(GTK_CONTAINER(notebook), 6);
575
576         /* Button panel */
577         if (prefs_common.addressbook_use_editaddress_dialog)
578         gtkut_stock_button_set_create(&hbbox, &cancel_btn, GTK_STOCK_CANCEL,
579                                       &ok_btn, GTK_STOCK_OK,
580                                       NULL, NULL);
581         else
582                 gtkut_stock_with_text_button_set_create(&hbbox,
583                                           &cancel_btn, GTK_STOCK_CANCEL, _("Discard"),
584                                       &ok_btn, GTK_STOCK_OK, _("Apply"),
585                                       NULL, NULL, NULL);
586         gtk_box_pack_end(GTK_BOX(vnbox), hbbox, FALSE, FALSE, 0);
587         gtk_widget_grab_default(ok_btn);
588
589         g_signal_connect(G_OBJECT(ok_btn), "clicked",
590                          G_CALLBACK(edit_person_ok), cancelled);
591         g_signal_connect(G_OBJECT(cancel_btn), "clicked",
592                          G_CALLBACK(edit_person_cancel), cancelled);
593         g_signal_connect(G_OBJECT(notebook), "switch_page",
594                          G_CALLBACK(edit_person_switch_page), NULL );
595
596         gtk_widget_show_all(vbox);
597
598         personeditdlg.notebook   = notebook;
599         personeditdlg.ok_btn     = ok_btn;
600         personeditdlg.cancel_btn = cancel_btn;
601
602         return vbox;
603 }
604
605 static void addressbook_edit_person_dialog_create( gboolean *cancelled ) {
606         GtkWidget *window;
607         GtkWidget *hsbox;
608         GtkWidget *vbox;
609         GtkWidget *statusbar;
610         static GdkGeometry geometry;
611
612         window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "editaddress");
613         /* gtk_container_set_border_width(GTK_CONTAINER(window), 0); */
614         gtk_window_set_title(GTK_WINDOW(window), _("Edit Person Data"));
615         gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
616         gtk_window_set_modal(GTK_WINDOW(window), TRUE); 
617         g_signal_connect(G_OBJECT(window), "delete_event",
618                          G_CALLBACK(edit_person_delete_event),
619                          cancelled);
620         g_signal_connect(G_OBJECT(window), "size_allocate",
621                          G_CALLBACK(edit_person_size_allocate_cb),
622                         cancelled);
623         g_signal_connect(G_OBJECT(window), "key_press_event",
624                          G_CALLBACK(edit_person_key_pressed),
625                          cancelled);
626
627         vbox = addressbook_edit_person_widgets_create(window, cancelled);
628
629         /* Status line */
630         hsbox = gtk_hbox_new(FALSE, 0);
631         gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
632         statusbar = gtk_statusbar_new();
633         gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
634
635         if (!geometry.min_height) {
636                 geometry.min_width = EDITPERSON_WIDTH;
637                 geometry.min_height = EDITPERSON_HEIGHT;
638         }
639
640         gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
641                                       GDK_HINT_MIN_SIZE);
642         gtk_widget_set_size_request(window, prefs_common.addressbookeditpersonwin_width,
643                                     prefs_common.addressbookeditpersonwin_height);
644
645         personeditdlg.container  = window;
646         personeditdlg.statusbar  = statusbar;
647         personeditdlg.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Edit Person Dialog" );
648
649 }
650
651 /* parent must be a box */
652 static void addressbook_edit_person_widgetset_create( GtkWidget *parent, gboolean *cancelled )
653 {
654         GtkWidget *vbox;
655         GtkWidget *label;
656
657         if ( parent == NULL )
658                 g_warning("addressbook_edit_person_widgetset_create: parent is NULL");
659
660         vbox = gtk_vbox_new(FALSE, 0);
661         gtk_box_pack_end(GTK_BOX(parent), vbox, TRUE, TRUE, 0);
662
663         label = gtk_label_new(_("Edit Person Data"));
664         gtk_label_set_justify( GTK_LABEL(label), GTK_JUSTIFY_CENTER);
665         gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
666
667         addressbook_edit_person_widgets_create(vbox, cancelled);
668
669         gtk_widget_set_size_request(vbox, EDITPERSON_WIDTH, EDITPERSON_HEIGHT);
670
671         personeditdlg.container = vbox;
672         personeditdlg.title = label;
673         personeditdlg.statusbar  = NULL;
674         personeditdlg.status_cid = 0;
675 }
676
677 void addressbook_edit_person_widgetset_hide( void )
678 {
679         if ( personeditdlg.container )
680                 gtk_widget_hide( personeditdlg.container );
681 }
682
683 static void addressbook_edit_person_page_basic( gint pageNum, gchar *pageLbl ) {
684         GtkWidget *vbox;
685         GtkWidget *table;
686         GtkWidget *label;
687         GtkWidget *entry_name;
688         GtkWidget *entry_fn;
689         GtkWidget *entry_ln;
690         GtkWidget *entry_nn;
691         const gchar *locale;
692         gint top = 0;
693
694         vbox = gtk_vbox_new( FALSE, 8 );
695         gtk_widget_show( vbox );
696         gtk_container_add( GTK_CONTAINER( personeditdlg.notebook ), vbox );
697         gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
698
699         label = gtk_label_new_with_mnemonic( pageLbl );
700         gtk_widget_show( label );
701         gtk_notebook_set_tab_label(
702                 GTK_NOTEBOOK( personeditdlg.notebook ),
703                 gtk_notebook_get_nth_page( GTK_NOTEBOOK( personeditdlg.notebook ), pageNum ), label );
704
705         table = gtk_table_new( 4, 3, FALSE);
706         gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
707         gtk_container_set_border_width( GTK_CONTAINER(table), 8 );
708         gtk_table_set_row_spacings(GTK_TABLE(table), 8);
709         gtk_table_set_col_spacings(GTK_TABLE(table), 8);
710
711 #define ATTACH_ROW(text, entry) \
712 { \
713         label = gtk_label_new(text); \
714         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), \
715                          GTK_FILL, 0, 0, 0); \
716         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); \
717  \
718         entry = gtk_entry_new(); \
719         gtk_table_attach(GTK_TABLE(table), entry, 1, 2, top, (top + 1), \
720                          GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); \
721         top++; \
722 }
723
724         ATTACH_ROW(_("Display Name"), entry_name);
725         locale = conv_get_current_locale();
726         if (locale &&
727             (!g_ascii_strncasecmp(locale, "ja", 2) ||
728              !g_ascii_strncasecmp(locale, "ko", 2) ||
729              !g_ascii_strncasecmp(locale, "zh", 2))) {
730                 ATTACH_ROW(_("Last Name"), entry_ln);
731                 ATTACH_ROW(_("First Name"), entry_fn);
732         } else {
733                 ATTACH_ROW(_("First Name"), entry_fn);
734                 ATTACH_ROW(_("Last Name"), entry_ln);
735         }
736         ATTACH_ROW(_("Nickname"), entry_nn);
737
738 #undef ATTACH_ROW
739
740         gtk_widget_show_all(vbox);
741
742         personeditdlg.entry_name  = entry_name;
743         personeditdlg.entry_first = entry_fn;
744         personeditdlg.entry_last  = entry_ln;
745         personeditdlg.entry_nick  = entry_nn;
746 }
747
748 static gboolean email_adding = FALSE, email_saving = FALSE;
749
750 static void edit_person_entry_email_changed (GtkWidget *entry, gpointer data)
751 {
752         gboolean non_empty = gtk_clist_get_row_data(GTK_CLIST(personeditdlg.clist_email), 0) != NULL;
753
754         if (personeditdlg.read_only)
755                 return;
756
757         if (gtk_entry_get_text(GTK_ENTRY(personeditdlg.entry_email)) == NULL
758         ||  strlen(gtk_entry_get_text(GTK_ENTRY(personeditdlg.entry_email))) == 0) {
759                 gtk_widget_set_sensitive(personeditdlg.email_add,FALSE);
760                 gtk_widget_set_sensitive(personeditdlg.email_mod,FALSE);
761                 email_adding = FALSE;
762                 email_saving = FALSE;
763         } else if (list_find_email(gtk_entry_get_text(GTK_ENTRY(personeditdlg.entry_email)))) {
764                 gtk_widget_set_sensitive(personeditdlg.email_add,FALSE);
765                 gtk_widget_set_sensitive(personeditdlg.email_mod,non_empty);
766                 email_adding = FALSE;
767                 email_saving = non_empty;
768         } else {
769                 gtk_widget_set_sensitive(personeditdlg.email_add,TRUE);
770                 gtk_widget_set_sensitive(personeditdlg.email_mod,non_empty);
771                 email_adding = TRUE;
772                 email_saving = non_empty;
773         }
774 }
775
776 static gboolean edit_person_entry_email_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
777 {
778         if (event && event->keyval == GDK_Return) {
779                 if (email_saving)
780                         edit_person_email_modify(NULL);         
781                 else if (email_adding)
782                         edit_person_email_add(NULL);
783         }
784         return FALSE;
785 }
786
787
788 static void addressbook_edit_person_page_email( gint pageNum, gchar *pageLbl ) {
789         GtkWidget *vbox;
790         GtkWidget *hbox;
791         GtkWidget *vboxl;
792         GtkWidget *vboxb;
793         GtkWidget *vbuttonbox;
794         GtkWidget *buttonUp;
795         GtkWidget *buttonDown;
796         GtkWidget *buttonDel;
797         GtkWidget *buttonMod;
798         GtkWidget *buttonAdd;
799
800         GtkWidget *table;
801         GtkWidget *label;
802         GtkWidget *clist_swin;
803         GtkWidget *clist;
804         GtkWidget *entry_email;
805         GtkWidget *entry_alias;
806         GtkWidget *entry_remarks;
807         gint top;
808
809         gchar *titles[ EMAIL_N_COLS ];
810         gint i;
811
812         titles[ EMAIL_COL_EMAIL   ] = _("Email Address");
813         titles[ EMAIL_COL_ALIAS   ] = _("Alias");
814         titles[ EMAIL_COL_REMARKS ] = _("Remarks");
815
816         vbox = gtk_vbox_new( FALSE, 8 );
817         gtk_widget_show( vbox );
818         gtk_container_add( GTK_CONTAINER( personeditdlg.notebook ), vbox );
819         gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
820
821         label = gtk_label_new_with_mnemonic( pageLbl );
822         gtk_widget_show( label );
823         gtk_notebook_set_tab_label(
824                 GTK_NOTEBOOK( personeditdlg.notebook ),
825                 gtk_notebook_get_nth_page( GTK_NOTEBOOK( personeditdlg.notebook ), pageNum ), label );
826
827         /* Split into two areas */
828         hbox = gtk_hbox_new( FALSE, 0 );
829         gtk_container_add( GTK_CONTAINER( vbox ), hbox );
830
831         /* Address list */
832         vboxl = gtk_vbox_new( FALSE, 4 );
833         gtk_container_add( GTK_CONTAINER( hbox ), vboxl );
834         gtk_container_set_border_width( GTK_CONTAINER(vboxl), 4 );
835
836         clist_swin = gtk_scrolled_window_new( NULL, NULL );
837         gtk_container_add( GTK_CONTAINER(vboxl), clist_swin );
838         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
839                                        GTK_POLICY_AUTOMATIC,
840                                        GTK_POLICY_AUTOMATIC);
841
842         clist = gtk_clist_new_with_titles( EMAIL_N_COLS, titles );
843         gtk_container_add( GTK_CONTAINER(clist_swin), clist );
844         gtk_clist_set_selection_mode( GTK_CLIST(clist), GTK_SELECTION_BROWSE );
845         gtk_clist_set_column_width( GTK_CLIST(clist), EMAIL_COL_EMAIL, EMAIL_COL_WIDTH_EMAIL );
846         gtk_clist_set_column_width( GTK_CLIST(clist), EMAIL_COL_ALIAS, EMAIL_COL_WIDTH_ALIAS );
847
848         for( i = 0; i < EMAIL_N_COLS; i++ )
849                 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button, GTK_CAN_FOCUS);
850
851         /* Data entry area */
852         table = gtk_table_new( 4, 2, FALSE);
853         gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0);
854         gtk_container_set_border_width( GTK_CONTAINER(table), 4 );
855         gtk_table_set_row_spacings(GTK_TABLE(table), 4);
856         gtk_table_set_col_spacings(GTK_TABLE(table), 4);
857
858         /* First row */
859         top = 0;
860         label = gtk_label_new(_("Email Address"));
861         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
862         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
863
864         entry_email = gtk_entry_new();
865         gtk_table_attach(GTK_TABLE(table), entry_email, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
866
867         /* Next row */
868         ++top;
869         label = gtk_label_new(_("Alias"));
870         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
871         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
872
873         entry_alias = gtk_entry_new();
874         gtk_table_attach(GTK_TABLE(table), entry_alias, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
875
876         /* Next row */
877         ++top;
878         label = gtk_label_new(_("Remarks"));
879         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
880         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
881
882         entry_remarks = gtk_entry_new();
883         gtk_table_attach(GTK_TABLE(table), entry_remarks, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
884
885         /* Button box */
886         vboxb = gtk_vbox_new( FALSE, 4 );
887         gtk_box_pack_start(GTK_BOX(hbox), vboxb, FALSE, FALSE, 2);
888
889         vbuttonbox = gtk_vbutton_box_new();
890         gtk_button_box_set_layout( GTK_BUTTON_BOX(vbuttonbox), GTK_BUTTONBOX_START );
891         gtk_box_set_spacing( GTK_BOX(vbuttonbox), 8 );
892         gtk_container_set_border_width( GTK_CONTAINER(vbuttonbox), 4 );
893         gtk_container_add( GTK_CONTAINER(vboxb), vbuttonbox );
894
895         /* Buttons */
896         buttonUp = gtk_button_new_from_stock(GTK_STOCK_GO_UP);
897         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonUp );
898
899         buttonDown = gtk_button_new_from_stock(GTK_STOCK_GO_DOWN);
900         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDown );
901
902         buttonDel = gtk_button_new_from_stock(GTK_STOCK_DELETE);
903         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDel );
904
905         buttonMod = gtk_button_new_from_stock(GTK_STOCK_SAVE);
906         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonMod );
907
908         buttonAdd = gtk_button_new_from_stock(GTK_STOCK_ADD);
909         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonAdd );
910
911         gtk_widget_show_all(vbox);
912
913         /* Event handlers */
914         g_signal_connect( G_OBJECT(clist), "select_row",
915                           G_CALLBACK( edit_person_email_list_selected), NULL );
916         g_signal_connect( G_OBJECT(buttonUp), "clicked",
917                           G_CALLBACK( edit_person_email_move_up ), NULL );
918         g_signal_connect( G_OBJECT(buttonDown), "clicked",
919                           G_CALLBACK( edit_person_email_move_down ), NULL );
920         g_signal_connect( G_OBJECT(buttonDel), "clicked",
921                           G_CALLBACK( edit_person_email_delete ), NULL );
922         g_signal_connect( G_OBJECT(buttonMod), "clicked",
923                           G_CALLBACK( edit_person_email_modify ), NULL );
924         g_signal_connect( G_OBJECT(buttonAdd), "clicked",
925                           G_CALLBACK( edit_person_email_add ), NULL );
926         g_signal_connect(G_OBJECT(entry_email), "changed",
927                          G_CALLBACK(edit_person_entry_email_changed), NULL);
928         g_signal_connect(G_OBJECT(entry_email), "key_press_event",
929                          G_CALLBACK(edit_person_entry_email_pressed), NULL);
930         g_signal_connect(G_OBJECT(entry_alias), "key_press_event",
931                          G_CALLBACK(edit_person_entry_email_pressed), NULL);
932         g_signal_connect(G_OBJECT(entry_remarks), "key_press_event",
933                          G_CALLBACK(edit_person_entry_email_pressed), NULL);
934
935         personeditdlg.clist_email   = clist;
936         personeditdlg.entry_email   = entry_email;
937         personeditdlg.entry_alias   = entry_alias;
938         personeditdlg.entry_remarks = entry_remarks;
939         personeditdlg.email_up = buttonUp;
940         personeditdlg.email_down = buttonDown;
941         personeditdlg.email_del = buttonDel;
942         personeditdlg.email_mod = buttonMod;
943         personeditdlg.email_add = buttonAdd;
944 }
945
946 static gboolean attrib_adding = FALSE, attrib_saving = FALSE;
947
948 static void edit_person_entry_att_changed (GtkWidget *entry, gpointer data)
949 {
950         gboolean non_empty = gtk_clist_get_row_data(GTK_CLIST(personeditdlg.clist_attrib), 0) != NULL;
951
952         if (personeditdlg.read_only || personeditdlg.ldap)
953                 return;
954
955         if (gtk_entry_get_text(GTK_ENTRY(personeditdlg.entry_atname)) == NULL
956         ||  strlen(gtk_entry_get_text(GTK_ENTRY(personeditdlg.entry_atname))) == 0) {
957                 gtk_widget_set_sensitive(personeditdlg.attrib_add,FALSE);
958                 gtk_widget_set_sensitive(personeditdlg.attrib_mod,FALSE);
959                 attrib_adding = FALSE;
960                 attrib_saving = FALSE;
961         } else if (list_find_attribute(gtk_entry_get_text(GTK_ENTRY(personeditdlg.entry_atname)))) {
962                 gtk_widget_set_sensitive(personeditdlg.attrib_add,FALSE);
963                 gtk_widget_set_sensitive(personeditdlg.attrib_mod,non_empty);
964                 attrib_adding = FALSE;
965                 attrib_saving = non_empty;
966         } else {
967                 gtk_widget_set_sensitive(personeditdlg.attrib_add,TRUE);
968                 gtk_widget_set_sensitive(personeditdlg.attrib_mod,non_empty);
969                 attrib_adding = TRUE;
970                 attrib_saving = non_empty;
971         }
972 }
973
974 static gboolean edit_person_entry_att_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
975 {
976         if (event && event->keyval == GDK_Return) {
977                 if (attrib_saving)
978                         edit_person_attrib_modify(NULL);
979                 else if (attrib_adding)
980                         edit_person_attrib_add(NULL);
981         }
982         return FALSE;
983 }
984
985 static void addressbook_edit_person_page_attrib( gint pageNum, gchar *pageLbl ) {
986         GtkWidget *vbox;
987         GtkWidget *hbox;
988         GtkWidget *vboxl;
989         GtkWidget *vboxb;
990         GtkWidget *vbuttonbox;
991         GtkWidget *buttonDel;
992         GtkWidget *buttonMod;
993         GtkWidget *buttonAdd;
994
995         GtkWidget *table;
996         GtkWidget *label;
997         GtkWidget *clist_swin;
998         GtkWidget *clist;
999         GtkWidget *entry_name;
1000         GtkWidget *entry_value;
1001         gint top;
1002
1003         gchar *titles[ ATTRIB_N_COLS ];
1004         gint i;
1005
1006         titles[ ATTRIB_COL_NAME  ] = _("Name");
1007         titles[ ATTRIB_COL_VALUE ] = _("Value");
1008
1009         vbox = gtk_vbox_new( FALSE, 8 );
1010         gtk_widget_show( vbox );
1011         gtk_container_add( GTK_CONTAINER( personeditdlg.notebook ), vbox );
1012         gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
1013
1014         label = gtk_label_new_with_mnemonic( pageLbl );
1015         gtk_widget_show( label );
1016         gtk_notebook_set_tab_label(
1017                 GTK_NOTEBOOK( personeditdlg.notebook ),
1018                 gtk_notebook_get_nth_page( GTK_NOTEBOOK( personeditdlg.notebook ), pageNum ), label );
1019
1020         /* Split into two areas */
1021         hbox = gtk_hbox_new( FALSE, 0 );
1022         gtk_container_add( GTK_CONTAINER( vbox ), hbox );
1023
1024         /* Attribute list */
1025         vboxl = gtk_vbox_new( FALSE, 4 );
1026         gtk_container_add( GTK_CONTAINER( hbox ), vboxl );
1027         gtk_container_set_border_width( GTK_CONTAINER(vboxl), 4 );
1028
1029         clist_swin = gtk_scrolled_window_new( NULL, NULL );
1030         gtk_container_add( GTK_CONTAINER(vboxl), clist_swin );
1031         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
1032                                        GTK_POLICY_AUTOMATIC,
1033                                        GTK_POLICY_AUTOMATIC);
1034
1035         clist = gtk_clist_new_with_titles( ATTRIB_N_COLS, titles );
1036         gtk_container_add( GTK_CONTAINER(clist_swin), clist );
1037         gtk_clist_set_selection_mode( GTK_CLIST(clist), GTK_SELECTION_BROWSE );
1038         gtk_clist_set_column_width( GTK_CLIST(clist), ATTRIB_COL_NAME, ATTRIB_COL_WIDTH_NAME );
1039         gtk_clist_set_column_width( GTK_CLIST(clist), ATTRIB_COL_VALUE, ATTRIB_COL_WIDTH_VALUE );
1040         gtk_clist_set_compare_func( GTK_CLIST(clist), edit_person_attrib_compare_func );
1041         gtk_clist_set_auto_sort( GTK_CLIST(clist), TRUE );
1042
1043         for( i = 0; i < ATTRIB_N_COLS; i++ )
1044                 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button, GTK_CAN_FOCUS);
1045
1046         /* Data entry area */
1047         table = gtk_table_new( 4, 2, FALSE);
1048         gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0);
1049         gtk_container_set_border_width( GTK_CONTAINER(table), 4 );
1050         gtk_table_set_row_spacings(GTK_TABLE(table), 4);
1051         gtk_table_set_col_spacings(GTK_TABLE(table), 4);
1052
1053         /* First row */
1054         top = 0;
1055         label = gtk_label_new(_("Name"));
1056         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
1057         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1058
1059         entry_name = gtk_entry_new();
1060         gtk_table_attach(GTK_TABLE(table), entry_name, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
1061
1062         /* Next row */
1063         ++top;
1064         label = gtk_label_new(_("Value"));
1065         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
1066         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1067
1068         entry_value = gtk_entry_new();
1069         gtk_table_attach(GTK_TABLE(table), entry_value, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
1070
1071         /* Button box */
1072         vboxb = gtk_vbox_new( FALSE, 4 );
1073         gtk_box_pack_start(GTK_BOX(hbox), vboxb, FALSE, FALSE, 2);
1074
1075         vbuttonbox = gtk_vbutton_box_new();
1076         gtk_button_box_set_layout( GTK_BUTTON_BOX(vbuttonbox), GTK_BUTTONBOX_START );
1077         gtk_box_set_spacing( GTK_BOX(vbuttonbox), 8 );
1078         gtk_container_set_border_width( GTK_CONTAINER(vbuttonbox), 4 );
1079         gtk_container_add( GTK_CONTAINER(vboxb), vbuttonbox );
1080
1081         /* Buttons */
1082         buttonDel = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1083         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDel );
1084
1085         buttonMod = gtk_button_new_from_stock(GTK_STOCK_SAVE);
1086         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonMod );
1087
1088         buttonAdd = gtk_button_new_from_stock(GTK_STOCK_ADD);
1089         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonAdd );
1090         
1091         gtk_widget_set_sensitive(buttonDel,FALSE);
1092         gtk_widget_set_sensitive(buttonMod,FALSE);
1093         gtk_widget_set_sensitive(buttonAdd,FALSE);
1094
1095         gtk_widget_show_all(vbox);
1096
1097         /* Event handlers */
1098         g_signal_connect( G_OBJECT(clist), "select_row",
1099                           G_CALLBACK( edit_person_attrib_list_selected), NULL );
1100         g_signal_connect( G_OBJECT(buttonDel), "clicked",
1101                           G_CALLBACK( edit_person_attrib_delete ), NULL );
1102         g_signal_connect( G_OBJECT(buttonMod), "clicked",
1103                           G_CALLBACK( edit_person_attrib_modify ), NULL );
1104         g_signal_connect( G_OBJECT(buttonAdd), "clicked",
1105                           G_CALLBACK( edit_person_attrib_add ), NULL );
1106         g_signal_connect(G_OBJECT(entry_name), "changed",
1107                          G_CALLBACK(edit_person_entry_att_changed), NULL);
1108         g_signal_connect(G_OBJECT(entry_name), "key_press_event",
1109                          G_CALLBACK(edit_person_entry_att_pressed), NULL);
1110         g_signal_connect(G_OBJECT(entry_value), "key_press_event",
1111                          G_CALLBACK(edit_person_entry_att_pressed), NULL);
1112
1113         personeditdlg.clist_attrib  = clist;
1114         personeditdlg.entry_atname  = entry_name;
1115         personeditdlg.entry_atvalue = entry_value;
1116         personeditdlg.attrib_add = buttonAdd;
1117         personeditdlg.attrib_del = buttonDel;
1118         personeditdlg.attrib_mod = buttonMod;
1119 }
1120
1121 static void addressbook_edit_person_create( GtkWidget *parent, gboolean *cancelled ) {
1122         if (prefs_common.addressbook_use_editaddress_dialog)
1123                 addressbook_edit_person_dialog_create( cancelled );
1124         else
1125                 addressbook_edit_person_widgetset_create( parent, cancelled );
1126         addressbook_edit_person_page_basic( PAGE_BASIC, _( "_User Data" ) );
1127         addressbook_edit_person_page_email( PAGE_EMAIL, _( "_Email Addresses" ) );
1128 #ifdef USE_LDAP
1129         if (personeditdlg.ldap)
1130                 addressbook_edit_person_page_attrib_ldap(&personeditdlg, PAGE_ATTRIBUTES, _("O_ther Attributes"));
1131         else
1132 #endif
1133                 addressbook_edit_person_page_attrib( PAGE_ATTRIBUTES, _( "O_ther Attributes" ) );
1134         gtk_widget_show_all( personeditdlg.container );
1135 }
1136
1137 /*
1138 * Return list of email items.
1139 */
1140 static GList *edit_person_build_email_list() {
1141         GtkCList *clist = GTK_CLIST(personeditdlg.clist_email);
1142         GList *listEMail = NULL;
1143         ItemEMail *email;
1144         gint row = 0;
1145         while( (email = gtk_clist_get_row_data( clist, row )) ) {
1146                 listEMail = g_list_append( listEMail, email );
1147                 row++;
1148         }
1149         return listEMail;
1150 }
1151
1152 /*
1153 * Return list of attributes.
1154 */
1155 static GList *edit_person_build_attrib_list() {
1156         GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib);
1157         GList *listAttrib = NULL;
1158         UserAttribute *attrib;
1159         gint row = 0;
1160         while( (attrib = gtk_clist_get_row_data( clist, row )) ) {
1161                 listAttrib = g_list_append( listAttrib, attrib );
1162                 row++;
1163         }
1164         return listAttrib;
1165 }
1166
1167 static void update_sensitivity(void)
1168 {
1169         gtk_widget_set_sensitive(personeditdlg.entry_name,    !personeditdlg.read_only);
1170         gtk_widget_set_sensitive(personeditdlg.entry_first,   !personeditdlg.read_only);
1171         gtk_widget_set_sensitive(personeditdlg.entry_last,    !personeditdlg.read_only);
1172         gtk_widget_set_sensitive(personeditdlg.entry_nick,    !personeditdlg.read_only && !personeditdlg.ldap);
1173         gtk_widget_set_sensitive(personeditdlg.entry_email,   !personeditdlg.read_only);
1174         gtk_widget_set_sensitive(personeditdlg.entry_alias,   !personeditdlg.read_only && !personeditdlg.ldap);
1175         gtk_widget_set_sensitive(personeditdlg.entry_remarks, !personeditdlg.read_only && !personeditdlg.ldap);
1176         gtk_widget_set_sensitive(personeditdlg.email_up,      !personeditdlg.read_only);
1177         gtk_widget_set_sensitive(personeditdlg.email_down,    !personeditdlg.read_only);
1178         gtk_widget_set_sensitive(personeditdlg.email_del,     !personeditdlg.read_only);
1179         gtk_widget_set_sensitive(personeditdlg.email_mod,     !personeditdlg.read_only);
1180         gtk_widget_set_sensitive(personeditdlg.email_add,     !personeditdlg.read_only);
1181         gtk_widget_set_sensitive(personeditdlg.entry_atname,  !personeditdlg.read_only);
1182         gtk_widget_set_sensitive(personeditdlg.entry_atvalue, !personeditdlg.read_only);
1183         gtk_widget_set_sensitive(personeditdlg.attrib_add,    !personeditdlg.read_only);
1184         gtk_widget_set_sensitive(personeditdlg.attrib_del,    !personeditdlg.read_only);
1185         gtk_widget_set_sensitive(personeditdlg.attrib_mod,    !personeditdlg.read_only);
1186 }
1187
1188 static void addressbook_edit_person_flush_transient( void )
1189 {
1190         ItemPerson *person = current_person;
1191         EditAddressPostUpdateCallback callback = edit_person_close_post_update_cb;
1192
1193         /* reset transient data */
1194         current_abf = NULL;
1195         current_person = NULL;
1196         current_parent_folder = NULL;
1197         edit_person_close_post_update_cb = NULL;
1198
1199         /* post action to perform on addressbook side */
1200         if (callback)
1201                 callback( person );
1202 }
1203
1204 void addressbook_edit_person_invalidate( AddressBookFile *abf, ItemFolder *parent_folder,
1205                                                                                  ItemPerson *person )
1206 {
1207         if (current_abf == NULL &&
1208                 current_person == NULL &&
1209                 current_parent_folder == NULL)
1210                 /* edit address form is already hidden */
1211                 return;
1212
1213         /* unconditional invalidation or invalidating the currently edited item */
1214         if ( ( abf == NULL && person == NULL && parent_folder == NULL )
1215                 || (current_abf == abf ||
1216                         current_person == person ||
1217                         current_parent_folder == parent_folder))
1218                 addressbook_edit_person_close( TRUE );
1219 }
1220
1221 static gboolean addressbook_edit_person_close( gboolean cancelled )
1222 {
1223         GList *listEMail = NULL;
1224         GList *listAttrib = NULL;
1225         gchar *cn = NULL;
1226
1227         listEMail = edit_person_build_email_list();
1228         listAttrib = edit_person_build_attrib_list();
1229         if( cancelled ) {
1230                 addritem_free_list_email( listEMail );
1231                 addritem_free_list_attribute( listAttrib );
1232                 gtk_clist_clear( GTK_CLIST(personeditdlg.clist_email) );
1233                 gtk_clist_clear( GTK_CLIST(personeditdlg.clist_attrib) );
1234
1235                 if (!prefs_common.addressbook_use_editaddress_dialog)
1236                         gtk_widget_hide( personeditdlg.container );
1237
1238                 /* no callback, as we're discarding the form */
1239                 edit_person_close_post_update_cb = NULL;
1240                 addressbook_edit_person_flush_transient();
1241
1242                 /* set focus to the address list (this is done by the post_update_cb usually) */
1243                 addressbook_address_list_set_focus();
1244                 return FALSE;
1245         }
1246
1247         cn = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_name), 0, -1 );
1248         if( current_person && current_abf ) {
1249                 /* Update email/attribute list for existing current_person */
1250                 addrbook_update_address_list( current_abf, current_person, listEMail );
1251                 addrbook_update_attrib_list( current_abf, current_person, listAttrib );
1252         }
1253         else {
1254                 /* Create new current_person and email/attribute list */
1255                 if( cn == NULL || *cn == '\0' ) {
1256                         /* Wasting our time */
1257                         if( listEMail == NULL && listAttrib == NULL ) cancelled = TRUE;
1258                 }
1259                 if( ! cancelled && current_abf ) {
1260                         current_person = addrbook_add_address_list( current_abf, current_parent_folder, listEMail );
1261                         addrbook_add_attrib_list( current_abf, current_person, listAttrib );
1262                 }
1263         }
1264         listEMail = NULL;
1265         listAttrib = NULL;
1266
1267         if( ! cancelled ) {
1268                 /* Set current_person stuff */
1269                 gchar *name;
1270                 addritem_person_set_common_name( current_person, cn );
1271                 name = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_first), 0, -1 );
1272                 addritem_person_set_first_name( current_person, name );
1273                 g_free( name );
1274                 name = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_last), 0, -1 );
1275                 addritem_person_set_last_name( current_person, name );
1276                 g_free( name );
1277                 name = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_nick), 0, -1 );
1278                 addritem_person_set_nick_name( current_person, name );
1279                 g_free( name );
1280         }
1281         g_free( cn );
1282
1283         gtk_clist_clear( GTK_CLIST(personeditdlg.clist_email) );
1284         gtk_clist_clear( GTK_CLIST(personeditdlg.clist_attrib) );
1285
1286         if (!prefs_common.addressbook_use_editaddress_dialog)
1287                 gtk_widget_hide( personeditdlg.container );
1288
1289         addressbook_edit_person_flush_transient();
1290
1291         return TRUE;
1292 }
1293  
1294 /*
1295 * Edit person.
1296 * Enter: abf    Address book.
1297 *        parent Parent folder for person (or NULL if adding to root folder). Argument is
1298 *               only required for new objects).
1299 *        person Person to edit, or NULL for a new person object.
1300 *        pgMail If TRUE, E-Mail page will be activated.
1301 * Return: Edited object, or NULL if cancelled.
1302 */
1303 ItemPerson *addressbook_edit_person( AddressBookFile *abf, ItemFolder *parent_folder, ItemPerson *person,
1304                                                                          gboolean pgMail, GtkWidget *parent_container,
1305                                                                          void (*post_update_cb) (ItemPerson *person),
1306                                                                          gboolean get_focus) {
1307         static gboolean cancelled;
1308
1309         /* set transient data */
1310         current_abf = abf;
1311         current_person = person;
1312         current_parent_folder = parent_folder;
1313         edit_person_close_post_update_cb = post_update_cb;
1314         personeditdlg.ldap = (abf->type == ADBOOKTYPE_LDAP)? TRUE : FALSE;
1315
1316         if( !personeditdlg.container )
1317                 addressbook_edit_person_create(parent_container, &cancelled);
1318
1319         /* typically, get focus when dialog mode is enabled, or when editing a new address */
1320         if( get_focus ) {
1321                 gtk_widget_grab_focus(personeditdlg.ok_btn);
1322                 gtk_widget_grab_focus(personeditdlg.entry_name);
1323         }
1324         
1325         personeditdlg.read_only = (current_abf == NULL);
1326         update_sensitivity();
1327
1328         gtk_widget_show(personeditdlg.container);
1329         if (prefs_common.addressbook_use_editaddress_dialog)
1330                 manage_window_set_transient(GTK_WINDOW(personeditdlg.container));
1331         else
1332                 if (get_focus)
1333                         addressbook_address_list_disable_some_actions();
1334
1335         /* Clear all fields */
1336         personeditdlg.rowIndEMail = -1;
1337         personeditdlg.rowIndAttrib = -1;
1338         edit_person_status_show( "" );
1339         gtk_clist_clear( GTK_CLIST(personeditdlg.clist_email) );
1340         gtk_clist_clear( GTK_CLIST(personeditdlg.clist_attrib) );
1341         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_name), "" );
1342         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_first), "" );
1343         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_last), "" );
1344         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_nick), "" );
1345
1346         personeditdlg.editNew = FALSE;
1347         if( person ) {
1348                 if( ADDRITEM_NAME(person) )
1349                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_name), ADDRITEM_NAME(person) );
1350                 if( person->firstName )
1351                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_first), person->firstName );
1352                 if( person->lastName )
1353                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_last), person->lastName );
1354                 if( person->nickName )
1355                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_nick), person->nickName );
1356                 edit_person_load_email( person );
1357                 edit_person_load_attrib( person );
1358                 gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_atvalue), "");
1359         }
1360         else {
1361                 personeditdlg.editNew = TRUE;
1362         }
1363
1364         /* Select appropriate start page */
1365         if( pgMail ) {
1366                 gtk_notebook_set_current_page( GTK_NOTEBOOK(personeditdlg.notebook), PAGE_EMAIL );
1367         }
1368         else {
1369                 gtk_notebook_set_current_page( GTK_NOTEBOOK(personeditdlg.notebook), PAGE_BASIC );
1370         }
1371
1372         gtk_clist_select_row( GTK_CLIST(personeditdlg.clist_email), 0, 0 );
1373         gtk_clist_select_row( GTK_CLIST(personeditdlg.clist_attrib), 0, 0 );
1374         edit_person_email_clear( NULL );
1375         if (person)
1376                 edit_person_email_list_selected(GTK_CLIST(personeditdlg.clist_email), 0, 0, NULL, NULL);
1377
1378         edit_person_attrib_clear( NULL );
1379
1380         if (prefs_common.addressbook_use_editaddress_dialog) {
1381
1382         gtk_main();
1383                 gtk_widget_hide( personeditdlg.container );
1384
1385                 if (!addressbook_edit_person_close( cancelled ))
1386                         return NULL;
1387         }
1388
1389         return person;
1390 }
1391
1392 /*
1393 * End of Source.
1394 */
1395