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