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