76345e2b5efb4c54cbb2708dac8bd961d5ef2ea0
[claws.git] / src / editaddress.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2001 Hiroyuki Yamamoto
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 <gdk/gdkkeysyms.h>
28 #include <gtk/gtkwindow.h>
29 #include <gtk/gtksignal.h>
30 #include <gtk/gtklabel.h>
31 #include <gtk/gtkvbox.h>
32 #include <gtk/gtkentry.h>
33 #include <gtk/gtktable.h>
34
35 #include "intl.h"
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
45 #include "prefs_common.h"
46
47 static struct _PersonEdit_dlg {
48         GtkWidget *window;
49         GtkWidget *notebook;
50         GtkWidget *ok_btn;
51         GtkWidget *cancel_btn;
52         GtkWidget *statusbar;
53         gint status_cid;
54
55         /* Basic data tab */
56         GtkWidget *entry_name;
57         GtkWidget *entry_first;
58         GtkWidget *entry_last;
59         GtkWidget *entry_nick;
60
61         /* EMail data tab */
62         GtkWidget *entry_email;
63         GtkWidget *entry_alias;
64         GtkWidget *entry_remarks;
65         GtkWidget *clist_email;
66
67         /* Attribute data tab */
68         GtkWidget *entry_atname;
69         GtkWidget *entry_atvalue;
70         GtkWidget *clist_attrib;
71
72         gint rowIndEMail;
73         gint rowIndAttrib;
74         gboolean editNew;
75
76 } personeditdlg;
77
78 typedef enum {
79         EMAIL_COL_EMAIL   = 0,
80         EMAIL_COL_ALIAS   = 1,
81         EMAIL_COL_REMARKS = 2
82 } PersonEditEMailColumnPos;
83
84 typedef enum {
85         ATTRIB_COL_NAME    = 0,
86         ATTRIB_COL_VALUE   = 1
87 } PersonEditAttribColumnPos;
88
89 #define EDITPERSON_WIDTH      520
90 #define EDITPERSON_HEIGHT     340
91
92 #define EMAIL_N_COLS          3
93 #define EMAIL_COL_WIDTH_EMAIL 180
94 #define EMAIL_COL_WIDTH_ALIAS 80
95
96 #define ATTRIB_N_COLS          2
97 #define ATTRIB_COL_WIDTH_NAME  120
98 #define ATTRIB_COL_WIDTH_VALUE 180
99
100 #define PAGE_BASIC             0
101 #define PAGE_EMAIL             1
102 #define PAGE_ATTRIBUTES        2
103
104 static void edit_person_status_show( gchar *msg ) {
105         if( personeditdlg.statusbar != NULL ) {
106                 gtk_statusbar_pop( GTK_STATUSBAR(personeditdlg.statusbar), personeditdlg.status_cid );
107                 if( msg ) {
108                         gtk_statusbar_push( GTK_STATUSBAR(personeditdlg.statusbar), personeditdlg.status_cid, msg );
109                 }
110         }
111 }
112
113 static void edit_person_ok(GtkWidget *widget, gboolean *cancelled) {
114         *cancelled = FALSE;
115         gtk_main_quit();
116 }
117
118 static void edit_person_cancel(GtkWidget *widget, gboolean *cancelled) {
119         *cancelled = TRUE;
120         gtk_main_quit();
121 }
122
123 static gint edit_person_delete_event(GtkWidget *widget, GdkEventAny *event, gboolean *cancelled) {
124         *cancelled = TRUE;
125         gtk_main_quit();
126         return TRUE;
127 }
128
129 static void edit_person_key_pressed(GtkWidget *widget, GdkEventKey *event, gboolean *cancelled) {
130         if (event && event->keyval == GDK_Escape) {
131                 *cancelled = TRUE;
132                 gtk_main_quit();
133         }
134 }
135
136 static gchar *_title_new_ = NULL;
137 static gchar *_title_edit_ = NULL;
138
139 static void edit_person_set_window_title( gint pageNum ) {
140         gchar *sTitle;
141
142         if( _title_new_ == NULL ) {
143                 _title_new_ = g_strdup( _("Add New Person") );
144                 _title_edit_ = g_strdup( _("Edit Person Details") );
145         }
146
147         if( pageNum == PAGE_BASIC ) {
148                 if( personeditdlg.editNew ) {
149                         gtk_window_set_title( GTK_WINDOW(personeditdlg.window), _title_new_ );
150                 }
151                 else {
152                         gtk_window_set_title( GTK_WINDOW(personeditdlg.window), _title_edit_ );
153                 }
154         }
155         else {
156                 if( personeditdlg.entry_name == NULL ) {
157                         sTitle = g_strdup( _title_edit_ );
158                 }
159                 else {
160                         sTitle = g_strdup_printf( "%s - %s", _title_edit_,
161                                         gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_name), 0, -1 ) );
162                 }
163                 gtk_window_set_title( GTK_WINDOW(personeditdlg.window), sTitle );
164                 g_free( sTitle );
165         }
166 }
167
168 static void edit_person_email_clear( gpointer data ) {
169         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_email), "" );
170         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_alias), "" );
171         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_remarks), "" );
172 }
173
174 static void edit_person_attrib_clear( gpointer data ) {
175         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atname), "" );
176         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atvalue), "" );
177 }
178
179 static void edit_person_switch_page( GtkNotebook *notebook, GtkNotebookPage *page,
180                                         gint pageNum, gpointer user_data)
181 {
182         edit_person_set_window_title( pageNum );
183         edit_person_status_show( "" );
184 }
185
186 /*
187 * Load clist with a copy of person's email addresses.
188 */
189 static void edit_person_load_email( ItemPerson *person ) {
190         GList *node = person->listEMail;
191         GtkCList *clist = GTK_CLIST(personeditdlg.clist_email);
192         gchar *text[ EMAIL_N_COLS ];
193         while( node ) {
194                 ItemEMail *emorig = ( ItemEMail * ) node->data;
195                 ItemEMail *email = addritem_copyfull_item_email( emorig );
196                 gint row;
197                 text[ EMAIL_COL_EMAIL   ] = email->address;
198                 text[ EMAIL_COL_ALIAS   ] = email->obj.name;
199                 text[ EMAIL_COL_REMARKS ] = email->remarks;
200
201                 row = gtk_clist_append( clist, text );
202                 gtk_clist_set_row_data( clist, row, email );
203                 node = g_list_next( node );
204         }
205 }
206
207 static void edit_person_email_list_selected( GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer data ) {
208         ItemEMail *email = gtk_clist_get_row_data( clist, row );
209         if( email ) {
210                 if( email->address )
211                         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_email), email->address );
212                 if( ADDRITEM_NAME(email) )
213                         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_alias), ADDRITEM_NAME(email) );
214                 if( email->remarks )
215                         gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_remarks), email->remarks );
216         }
217         personeditdlg.rowIndEMail = row;
218         edit_person_status_show( NULL );
219 }
220
221 static void edit_person_email_move( gint dir ) {
222         GtkCList *clist = GTK_CLIST(personeditdlg.clist_email);
223         gint row = personeditdlg.rowIndEMail + dir;
224         ItemEMail *email = gtk_clist_get_row_data( clist, row );
225         if( email ) {
226                 gtk_clist_row_move( clist, personeditdlg.rowIndEMail, row );
227                 personeditdlg.rowIndEMail = row;
228         }
229         edit_person_email_clear( NULL );
230         edit_person_status_show( NULL );
231 }
232
233 static void edit_person_email_move_up( gpointer data ) {
234         edit_person_email_move( -1 );
235 }
236
237 static void edit_person_email_move_down( gpointer data ) {
238         edit_person_email_move( +1 );
239 }
240
241 static void edit_person_email_delete( gpointer data ) {
242         GtkCList *clist = GTK_CLIST(personeditdlg.clist_email);
243         gint row = personeditdlg.rowIndEMail;
244         ItemEMail *email = gtk_clist_get_row_data( clist, row );
245         edit_person_email_clear( NULL );
246         if( email ) {
247                 /* Remove list entry */
248                 gtk_clist_remove( clist, row );
249                 addritem_free_item_email( email );
250                 email = NULL;
251         }
252
253         /* Position hilite bar */
254         email = gtk_clist_get_row_data( clist, row );
255         if( ! email ) {
256                 personeditdlg.rowIndEMail = -1 + row;
257         }
258         edit_person_status_show( NULL );
259 }
260
261 static ItemEMail *edit_person_email_edit( gboolean *error, ItemEMail *email ) {
262         ItemEMail *retVal = NULL;
263         gchar *sEmail, *sAlias, *sRemarks;
264         *error = TRUE;
265         sEmail = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_email), 0, -1 );
266         sAlias = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_alias), 0, -1 );
267         sRemarks = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_remarks), 0, -1 );
268         sEmail = mgu_email_check_empty( sEmail );
269         if( sEmail ) {
270                 if( email == NULL ) {
271                         email = addritem_create_item_email();
272                 }
273                 addritem_email_set_address( email, sEmail );
274                 addritem_email_set_alias( email, sAlias );
275                 addritem_email_set_remarks( email, sRemarks );
276                 retVal = email;
277                 *error = FALSE;
278         }
279         else {
280                 edit_person_status_show( _( "An E-Mail address must be supplied." ) );
281         }
282         return retVal;
283 }
284
285 static void edit_person_email_modify( gpointer data ) {
286         gboolean errFlg = FALSE;
287         GtkCList *clist = GTK_CLIST(personeditdlg.clist_email);
288         gint row = personeditdlg.rowIndEMail;
289         ItemEMail *email = gtk_clist_get_row_data( clist, row );
290         if( email ) {
291                 edit_person_email_edit( &errFlg, email );
292                 if( ! errFlg ) {
293                         gtk_clist_set_text( clist, row, EMAIL_COL_EMAIL, email->address );
294                         gtk_clist_set_text( clist, row, EMAIL_COL_ALIAS, email->obj.name );
295                         gtk_clist_set_text( clist, row, EMAIL_COL_REMARKS, email->remarks );
296                         edit_person_email_clear( NULL );
297                 }
298         }
299 }
300
301 static void edit_person_email_add( gpointer data ) {
302         GtkCList *clist = GTK_CLIST(personeditdlg.clist_email);
303         gboolean errFlg = FALSE;
304         ItemEMail *email = NULL;
305         gint row = personeditdlg.rowIndEMail;
306         if( gtk_clist_get_row_data( clist, row ) == NULL ) row = 0;
307
308         email = edit_person_email_edit( &errFlg, NULL );
309         if( ! errFlg ) {
310                 gchar *text[ EMAIL_N_COLS ];
311                 text[ EMAIL_COL_EMAIL   ] = email->address;
312                 text[ EMAIL_COL_ALIAS   ] = email->obj.name;
313                 text[ EMAIL_COL_REMARKS ] = email->remarks;
314
315                 row = gtk_clist_insert( clist, 1 + row, text );
316                 gtk_clist_set_row_data( clist, row, email );
317                 gtk_clist_select_row( clist, row, 0 );
318                 edit_person_email_clear( NULL );
319         }
320 }
321
322 /*
323 * Comparison using cell contents (text in first column). Used for sort
324 * address index widget.
325 */
326 static gint edit_person_attrib_compare_func(
327         GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
328 {
329         GtkCell *cell1 = ((GtkCListRow *)ptr1)->cell;
330         GtkCell *cell2 = ((GtkCListRow *)ptr2)->cell;
331         gchar *name1 = NULL, *name2 = NULL;
332
333         if( cell1 ) name1 = cell1->u.text;
334         if( cell2 ) name2 = cell2->u.text;
335         if( ! name1 ) return ( name2 != NULL );
336         if( ! name2 ) return -1;
337         return strcasecmp( name1, name2 );
338 }
339
340 /*
341 * Load clist with a copy of person's email addresses.
342 */
343 static void edit_person_load_attrib( ItemPerson *person ) {
344         GList *node = person->listAttrib;
345         GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib);
346         gchar *text[ ATTRIB_N_COLS ];
347         while( node ) {
348                 UserAttribute *atorig = ( UserAttribute * ) node->data;
349                 UserAttribute *attrib = addritem_copy_attribute( atorig );
350                 gint row;
351                 text[ ATTRIB_COL_NAME  ] = attrib->name;
352                 text[ ATTRIB_COL_VALUE ] = attrib->value;
353
354                 row = gtk_clist_append( clist, text );
355                 gtk_clist_set_row_data( clist, row, attrib );
356                 node = g_list_next( node );
357         }
358 }
359
360 static void edit_person_attrib_list_selected( GtkCList *clist, gint row, gint column, GdkEvent *event, gpointer data ) {
361         UserAttribute *attrib = gtk_clist_get_row_data( clist, row );
362         if( attrib ) {
363                 gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atname), attrib->name );
364                 gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atvalue), attrib->value );
365         }
366         personeditdlg.rowIndAttrib = row;
367         edit_person_status_show( NULL );
368 }
369
370 static void edit_person_attrib_delete( gpointer data ) {
371         GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib);
372         gint row = personeditdlg.rowIndAttrib;
373         UserAttribute *attrib = gtk_clist_get_row_data( clist, row );
374         edit_person_attrib_clear( NULL );
375         if( attrib ) {
376                 /* Remove list entry */
377                 gtk_clist_remove( clist, row );
378                 addritem_free_attribute( attrib );
379                 attrib = NULL;
380         }
381
382         /* Position hilite bar */
383         attrib = gtk_clist_get_row_data( clist, row );
384         if( ! attrib ) {
385                 personeditdlg.rowIndAttrib = -1 + row;
386         }
387         edit_person_status_show( NULL );
388 }
389
390 static UserAttribute *edit_person_attrib_edit( gboolean *error, UserAttribute *attrib ) {
391         UserAttribute *retVal = NULL;
392         gchar *sName, *sValue;
393         *error = TRUE;
394         sName = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_atname), 0, -1 );
395         sValue = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_atvalue), 0, -1 );
396         sName = mgu_email_check_empty( sName );
397         sValue = mgu_email_check_empty( sValue );
398         if( sName && sValue ) {
399                 if( attrib == NULL ) {
400                         attrib = addritem_create_attribute();
401                 }
402                 addritem_attrib_set_name( attrib, sName );
403                 addritem_attrib_set_value( attrib, sValue );
404                 retVal = attrib;
405                 *error = FALSE;
406         }
407         else {
408                 edit_person_status_show( _( "A Name and Value must be supplied." ) );
409         }
410         return retVal;
411 }
412
413 static void edit_person_attrib_modify( gpointer data ) {
414         gboolean errFlg = FALSE;
415         GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib);
416         gint row = personeditdlg.rowIndAttrib;
417         UserAttribute *attrib = gtk_clist_get_row_data( clist, row );
418         if( attrib ) {
419                 edit_person_attrib_edit( &errFlg, attrib );
420                 if( ! errFlg ) {
421                         gtk_clist_set_text( clist, row, ATTRIB_COL_NAME, attrib->name );
422                         gtk_clist_set_text( clist, row, ATTRIB_COL_VALUE, attrib->value );
423                         edit_person_attrib_clear( NULL );
424                 }
425         }
426 }
427
428 static void edit_person_attrib_add( gpointer data ) {
429         GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib);
430         gboolean errFlg = FALSE;
431         UserAttribute *attrib = NULL;
432         gint row = personeditdlg.rowIndAttrib;
433         if( gtk_clist_get_row_data( clist, row ) == NULL ) row = 0;
434
435         attrib = edit_person_attrib_edit( &errFlg, NULL );
436         if( ! errFlg ) {
437                 gchar *text[ EMAIL_N_COLS ];
438                 text[ ATTRIB_COL_NAME  ] = attrib->name;
439                 text[ ATTRIB_COL_VALUE ] = attrib->value;
440
441                 row = gtk_clist_insert( clist, 1 + row, text );
442                 gtk_clist_set_row_data( clist, row, attrib );
443                 gtk_clist_select_row( clist, row, 0 );
444                 edit_person_attrib_clear( NULL );
445         }
446 }
447
448 static void addressbook_edit_person_dialog_create( gboolean *cancelled ) {
449         GtkWidget *window;
450         GtkWidget *vbox;
451         GtkWidget *vnbox;
452         GtkWidget *notebook;
453         GtkWidget *hbbox;
454         GtkWidget *ok_btn;
455         GtkWidget *cancel_btn;
456         GtkWidget *hsbox;
457         GtkWidget *statusbar;
458
459         window = gtk_window_new(GTK_WINDOW_DIALOG);
460         gtk_widget_set_usize(window, EDITPERSON_WIDTH, EDITPERSON_HEIGHT );
461         /* gtk_container_set_border_width(GTK_CONTAINER(window), 0); */
462         gtk_window_set_title(GTK_WINDOW(window), _("Edit Person Data"));
463         gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
464         gtk_window_set_modal(GTK_WINDOW(window), TRUE); 
465         gtk_signal_connect(GTK_OBJECT(window), "delete_event",
466                            GTK_SIGNAL_FUNC(edit_person_delete_event),
467                            cancelled);
468         gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
469                            GTK_SIGNAL_FUNC(edit_person_key_pressed),
470                            cancelled);
471
472         vbox = gtk_vbox_new(FALSE, 4);
473         /* gtk_container_set_border_width(GTK_CONTAINER(vbox), BORDER_WIDTH); */
474         gtk_widget_show(vbox);
475         gtk_container_add(GTK_CONTAINER(window), vbox);
476
477         vnbox = gtk_vbox_new(FALSE, 4);
478         gtk_container_set_border_width(GTK_CONTAINER(vnbox), 4);
479         gtk_widget_show(vnbox);
480         gtk_box_pack_start(GTK_BOX(vbox), vnbox, TRUE, TRUE, 0);
481
482         /* Notebook */
483         notebook = gtk_notebook_new();
484         gtk_widget_show(notebook);
485         gtk_box_pack_start(GTK_BOX(vnbox), notebook, TRUE, TRUE, 0);
486         gtk_container_set_border_width(GTK_CONTAINER(notebook), 6);
487
488         /* Status line */
489         hsbox = gtk_hbox_new(FALSE, 0);
490         gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
491         statusbar = gtk_statusbar_new();
492         gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
493
494         /* Button panel */
495         gtkut_button_set_create(&hbbox, &ok_btn, _("OK"),
496                                 &cancel_btn, _("Cancel"), NULL, NULL);
497         gtk_box_pack_end(GTK_BOX(vnbox), hbbox, FALSE, FALSE, 0);
498         gtk_widget_grab_default(ok_btn);
499
500         gtk_signal_connect(GTK_OBJECT(ok_btn), "clicked",
501                            GTK_SIGNAL_FUNC(edit_person_ok), cancelled);
502         gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked",
503                            GTK_SIGNAL_FUNC(edit_person_cancel), cancelled);
504         gtk_signal_connect(GTK_OBJECT(notebook), "switch_page",
505                            GTK_SIGNAL_FUNC(edit_person_switch_page), NULL );
506
507         gtk_widget_show_all(vbox);
508
509         personeditdlg.window     = window;
510         personeditdlg.notebook   = notebook;
511         personeditdlg.ok_btn     = ok_btn;
512         personeditdlg.cancel_btn = cancel_btn;
513         personeditdlg.statusbar  = statusbar;
514         personeditdlg.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Edit Person Dialog" );
515
516 }
517
518 static void addressbook_edit_person_page_basic( gint pageNum, gchar *pageLbl ) {
519         GtkWidget *vbox;
520         GtkWidget *table;
521         GtkWidget *label;
522         GtkWidget *entry_name;
523         GtkWidget *entry_fn;
524         GtkWidget *entry_ln;
525         GtkWidget *entry_nn;
526         const gchar *locale;
527         gint top = 0;
528
529         vbox = gtk_vbox_new( FALSE, 8 );
530         gtk_widget_show( vbox );
531         gtk_container_add( GTK_CONTAINER( personeditdlg.notebook ), vbox );
532         gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
533
534         label = gtk_label_new( pageLbl );
535         gtk_widget_show( label );
536         gtk_notebook_set_tab_label(
537                 GTK_NOTEBOOK( personeditdlg.notebook ),
538                 gtk_notebook_get_nth_page( GTK_NOTEBOOK( personeditdlg.notebook ), pageNum ), label );
539
540         table = gtk_table_new( 4, 3, FALSE);
541         gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
542         gtk_container_set_border_width( GTK_CONTAINER(table), 8 );
543         gtk_table_set_row_spacings(GTK_TABLE(table), 8);
544         gtk_table_set_col_spacings(GTK_TABLE(table), 8);
545
546 #define ATTACH_ROW(text, entry) \
547 { \
548         label = gtk_label_new(text); \
549         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), \
550                          GTK_FILL, 0, 0, 0); \
551         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); \
552  \
553         entry = gtk_entry_new(); \
554         gtk_table_attach(GTK_TABLE(table), entry, 1, 2, top, (top + 1), \
555                          GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0); \
556         top++; \
557 }
558
559         ATTACH_ROW(_("Display Name"), entry_name);
560         locale = conv_get_current_locale();
561         if (locale &&
562             (!g_strncasecmp(locale, "ja", 2) ||
563              !g_strncasecmp(locale, "ko", 2) ||
564              !g_strncasecmp(locale, "zh", 2))) {
565                 ATTACH_ROW(_("Last Name"), entry_ln);
566                 ATTACH_ROW(_("First Name"), entry_fn);
567         } else {
568                 ATTACH_ROW(_("First Name"), entry_fn);
569                 ATTACH_ROW(_("Last Name"), entry_ln);
570         }
571         ATTACH_ROW(_("Nick Name"), entry_nn);
572
573 #undef ATTACH_ROW
574
575         gtk_widget_show_all(vbox);
576
577         personeditdlg.entry_name  = entry_name;
578         personeditdlg.entry_first = entry_fn;
579         personeditdlg.entry_last  = entry_ln;
580         personeditdlg.entry_nick  = entry_nn;
581 }
582
583 static void addressbook_edit_person_page_email( gint pageNum, gchar *pageLbl ) {
584         GtkWidget *vbox;
585         GtkWidget *hbox;
586         GtkWidget *vboxl;
587         GtkWidget *vboxb;
588         GtkWidget *vbuttonbox;
589         GtkWidget *buttonUp;
590         GtkWidget *buttonDown;
591         GtkWidget *buttonDel;
592         GtkWidget *buttonMod;
593         GtkWidget *buttonAdd;
594         GtkWidget *buttonClr;
595
596         GtkWidget *table;
597         GtkWidget *label;
598         GtkWidget *clist_swin;
599         GtkWidget *clist;
600         GtkWidget *entry_email;
601         GtkWidget *entry_alias;
602         GtkWidget *entry_remarks;
603         gint top;
604
605         gchar *titles[ EMAIL_N_COLS ] = { _("E-Mail Address"), _("Alias"), _("Remarks") };
606         gint i;
607
608         vbox = gtk_vbox_new( FALSE, 8 );
609         gtk_widget_show( vbox );
610         gtk_container_add( GTK_CONTAINER( personeditdlg.notebook ), vbox );
611         gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
612
613         label = gtk_label_new( pageLbl );
614         gtk_widget_show( label );
615         gtk_notebook_set_tab_label(
616                 GTK_NOTEBOOK( personeditdlg.notebook ),
617                 gtk_notebook_get_nth_page( GTK_NOTEBOOK( personeditdlg.notebook ), pageNum ), label );
618
619         /* Split into two areas */
620         hbox = gtk_hbox_new( FALSE, 0 );
621         gtk_container_add( GTK_CONTAINER( vbox ), hbox );
622
623         /* Address list */
624         vboxl = gtk_vbox_new( FALSE, 4 );
625         gtk_container_add( GTK_CONTAINER( hbox ), vboxl );
626         gtk_container_set_border_width( GTK_CONTAINER(vboxl), 4 );
627
628         clist_swin = gtk_scrolled_window_new( NULL, NULL );
629         gtk_container_add( GTK_CONTAINER(vboxl), clist_swin );
630         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
631                                        GTK_POLICY_AUTOMATIC,
632                                        GTK_POLICY_ALWAYS);
633
634         clist = gtk_clist_new_with_titles( EMAIL_N_COLS, titles );
635         gtk_container_add( GTK_CONTAINER(clist_swin), clist );
636         gtk_clist_set_selection_mode( GTK_CLIST(clist), GTK_SELECTION_BROWSE );
637         gtk_clist_set_column_width( GTK_CLIST(clist), EMAIL_COL_EMAIL, EMAIL_COL_WIDTH_EMAIL );
638         gtk_clist_set_column_width( GTK_CLIST(clist), EMAIL_COL_ALIAS, EMAIL_COL_WIDTH_ALIAS );
639
640         for( i = 0; i < EMAIL_N_COLS; i++ )
641                 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button, GTK_CAN_FOCUS);
642
643         /* Data entry area */
644         table = gtk_table_new( 4, 2, FALSE);
645         gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0);
646         gtk_container_set_border_width( GTK_CONTAINER(table), 4 );
647         gtk_table_set_row_spacings(GTK_TABLE(table), 4);
648         gtk_table_set_col_spacings(GTK_TABLE(table), 4);
649
650         /* First row */
651         top = 0;
652         label = gtk_label_new(_("E-Mail Address"));
653         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
654         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
655
656         entry_email = gtk_entry_new();
657         gtk_table_attach(GTK_TABLE(table), entry_email, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
658
659         /* Next row */
660         ++top;
661         label = gtk_label_new(_("Alias"));
662         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
663         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
664
665         entry_alias = gtk_entry_new();
666         gtk_table_attach(GTK_TABLE(table), entry_alias, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
667
668         /* Next row */
669         ++top;
670         label = gtk_label_new(_("Remarks"));
671         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
672         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
673
674         entry_remarks = gtk_entry_new();
675         gtk_table_attach(GTK_TABLE(table), entry_remarks, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
676
677         /* Button box */
678         vboxb = gtk_vbox_new( FALSE, 4 );
679         gtk_box_pack_start(GTK_BOX(hbox), vboxb, FALSE, FALSE, 2);
680
681         vbuttonbox = gtk_vbutton_box_new();
682         gtk_button_box_set_layout( GTK_BUTTON_BOX(vbuttonbox), GTK_BUTTONBOX_START );
683         gtk_button_box_set_spacing( GTK_BUTTON_BOX(vbuttonbox), 8 );
684         gtk_container_set_border_width( GTK_CONTAINER(vbuttonbox), 4 );
685         gtk_container_add( GTK_CONTAINER(vboxb), vbuttonbox );
686
687         /* Buttons */
688         buttonUp = gtk_button_new_with_label( _( "Move Up" ) );
689         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonUp );
690
691         buttonDown = gtk_button_new_with_label( _( "Move Down" ) );
692         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDown );
693
694         buttonDel = gtk_button_new_with_label( _( "Delete" ) );
695         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDel );
696
697         buttonMod = gtk_button_new_with_label( _( "Modify" ) );
698         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonMod );
699
700         buttonAdd = gtk_button_new_with_label( _( "Add" ) );
701         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonAdd );
702
703         buttonClr = gtk_button_new_with_label( _( "Clear" ) );
704         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonClr );
705
706         gtk_widget_show_all(vbox);
707
708         /* Event handlers */
709         gtk_signal_connect( GTK_OBJECT(clist), "select_row",
710                         GTK_SIGNAL_FUNC( edit_person_email_list_selected), NULL );
711         gtk_signal_connect( GTK_OBJECT(buttonUp), "clicked",
712                         GTK_SIGNAL_FUNC( edit_person_email_move_up ), NULL );
713         gtk_signal_connect( GTK_OBJECT(buttonDown), "clicked",
714                         GTK_SIGNAL_FUNC( edit_person_email_move_down ), NULL );
715         gtk_signal_connect( GTK_OBJECT(buttonDel), "clicked",
716                         GTK_SIGNAL_FUNC( edit_person_email_delete ), NULL );
717         gtk_signal_connect( GTK_OBJECT(buttonMod), "clicked",
718                         GTK_SIGNAL_FUNC( edit_person_email_modify ), NULL );
719         gtk_signal_connect( GTK_OBJECT(buttonAdd), "clicked",
720                         GTK_SIGNAL_FUNC( edit_person_email_add ), NULL );
721         gtk_signal_connect( GTK_OBJECT(buttonClr), "clicked",
722                         GTK_SIGNAL_FUNC( edit_person_email_clear ), NULL );
723
724         personeditdlg.clist_email   = clist;
725         personeditdlg.entry_email   = entry_email;
726         personeditdlg.entry_alias   = entry_alias;
727         personeditdlg.entry_remarks = entry_remarks;
728 }
729
730 static void addressbook_edit_person_page_attrib( gint pageNum, gchar *pageLbl ) {
731         GtkWidget *vbox;
732         GtkWidget *hbox;
733         GtkWidget *vboxl;
734         GtkWidget *vboxb;
735         GtkWidget *vbuttonbox;
736         GtkWidget *buttonDel;
737         GtkWidget *buttonMod;
738         GtkWidget *buttonAdd;
739         GtkWidget *buttonClr;
740
741         GtkWidget *table;
742         GtkWidget *label;
743         GtkWidget *clist_swin;
744         GtkWidget *clist;
745         GtkWidget *entry_name;
746         GtkWidget *entry_value;
747         gint top;
748
749         gchar *titles[ ATTRIB_N_COLS ] = { _("Name"), _("Value") };
750         gint i;
751
752         vbox = gtk_vbox_new( FALSE, 8 );
753         gtk_widget_show( vbox );
754         gtk_container_add( GTK_CONTAINER( personeditdlg.notebook ), vbox );
755         gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
756
757         label = gtk_label_new( pageLbl );
758         gtk_widget_show( label );
759         gtk_notebook_set_tab_label(
760                 GTK_NOTEBOOK( personeditdlg.notebook ),
761                 gtk_notebook_get_nth_page( GTK_NOTEBOOK( personeditdlg.notebook ), pageNum ), label );
762
763         /* Split into two areas */
764         hbox = gtk_hbox_new( FALSE, 0 );
765         gtk_container_add( GTK_CONTAINER( vbox ), hbox );
766
767         /* Attribute list */
768         vboxl = gtk_vbox_new( FALSE, 4 );
769         gtk_container_add( GTK_CONTAINER( hbox ), vboxl );
770         gtk_container_set_border_width( GTK_CONTAINER(vboxl), 4 );
771
772         clist_swin = gtk_scrolled_window_new( NULL, NULL );
773         gtk_container_add( GTK_CONTAINER(vboxl), clist_swin );
774         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
775                                        GTK_POLICY_AUTOMATIC,
776                                        GTK_POLICY_ALWAYS);
777
778         clist = gtk_clist_new_with_titles( ATTRIB_N_COLS, titles );
779         gtk_container_add( GTK_CONTAINER(clist_swin), clist );
780         gtk_clist_set_selection_mode( GTK_CLIST(clist), GTK_SELECTION_BROWSE );
781         gtk_clist_set_column_width( GTK_CLIST(clist), ATTRIB_COL_NAME, ATTRIB_COL_WIDTH_NAME );
782         gtk_clist_set_column_width( GTK_CLIST(clist), ATTRIB_COL_VALUE, ATTRIB_COL_WIDTH_VALUE );
783         gtk_clist_set_compare_func( GTK_CLIST(clist), edit_person_attrib_compare_func );
784         gtk_clist_set_auto_sort( GTK_CLIST(clist), TRUE );
785
786         for( i = 0; i < ATTRIB_N_COLS; i++ )
787                 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button, GTK_CAN_FOCUS);
788
789         /* Data entry area */
790         table = gtk_table_new( 4, 2, FALSE);
791         gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0);
792         gtk_container_set_border_width( GTK_CONTAINER(table), 4 );
793         gtk_table_set_row_spacings(GTK_TABLE(table), 4);
794         gtk_table_set_col_spacings(GTK_TABLE(table), 4);
795
796         /* First row */
797         top = 0;
798         label = gtk_label_new(_("Name"));
799         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
800         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
801
802         entry_name = gtk_entry_new();
803         gtk_table_attach(GTK_TABLE(table), entry_name, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
804
805         /* Next row */
806         ++top;
807         label = gtk_label_new(_("Value"));
808         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
809         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
810
811         entry_value = gtk_entry_new();
812         gtk_table_attach(GTK_TABLE(table), entry_value, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
813
814         /* Button box */
815         vboxb = gtk_vbox_new( FALSE, 4 );
816         gtk_box_pack_start(GTK_BOX(hbox), vboxb, FALSE, FALSE, 2);
817
818         vbuttonbox = gtk_vbutton_box_new();
819         gtk_button_box_set_layout( GTK_BUTTON_BOX(vbuttonbox), GTK_BUTTONBOX_START );
820         gtk_button_box_set_spacing( GTK_BUTTON_BOX(vbuttonbox), 8 );
821         gtk_container_set_border_width( GTK_CONTAINER(vbuttonbox), 4 );
822         gtk_container_add( GTK_CONTAINER(vboxb), vbuttonbox );
823
824         /* Buttons */
825         buttonDel = gtk_button_new_with_label( _( "Delete" ) );
826         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDel );
827
828         buttonMod = gtk_button_new_with_label( _( "Modify" ) );
829         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonMod );
830
831         buttonAdd = gtk_button_new_with_label( _( "Add" ) );
832         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonAdd );
833
834         buttonClr = gtk_button_new_with_label( _( "Clear" ) );
835         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonClr );
836
837         gtk_widget_show_all(vbox);
838
839         /* Event handlers */
840         gtk_signal_connect( GTK_OBJECT(clist), "select_row",
841                         GTK_SIGNAL_FUNC( edit_person_attrib_list_selected), NULL );
842         gtk_signal_connect( GTK_OBJECT(buttonDel), "clicked",
843                         GTK_SIGNAL_FUNC( edit_person_attrib_delete ), NULL );
844         gtk_signal_connect( GTK_OBJECT(buttonMod), "clicked",
845                         GTK_SIGNAL_FUNC( edit_person_attrib_modify ), NULL );
846         gtk_signal_connect( GTK_OBJECT(buttonAdd), "clicked",
847                         GTK_SIGNAL_FUNC( edit_person_attrib_add ), NULL );
848         gtk_signal_connect( GTK_OBJECT(buttonClr), "clicked",
849                         GTK_SIGNAL_FUNC( edit_person_attrib_clear ), NULL );
850
851         personeditdlg.clist_attrib  = clist;
852         personeditdlg.entry_atname  = entry_name;
853         personeditdlg.entry_atvalue = entry_value;
854 }
855
856 static void addressbook_edit_person_create( gboolean *cancelled ) {
857         addressbook_edit_person_dialog_create( cancelled );
858         addressbook_edit_person_page_basic( PAGE_BASIC, _( "Basic Data" ) );
859         addressbook_edit_person_page_email( PAGE_EMAIL, _( "E-Mail Address" ) );
860         addressbook_edit_person_page_attrib( PAGE_ATTRIBUTES, _( "User Attributes" ) );
861         gtk_widget_show_all( personeditdlg.window );
862 }
863
864 /*
865 * Return list of email items.
866 */
867 static GList *edit_person_build_email_list() {
868         GtkCList *clist = GTK_CLIST(personeditdlg.clist_email);
869         GList *listEMail = NULL;
870         ItemEMail *email;
871         gint row = 0;
872         while( (email = gtk_clist_get_row_data( clist, row )) ) {
873                 listEMail = g_list_append( listEMail, email );
874                 row++;
875         }
876         return listEMail;
877 }
878
879 /*
880 * Return list of attributes.
881 */
882 static GList *edit_person_build_attrib_list() {
883         GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib);
884         GList *listAttrib = NULL;
885         UserAttribute *attrib;
886         gint row = 0;
887         while( (attrib = gtk_clist_get_row_data( clist, row )) ) {
888                 listAttrib = g_list_append( listAttrib, attrib );
889                 row++;
890         }
891         return listAttrib;
892 }
893
894 /*
895 * Edit person.
896 * Enter: abf    Address book.
897 *        parent Parent folder for person (or NULL if adding to root folder). Argument is
898 *               only required for new objects).
899 *        person Person to edit, or NULL for a new person object.
900 *        pgMail If TRUE, E-Mail page will be activated.
901 * Return: Edited object, or NULL if cancelled.
902 */
903 ItemPerson *addressbook_edit_person( AddressBookFile *abf, ItemFolder *parent, ItemPerson *person, gboolean pgMail ) {
904         static gboolean cancelled;
905         GList *listEMail = NULL;
906         GList *listAttrib = NULL;
907         gchar *cn = NULL;
908
909         if (!personeditdlg.window)
910                 addressbook_edit_person_create(&cancelled);
911         gtk_widget_grab_focus(personeditdlg.ok_btn);
912         gtk_widget_grab_focus(personeditdlg.entry_name);
913         gtk_widget_show(personeditdlg.window);
914         manage_window_set_transient(GTK_WINDOW(personeditdlg.window));
915
916         /* Clear all fields */
917         personeditdlg.rowIndEMail = -1;
918         personeditdlg.rowIndAttrib = -1;
919         edit_person_status_show( "" );
920         gtk_clist_clear( GTK_CLIST(personeditdlg.clist_email) );
921         gtk_clist_clear( GTK_CLIST(personeditdlg.clist_attrib) );
922         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_name), "" );
923         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_first), "" );
924         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_last), "" );
925         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_nick), "" );
926
927         personeditdlg.editNew = FALSE;
928         if( person ) {
929                 if( ADDRITEM_NAME(person) )
930                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_name), ADDRITEM_NAME(person) );
931                 if( person->firstName )
932                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_first), person->firstName );
933                 if( person->lastName )
934                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_last), person->lastName );
935                 if( person->nickName )
936                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_nick), person->nickName );
937                 edit_person_load_email( person );
938                 edit_person_load_attrib( person );
939         }
940         else {
941                 personeditdlg.editNew = TRUE;
942         }
943
944         /* Select appropriate start page */
945         if( pgMail ) {
946                 gtk_notebook_set_page( GTK_NOTEBOOK(personeditdlg.notebook), PAGE_EMAIL );
947         }
948         else {
949                 gtk_notebook_set_page( GTK_NOTEBOOK(personeditdlg.notebook), PAGE_BASIC );
950         }
951
952         gtk_clist_select_row( GTK_CLIST(personeditdlg.clist_email), 0, 0 );
953         gtk_clist_select_row( GTK_CLIST(personeditdlg.clist_attrib), 0, 0 );
954         edit_person_email_clear( NULL );
955         edit_person_attrib_clear( NULL );
956
957         gtk_main();
958         gtk_widget_hide( personeditdlg.window );
959
960         listEMail = edit_person_build_email_list();
961         listAttrib = edit_person_build_attrib_list();
962         if( cancelled ) {
963                 addritem_free_list_email( listEMail );
964                 gtk_clist_clear( GTK_CLIST(personeditdlg.clist_email) );
965                 gtk_clist_clear( GTK_CLIST(personeditdlg.clist_attrib) );
966                 return NULL;
967         }
968
969         cn = g_strdup( gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_name), 0, -1 ) );
970         if( person ) {
971                 /* Update email/attribute list */
972                 addrbook_update_address_list( abf, person, listEMail );
973                 addrbook_update_attrib_list( abf, person, listAttrib );
974         }
975         else {
976                 /* Create new person and email/attribute list */
977                 if( cn == NULL || *cn == '\0' ) {
978                         /* Wasting our time */
979                         if( listEMail == NULL && listAttrib == NULL ) cancelled = TRUE;
980                 }
981                 if( ! cancelled ) {
982                         person = addrbook_add_address_list( abf, parent, listEMail );
983                         addrbook_add_attrib_list( abf, person, listAttrib );
984                 }
985         }
986
987         if( ! cancelled ) {
988                 /* Set person stuff */
989                 addritem_person_set_common_name( person, cn );
990                 addritem_person_set_first_name( person,
991                         gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_first), 0, -1 ) );
992                 addritem_person_set_last_name( person,
993                         gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_last), 0, -1 ) );
994                 addritem_person_set_nick_name( person,
995                         gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_nick), 0, -1 ) );
996         }
997         g_free( cn );
998
999         listEMail = NULL;
1000
1001         gtk_clist_clear( GTK_CLIST(personeditdlg.clist_email) );
1002         gtk_clist_clear( GTK_CLIST(personeditdlg.clist_attrib) );
1003
1004         return person;
1005 }
1006
1007 /*
1008 * End of Source.
1009 */
1010