src/compose.[ch]
[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(_("Nickname"), 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 ];
606         gint i;
607
608         titles[ EMAIL_COL_EMAIL   ] = _("E-Mail Address");
609         titles[ EMAIL_COL_ALIAS   ] = _("Alias");
610         titles[ EMAIL_COL_REMARKS ] = _("Remarks");
611
612         vbox = gtk_vbox_new( FALSE, 8 );
613         gtk_widget_show( vbox );
614         gtk_container_add( GTK_CONTAINER( personeditdlg.notebook ), vbox );
615         gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
616
617         label = gtk_label_new( pageLbl );
618         gtk_widget_show( label );
619         gtk_notebook_set_tab_label(
620                 GTK_NOTEBOOK( personeditdlg.notebook ),
621                 gtk_notebook_get_nth_page( GTK_NOTEBOOK( personeditdlg.notebook ), pageNum ), label );
622
623         /* Split into two areas */
624         hbox = gtk_hbox_new( FALSE, 0 );
625         gtk_container_add( GTK_CONTAINER( vbox ), hbox );
626
627         /* Address list */
628         vboxl = gtk_vbox_new( FALSE, 4 );
629         gtk_container_add( GTK_CONTAINER( hbox ), vboxl );
630         gtk_container_set_border_width( GTK_CONTAINER(vboxl), 4 );
631
632         clist_swin = gtk_scrolled_window_new( NULL, NULL );
633         gtk_container_add( GTK_CONTAINER(vboxl), clist_swin );
634         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
635                                        GTK_POLICY_AUTOMATIC,
636                                        GTK_POLICY_ALWAYS);
637
638         clist = gtk_clist_new_with_titles( EMAIL_N_COLS, titles );
639         gtk_container_add( GTK_CONTAINER(clist_swin), clist );
640         gtk_clist_set_selection_mode( GTK_CLIST(clist), GTK_SELECTION_BROWSE );
641         gtk_clist_set_column_width( GTK_CLIST(clist), EMAIL_COL_EMAIL, EMAIL_COL_WIDTH_EMAIL );
642         gtk_clist_set_column_width( GTK_CLIST(clist), EMAIL_COL_ALIAS, EMAIL_COL_WIDTH_ALIAS );
643
644         for( i = 0; i < EMAIL_N_COLS; i++ )
645                 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button, GTK_CAN_FOCUS);
646
647         /* Data entry area */
648         table = gtk_table_new( 4, 2, FALSE);
649         gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0);
650         gtk_container_set_border_width( GTK_CONTAINER(table), 4 );
651         gtk_table_set_row_spacings(GTK_TABLE(table), 4);
652         gtk_table_set_col_spacings(GTK_TABLE(table), 4);
653
654         /* First row */
655         top = 0;
656         label = gtk_label_new(_("E-Mail Address"));
657         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
658         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
659
660         entry_email = gtk_entry_new();
661         gtk_table_attach(GTK_TABLE(table), entry_email, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
662
663         /* Next row */
664         ++top;
665         label = gtk_label_new(_("Alias"));
666         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
667         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
668
669         entry_alias = gtk_entry_new();
670         gtk_table_attach(GTK_TABLE(table), entry_alias, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
671
672         /* Next row */
673         ++top;
674         label = gtk_label_new(_("Remarks"));
675         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
676         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
677
678         entry_remarks = gtk_entry_new();
679         gtk_table_attach(GTK_TABLE(table), entry_remarks, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
680
681         /* Button box */
682         vboxb = gtk_vbox_new( FALSE, 4 );
683         gtk_box_pack_start(GTK_BOX(hbox), vboxb, FALSE, FALSE, 2);
684
685         vbuttonbox = gtk_vbutton_box_new();
686         gtk_button_box_set_layout( GTK_BUTTON_BOX(vbuttonbox), GTK_BUTTONBOX_START );
687         gtk_button_box_set_spacing( GTK_BUTTON_BOX(vbuttonbox), 8 );
688         gtk_container_set_border_width( GTK_CONTAINER(vbuttonbox), 4 );
689         gtk_container_add( GTK_CONTAINER(vboxb), vbuttonbox );
690
691         /* Buttons */
692         buttonUp = gtk_button_new_with_label( _( "Move Up" ) );
693         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonUp );
694
695         buttonDown = gtk_button_new_with_label( _( "Move Down" ) );
696         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDown );
697
698         buttonDel = gtk_button_new_with_label( _( "Delete" ) );
699         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDel );
700
701         buttonMod = gtk_button_new_with_label( _( "Modify" ) );
702         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonMod );
703
704         buttonAdd = gtk_button_new_with_label( _( "Add" ) );
705         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonAdd );
706
707         buttonClr = gtk_button_new_with_label( _( "Clear" ) );
708         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonClr );
709
710         gtk_widget_show_all(vbox);
711
712         /* Event handlers */
713         gtk_signal_connect( GTK_OBJECT(clist), "select_row",
714                         GTK_SIGNAL_FUNC( edit_person_email_list_selected), NULL );
715         gtk_signal_connect( GTK_OBJECT(buttonUp), "clicked",
716                         GTK_SIGNAL_FUNC( edit_person_email_move_up ), NULL );
717         gtk_signal_connect( GTK_OBJECT(buttonDown), "clicked",
718                         GTK_SIGNAL_FUNC( edit_person_email_move_down ), NULL );
719         gtk_signal_connect( GTK_OBJECT(buttonDel), "clicked",
720                         GTK_SIGNAL_FUNC( edit_person_email_delete ), NULL );
721         gtk_signal_connect( GTK_OBJECT(buttonMod), "clicked",
722                         GTK_SIGNAL_FUNC( edit_person_email_modify ), NULL );
723         gtk_signal_connect( GTK_OBJECT(buttonAdd), "clicked",
724                         GTK_SIGNAL_FUNC( edit_person_email_add ), NULL );
725         gtk_signal_connect( GTK_OBJECT(buttonClr), "clicked",
726                         GTK_SIGNAL_FUNC( edit_person_email_clear ), NULL );
727
728         personeditdlg.clist_email   = clist;
729         personeditdlg.entry_email   = entry_email;
730         personeditdlg.entry_alias   = entry_alias;
731         personeditdlg.entry_remarks = entry_remarks;
732 }
733
734 static void addressbook_edit_person_page_attrib( gint pageNum, gchar *pageLbl ) {
735         GtkWidget *vbox;
736         GtkWidget *hbox;
737         GtkWidget *vboxl;
738         GtkWidget *vboxb;
739         GtkWidget *vbuttonbox;
740         GtkWidget *buttonDel;
741         GtkWidget *buttonMod;
742         GtkWidget *buttonAdd;
743         GtkWidget *buttonClr;
744
745         GtkWidget *table;
746         GtkWidget *label;
747         GtkWidget *clist_swin;
748         GtkWidget *clist;
749         GtkWidget *entry_name;
750         GtkWidget *entry_value;
751         gint top;
752
753         gchar *titles[ ATTRIB_N_COLS ];
754         gint i;
755
756         titles[ ATTRIB_COL_NAME  ] = _("Name");
757         titles[ ATTRIB_COL_VALUE ] = _("Value");
758
759         vbox = gtk_vbox_new( FALSE, 8 );
760         gtk_widget_show( vbox );
761         gtk_container_add( GTK_CONTAINER( personeditdlg.notebook ), vbox );
762         gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
763
764         label = gtk_label_new( pageLbl );
765         gtk_widget_show( label );
766         gtk_notebook_set_tab_label(
767                 GTK_NOTEBOOK( personeditdlg.notebook ),
768                 gtk_notebook_get_nth_page( GTK_NOTEBOOK( personeditdlg.notebook ), pageNum ), label );
769
770         /* Split into two areas */
771         hbox = gtk_hbox_new( FALSE, 0 );
772         gtk_container_add( GTK_CONTAINER( vbox ), hbox );
773
774         /* Attribute list */
775         vboxl = gtk_vbox_new( FALSE, 4 );
776         gtk_container_add( GTK_CONTAINER( hbox ), vboxl );
777         gtk_container_set_border_width( GTK_CONTAINER(vboxl), 4 );
778
779         clist_swin = gtk_scrolled_window_new( NULL, NULL );
780         gtk_container_add( GTK_CONTAINER(vboxl), clist_swin );
781         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
782                                        GTK_POLICY_AUTOMATIC,
783                                        GTK_POLICY_ALWAYS);
784
785         clist = gtk_clist_new_with_titles( ATTRIB_N_COLS, titles );
786         gtk_container_add( GTK_CONTAINER(clist_swin), clist );
787         gtk_clist_set_selection_mode( GTK_CLIST(clist), GTK_SELECTION_BROWSE );
788         gtk_clist_set_column_width( GTK_CLIST(clist), ATTRIB_COL_NAME, ATTRIB_COL_WIDTH_NAME );
789         gtk_clist_set_column_width( GTK_CLIST(clist), ATTRIB_COL_VALUE, ATTRIB_COL_WIDTH_VALUE );
790         gtk_clist_set_compare_func( GTK_CLIST(clist), edit_person_attrib_compare_func );
791         gtk_clist_set_auto_sort( GTK_CLIST(clist), TRUE );
792
793         for( i = 0; i < ATTRIB_N_COLS; i++ )
794                 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button, GTK_CAN_FOCUS);
795
796         /* Data entry area */
797         table = gtk_table_new( 4, 2, FALSE);
798         gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0);
799         gtk_container_set_border_width( GTK_CONTAINER(table), 4 );
800         gtk_table_set_row_spacings(GTK_TABLE(table), 4);
801         gtk_table_set_col_spacings(GTK_TABLE(table), 4);
802
803         /* First row */
804         top = 0;
805         label = gtk_label_new(_("Name"));
806         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
807         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
808
809         entry_name = gtk_entry_new();
810         gtk_table_attach(GTK_TABLE(table), entry_name, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
811
812         /* Next row */
813         ++top;
814         label = gtk_label_new(_("Value"));
815         gtk_table_attach(GTK_TABLE(table), label, 0, 1, top, (top + 1), GTK_FILL, 0, 0, 0);
816         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
817
818         entry_value = gtk_entry_new();
819         gtk_table_attach(GTK_TABLE(table), entry_value, 1, 2, top, (top + 1), GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
820
821         /* Button box */
822         vboxb = gtk_vbox_new( FALSE, 4 );
823         gtk_box_pack_start(GTK_BOX(hbox), vboxb, FALSE, FALSE, 2);
824
825         vbuttonbox = gtk_vbutton_box_new();
826         gtk_button_box_set_layout( GTK_BUTTON_BOX(vbuttonbox), GTK_BUTTONBOX_START );
827         gtk_button_box_set_spacing( GTK_BUTTON_BOX(vbuttonbox), 8 );
828         gtk_container_set_border_width( GTK_CONTAINER(vbuttonbox), 4 );
829         gtk_container_add( GTK_CONTAINER(vboxb), vbuttonbox );
830
831         /* Buttons */
832         buttonDel = gtk_button_new_with_label( _( "Delete" ) );
833         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDel );
834
835         buttonMod = gtk_button_new_with_label( _( "Modify" ) );
836         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonMod );
837
838         buttonAdd = gtk_button_new_with_label( _( "Add" ) );
839         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonAdd );
840
841         buttonClr = gtk_button_new_with_label( _( "Clear" ) );
842         gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonClr );
843
844         gtk_widget_show_all(vbox);
845
846         /* Event handlers */
847         gtk_signal_connect( GTK_OBJECT(clist), "select_row",
848                         GTK_SIGNAL_FUNC( edit_person_attrib_list_selected), NULL );
849         gtk_signal_connect( GTK_OBJECT(buttonDel), "clicked",
850                         GTK_SIGNAL_FUNC( edit_person_attrib_delete ), NULL );
851         gtk_signal_connect( GTK_OBJECT(buttonMod), "clicked",
852                         GTK_SIGNAL_FUNC( edit_person_attrib_modify ), NULL );
853         gtk_signal_connect( GTK_OBJECT(buttonAdd), "clicked",
854                         GTK_SIGNAL_FUNC( edit_person_attrib_add ), NULL );
855         gtk_signal_connect( GTK_OBJECT(buttonClr), "clicked",
856                         GTK_SIGNAL_FUNC( edit_person_attrib_clear ), NULL );
857
858         personeditdlg.clist_attrib  = clist;
859         personeditdlg.entry_atname  = entry_name;
860         personeditdlg.entry_atvalue = entry_value;
861 }
862
863 static void addressbook_edit_person_create( gboolean *cancelled ) {
864         addressbook_edit_person_dialog_create( cancelled );
865         addressbook_edit_person_page_basic( PAGE_BASIC, _( "Basic Data" ) );
866         addressbook_edit_person_page_email( PAGE_EMAIL, _( "E-Mail Address" ) );
867         addressbook_edit_person_page_attrib( PAGE_ATTRIBUTES, _( "User Attributes" ) );
868         gtk_widget_show_all( personeditdlg.window );
869 }
870
871 /*
872 * Return list of email items.
873 */
874 static GList *edit_person_build_email_list() {
875         GtkCList *clist = GTK_CLIST(personeditdlg.clist_email);
876         GList *listEMail = NULL;
877         ItemEMail *email;
878         gint row = 0;
879         while( (email = gtk_clist_get_row_data( clist, row )) ) {
880                 listEMail = g_list_append( listEMail, email );
881                 row++;
882         }
883         return listEMail;
884 }
885
886 /*
887 * Return list of attributes.
888 */
889 static GList *edit_person_build_attrib_list() {
890         GtkCList *clist = GTK_CLIST(personeditdlg.clist_attrib);
891         GList *listAttrib = NULL;
892         UserAttribute *attrib;
893         gint row = 0;
894         while( (attrib = gtk_clist_get_row_data( clist, row )) ) {
895                 listAttrib = g_list_append( listAttrib, attrib );
896                 row++;
897         }
898         return listAttrib;
899 }
900
901 /*
902 * Edit person.
903 * Enter: abf    Address book.
904 *        parent Parent folder for person (or NULL if adding to root folder). Argument is
905 *               only required for new objects).
906 *        person Person to edit, or NULL for a new person object.
907 *        pgMail If TRUE, E-Mail page will be activated.
908 * Return: Edited object, or NULL if cancelled.
909 */
910 ItemPerson *addressbook_edit_person( AddressBookFile *abf, ItemFolder *parent, ItemPerson *person, gboolean pgMail ) {
911         static gboolean cancelled;
912         GList *listEMail = NULL;
913         GList *listAttrib = NULL;
914         gchar *cn = NULL;
915
916         if (!personeditdlg.window)
917                 addressbook_edit_person_create(&cancelled);
918         gtk_widget_grab_focus(personeditdlg.ok_btn);
919         gtk_widget_grab_focus(personeditdlg.entry_name);
920         gtk_widget_show(personeditdlg.window);
921         manage_window_set_transient(GTK_WINDOW(personeditdlg.window));
922
923         /* Clear all fields */
924         personeditdlg.rowIndEMail = -1;
925         personeditdlg.rowIndAttrib = -1;
926         edit_person_status_show( "" );
927         gtk_clist_clear( GTK_CLIST(personeditdlg.clist_email) );
928         gtk_clist_clear( GTK_CLIST(personeditdlg.clist_attrib) );
929         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_name), "" );
930         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_first), "" );
931         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_last), "" );
932         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_nick), "" );
933
934         personeditdlg.editNew = FALSE;
935         if( person ) {
936                 if( ADDRITEM_NAME(person) )
937                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_name), ADDRITEM_NAME(person) );
938                 if( person->firstName )
939                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_first), person->firstName );
940                 if( person->lastName )
941                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_last), person->lastName );
942                 if( person->nickName )
943                         gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_nick), person->nickName );
944                 edit_person_load_email( person );
945                 edit_person_load_attrib( person );
946         }
947         else {
948                 personeditdlg.editNew = TRUE;
949         }
950
951         /* Select appropriate start page */
952         if( pgMail ) {
953                 gtk_notebook_set_page( GTK_NOTEBOOK(personeditdlg.notebook), PAGE_EMAIL );
954         }
955         else {
956                 gtk_notebook_set_page( GTK_NOTEBOOK(personeditdlg.notebook), PAGE_BASIC );
957         }
958
959         gtk_clist_select_row( GTK_CLIST(personeditdlg.clist_email), 0, 0 );
960         gtk_clist_select_row( GTK_CLIST(personeditdlg.clist_attrib), 0, 0 );
961         edit_person_email_clear( NULL );
962         edit_person_attrib_clear( NULL );
963
964         gtk_main();
965         gtk_widget_hide( personeditdlg.window );
966
967         listEMail = edit_person_build_email_list();
968         listAttrib = edit_person_build_attrib_list();
969         if( cancelled ) {
970                 addritem_free_list_email( listEMail );
971                 gtk_clist_clear( GTK_CLIST(personeditdlg.clist_email) );
972                 gtk_clist_clear( GTK_CLIST(personeditdlg.clist_attrib) );
973                 return NULL;
974         }
975
976         cn = g_strdup( gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_name), 0, -1 ) );
977         if( person ) {
978                 /* Update email/attribute list */
979                 addrbook_update_address_list( abf, person, listEMail );
980                 addrbook_update_attrib_list( abf, person, listAttrib );
981         }
982         else {
983                 /* Create new person and email/attribute list */
984                 if( cn == NULL || *cn == '\0' ) {
985                         /* Wasting our time */
986                         if( listEMail == NULL && listAttrib == NULL ) cancelled = TRUE;
987                 }
988                 if( ! cancelled ) {
989                         person = addrbook_add_address_list( abf, parent, listEMail );
990                         addrbook_add_attrib_list( abf, person, listAttrib );
991                 }
992         }
993
994         if( ! cancelled ) {
995                 /* Set person stuff */
996                 addritem_person_set_common_name( person, cn );
997                 addritem_person_set_first_name( person,
998                         gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_first), 0, -1 ) );
999                 addritem_person_set_last_name( person,
1000                         gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_last), 0, -1 ) );
1001                 addritem_person_set_nick_name( person,
1002                         gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_nick), 0, -1 ) );
1003         }
1004         g_free( cn );
1005
1006         listEMail = NULL;
1007
1008         gtk_clist_clear( GTK_CLIST(personeditdlg.clist_email) );
1009         gtk_clist_clear( GTK_CLIST(personeditdlg.clist_attrib) );
1010
1011         return person;
1012 }
1013
1014 /*
1015 * End of Source.
1016 */
1017