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