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