talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

editaddress.c (43373B)


      1 /*
      2  * Claws Mail -- a GTK based, lightweight, and fast e-mail client
      3  * Copyright (C) 1999-2022 the Claws Mail team and 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 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 #include "defs.h"
     20 
     21 #include <glib.h>
     22 #include <glib/gi18n.h>
     23 #include <gdk/gdkkeysyms.h>
     24 #include <gtk/gtk.h>
     25 
     26 #include "alertpanel.h"
     27 #include "stock_pixmap.h"
     28 #include "addressbook.h"
     29 #include "addressitem.h"
     30 #include "addritem.h"
     31 #include "addrbook.h"
     32 #include "manage_window.h"
     33 #include "gtkutils.h"
     34 #include "filesel.h"
     35 #include "codeconv.h"
     36 #include "editaddress.h"
     37 #include "prefs_common.h"
     38 #include "menu.h"
     39 #include "combobox.h"
     40 #include "file-utils.h"
     41 
     42 enum {
     43 	ATTRIB_COL_NAME,
     44 	ATTRIB_COL_VALUE,
     45 	ATTRIB_COL_PTR,
     46 	ATTRIB_N_COLS
     47 };
     48 
     49 typedef struct _PersonEdit_dlg PersonEditDlg;
     50 struct _PersonEdit_dlg {
     51 	GtkWidget *container;
     52 	GtkWidget *notebook;
     53 	GtkWidget *ok_btn;
     54 	GtkWidget *cancel_btn;
     55 	GtkWidget *statusbar;	/* used when prefs_common.addressbook_use_editaddress_dialog is TRUE */
     56 	GtkWidget *title;	/* used when prefs_common.addressbook_use_editaddress_dialog is FALSE */
     57 	gint status_cid;
     58 
     59 	/* User data tab */
     60 	GtkWidget *image;
     61 	gboolean picture_set;
     62 	GtkWidget *entry_name;
     63 	GtkWidget *entry_first;
     64 	GtkWidget *entry_last;
     65 	GtkWidget *entry_nick;
     66 
     67 	/* EMail data tab */
     68 	GtkWidget *entry_email;
     69 	GtkWidget *entry_alias;
     70 	GtkWidget *entry_remarks;
     71 	GtkWidget *view_email;
     72 	GtkWidget *email_up;
     73 	GtkWidget *email_down;
     74 	GtkWidget *email_del;
     75 	GtkWidget *email_mod;
     76 	GtkWidget *email_add;
     77 
     78 	gboolean editNew;
     79 	gboolean read_only;
     80 };
     81 
     82 /* transient data */
     83 static struct _PersonEdit_dlg personeditdlg;
     84 static AddressBookFile *current_abf = NULL;
     85 static ItemPerson *current_person = NULL;
     86 static ItemFolder *current_parent_folder = NULL;
     87 static EditAddressPostUpdateCallback edit_person_close_post_update_cb = NULL;
     88 
     89 typedef enum {
     90 	EMAIL_COL_EMAIL,
     91 	EMAIL_COL_ALIAS,
     92 	EMAIL_COL_REMARKS,
     93 	EMAIL_COL_PTR
     94 } PersonEditEMailColumnPos;
     95 
     96 #define EDITPERSON_WIDTH      520
     97 #define EDITPERSON_HEIGHT     320
     98 
     99 #define EMAIL_N_COLS          4
    100 #define EMAIL_COL_WIDTH_EMAIL 180
    101 #define EMAIL_COL_WIDTH_ALIAS 80
    102 
    103 #define ATTRIB_COL_WIDTH_NAME  240
    104 #define ATTRIB_COL_WIDTH_VALUE 0
    105 
    106 #define PAGE_BASIC             0
    107 #define PAGE_EMAIL             1
    108 
    109 static gboolean addressbook_edit_person_close( gboolean cancelled );
    110 static GList *edit_person_build_email_list();
    111 
    112 static gchar* edit_person_get_common_name_from_widgets(void)
    113 {
    114 	gchar *cn = NULL; /* cn must be freed by caller */
    115 
    116 	{
    117 		cn = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_name), 0, -1 );
    118 		if ( cn == NULL || *cn == '\0' ) {
    119 			gchar *first = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_first), 0, -1 );
    120 			gchar *last = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_last), 0, -1 );
    121 			cn = g_strdup_printf("%s%s%s", first?first:"", (first && last && *first && *last)?" ":"", last?last:"");
    122 			g_free(first);
    123 			g_free(last);
    124 		}
    125 		if ( cn == NULL || *cn == '\0' ) {
    126 			g_free(cn);
    127 			cn = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_nick), 0, -1 );
    128 		}
    129 	}
    130 	if ( cn != NULL )
    131 		g_strstrip(cn);
    132 	return cn;
    133 }
    134 
    135 static void edit_person_status_show( gchar *msg ) {
    136 	if( personeditdlg.statusbar != NULL ) {
    137 		gtk_statusbar_pop( GTK_STATUSBAR(personeditdlg.statusbar), personeditdlg.status_cid );
    138 		if( msg ) {
    139 			gtk_statusbar_push( GTK_STATUSBAR(personeditdlg.statusbar), personeditdlg.status_cid, msg );
    140 		}
    141 	}
    142 }
    143 
    144 static void edit_person_cancel(GtkWidget *widget, gboolean *cancelled) {
    145 	*cancelled = TRUE;
    146 	if (prefs_common.addressbook_use_editaddress_dialog)
    147 		gtk_main_quit();
    148 	else
    149 		addressbook_edit_person_close( *cancelled );
    150 }
    151 
    152 static void edit_person_ok(GtkWidget *widget, gboolean *cancelled) {
    153 	GList *listEMail = edit_person_build_email_list();
    154 	gchar *cn = edit_person_get_common_name_from_widgets();
    155 
    156 	if( (cn == NULL || *cn == '\0') && listEMail == NULL) {
    157 		gint val;
    158 
    159 		val = alertpanel( _("Add New Person"),
    160 				_("Adding a new person requires at least one of the\n"
    161 				  "following values to be set:\n"
    162 				  " - Display Name\n"
    163 				  " - First Name\n"
    164 				  " - Last Name\n"
    165 				  " - Nickname\n"
    166 				  " - any email address\n"
    167 				  " - any additional attribute\n\n"
    168 				  "Click OK to keep editing this contact.\n"
    169 				  "Click Cancel to close without saving."),
    170 				NULL, _("_Cancel"), NULL, _("_OK"), NULL, NULL, ALERTFOCUS_SECOND );
    171 		if( val == G_ALERTDEFAULT ) {
    172 			edit_person_cancel(widget, cancelled);
    173 		}
    174 		g_free( cn );
    175 		return;
    176 	}
    177 	g_free( cn );
    178 
    179 	*cancelled = FALSE;
    180 	if (prefs_common.addressbook_use_editaddress_dialog)
    181 		gtk_main_quit();
    182 	else
    183 		addressbook_edit_person_close( *cancelled );
    184 }
    185 
    186 /* Updated up/down buttons sensitivity, depending on list
    187  * cursor position */
    188 static void edit_person_email_update_buttons()
    189 {
    190 	GtkTreeModel *model;
    191 	GtkTreeIter iter, otheriter;
    192 	GtkTreePath *path;
    193 	gboolean has_prev;
    194 	ItemEMail *email;
    195 
    196 	email = gtkut_tree_view_get_selected_pointer(
    197 			GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
    198 			&model, NULL, &iter);
    199 
    200 	if (email) {
    201 		if (!personeditdlg.read_only) {
    202 			otheriter = iter;
    203 			path = gtk_tree_model_get_path(model, &otheriter);
    204 			has_prev = gtk_tree_path_prev(path);
    205 			if (has_prev) {
    206 				gtk_tree_model_get_iter(model, &otheriter, path);
    207 			}
    208 			gtk_widget_set_sensitive(personeditdlg.email_up, has_prev);
    209 
    210 			otheriter = iter;
    211 			gtk_widget_set_sensitive(personeditdlg.email_down,
    212 					gtk_tree_model_iter_next(model, &otheriter));
    213 		}
    214 	} else {
    215 		gtk_widget_set_sensitive(personeditdlg.email_del, FALSE);
    216 		gtk_widget_set_sensitive(personeditdlg.email_up, FALSE);
    217 		gtk_widget_set_sensitive(personeditdlg.email_down, FALSE);
    218 	}
    219 }
    220 
    221 static void edit_person_email_cursor_changed(GtkTreeView *view,
    222 		gpointer user_data)
    223 {
    224 	GtkTreeModel *model;
    225 	GtkTreeIter iter;
    226 	ItemEMail *email;
    227 
    228 	email = gtkut_tree_view_get_selected_pointer(
    229 			GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
    230 			&model, NULL, &iter);
    231 
    232 	if (email != NULL) {
    233 		if (email->address != NULL)
    234 			gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_email),
    235 					email->address);
    236 		if (ADDRITEM_NAME(email) != NULL)
    237 			gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_alias),
    238 					ADDRITEM_NAME(email));
    239 		if (email->remarks != NULL)
    240 			gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_remarks),
    241 					email->remarks);
    242 	}
    243 
    244 	edit_person_email_update_buttons();
    245 }
    246 
    247 
    248 static gint edit_person_delete_event(GtkWidget *widget, GdkEventAny *event, gboolean *cancelled) {
    249 	*cancelled = TRUE;
    250 	if (prefs_common.addressbook_use_editaddress_dialog)
    251 		gtk_main_quit();
    252 	else
    253 		addressbook_edit_person_close( *cancelled );
    254 	return TRUE;
    255 }
    256 
    257 static gchar *_title_new_ = NULL;
    258 static gchar *_title_edit_ = NULL;
    259 
    260 static void edit_person_set_widgets_title( gchar *text )
    261 {
    262 	gchar *label = NULL;
    263 
    264 	cm_return_if_fail( text != NULL );
    265 
    266 	gtk_label_set_text(GTK_LABEL(personeditdlg.title), "");
    267 	label = g_markup_printf_escaped("<b>%s</b>", text);
    268 	gtk_label_set_markup(GTK_LABEL(personeditdlg.title), label);
    269 	g_free(label);
    270 }
    271 
    272 static void edit_person_set_window_title( gint pageNum ) {
    273 	gchar *sTitle;
    274 
    275 	if( _title_new_ == NULL ) {
    276 		_title_new_ = g_strdup( _("Add New Person") );
    277 		_title_edit_ = g_strdup( _("Edit Person Details") );
    278 	}
    279 
    280 	if( pageNum == PAGE_BASIC ) {
    281 		if( personeditdlg.editNew ) {
    282 			if (prefs_common.addressbook_use_editaddress_dialog)
    283 				gtk_window_set_title( GTK_WINDOW(personeditdlg.container), _title_new_ );
    284 			else
    285 				edit_person_set_widgets_title( _title_new_ );
    286 		}
    287 		else {
    288 			if (prefs_common.addressbook_use_editaddress_dialog)
    289 				gtk_window_set_title( GTK_WINDOW(personeditdlg.container), _title_edit_ );
    290 			else
    291 				edit_person_set_widgets_title( _title_edit_ );
    292 		}
    293 	}
    294 	else {
    295 		if( personeditdlg.entry_name == NULL ) {
    296 			sTitle = g_strdup( _title_edit_ );
    297 		}
    298 		else {
    299 			gchar *name;
    300 			name = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_name), 0, -1 );
    301 			g_strstrip(name);
    302 			if ( *name != '\0' )
    303 				sTitle = g_strdup_printf( "%s - %s", _title_edit_, name );
    304 			else
    305 				sTitle = g_strdup( _title_edit_ );
    306 			g_free( name );
    307 		}
    308 		if (prefs_common.addressbook_use_editaddress_dialog)
    309 			gtk_window_set_title( GTK_WINDOW(personeditdlg.container), sTitle );
    310 		else
    311 			edit_person_set_widgets_title( sTitle );
    312 		g_free( sTitle );
    313 	}
    314 }
    315 
    316 static void edit_person_email_clear( gpointer data ) {
    317 	gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_email), "" );
    318 	gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_alias), "" );
    319 	gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_remarks), "" );
    320 }
    321 
    322 static void edit_person_switch_page( GtkNotebook *notebook, gpointer page,
    323 					gint pageNum, gpointer user_data)
    324 {
    325 	edit_person_set_window_title( pageNum );
    326 	edit_person_status_show( "" );
    327 }
    328 
    329 /*
    330 * Load clist with a copy of person's email addresses.
    331 */
    332 static void edit_person_load_email( ItemPerson *person ) {
    333 	GList *node = person->listEMail;
    334 	GtkTreeModel *model = gtk_tree_view_get_model(
    335 			GTK_TREE_VIEW(personeditdlg.view_email));
    336 	GtkTreeIter iter;
    337 
    338 	while( node ) {
    339 		ItemEMail *emorig = ( ItemEMail * ) node->data;
    340 		ItemEMail *email = addritem_copyfull_item_email( emorig );
    341 
    342 		gtk_list_store_append(GTK_LIST_STORE(model), &iter);
    343 		gtk_list_store_set(GTK_LIST_STORE(model), &iter,
    344 				EMAIL_COL_EMAIL, email->address,
    345 				EMAIL_COL_ALIAS, email->obj.name,
    346 				EMAIL_COL_REMARKS, email->remarks,
    347 				EMAIL_COL_PTR, email,
    348 				-1);
    349 
    350 		node = g_list_next( node );
    351 	}
    352 }
    353 
    354 static void edit_person_email_move_up( gpointer data ) {
    355 	GtkTreeModel *model;
    356 	GtkTreeIter iter, otheriter;
    357 	GtkTreePath *path;
    358 	ItemEMail *email;
    359 	gboolean has_prev;
    360 
    361 	edit_person_email_clear( NULL );
    362 	edit_person_status_show( NULL );
    363 
    364 	email = gtkut_tree_view_get_selected_pointer(
    365 			GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
    366 			&model, NULL, &iter);
    367 
    368 	if( email ) {
    369 		otheriter = iter;
    370 		/* GTK+2 does not have gtk_tree_model_iter_previous(), so
    371 		 * we have to go through GtkTreePath */
    372 		path = gtk_tree_model_get_path(model, &otheriter);
    373 		has_prev = gtk_tree_path_prev(path);
    374 		if (has_prev) {
    375 			gtk_tree_model_get_iter(model, &otheriter, path);
    376 			gtk_list_store_move_before(GTK_LIST_STORE(model), &iter, &otheriter);
    377 		}
    378 		gtk_tree_path_free(path);
    379 	}
    380 
    381 	edit_person_email_update_buttons();
    382 }
    383 
    384 static void edit_person_email_move_down( gpointer data ) {
    385 	GtkTreeModel *model;
    386 	GtkTreeIter iter, otheriter;
    387 	ItemEMail *email;
    388 
    389 	edit_person_email_clear( NULL );
    390 	edit_person_status_show( NULL );
    391 
    392 	email = gtkut_tree_view_get_selected_pointer(
    393 			GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
    394 			&model, NULL, &iter);
    395 
    396 	if( email ) {
    397 		otheriter = iter;
    398 		if (gtk_tree_model_iter_next(model, &otheriter)) {
    399 			gtk_list_store_move_after(GTK_LIST_STORE(model), &iter, &otheriter);
    400 		}
    401 	}
    402 
    403 	edit_person_email_update_buttons();
    404 }
    405 
    406 static void edit_person_email_delete( gpointer data ) {
    407 	GtkTreeModel *model;
    408 	GtkTreeIter iter;
    409 	GtkTreeSelection *sel;
    410 	ItemEMail *email;
    411 	gboolean has_row = FALSE;
    412 	gint n;
    413 
    414 	edit_person_email_clear( NULL );
    415 	edit_person_status_show( NULL );
    416 
    417 	email = gtkut_tree_view_get_selected_pointer(
    418 			GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
    419 			&model, &sel, &iter);
    420 
    421 	if( email ) {
    422 		/* Remove list entry and set iter to next row, if any */
    423 		has_row = gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
    424 		addritem_free_item_email( email );
    425 		email = NULL;
    426 	}
    427 
    428 	/* Position hilite bar */
    429 	if (!has_row) {
    430 		/* The removed row was the last in the list, so iter is not
    431 		 * valid. Find out if there is at least one row remaining
    432 		 * in the list, and select the last one if so. */
    433 		n = gtk_tree_model_iter_n_children(model, NULL);
    434 		if (n > 0 && gtk_tree_model_iter_nth_child(model, &iter, NULL, n-1)) {
    435 			/* It exists */
    436 			has_row = TRUE;
    437 		}
    438 	}
    439 
    440 	if (has_row)
    441 		gtk_tree_selection_select_iter(sel, &iter);
    442 
    443 	edit_person_email_cursor_changed(
    444 			GTK_TREE_VIEW(personeditdlg.view_email), NULL);
    445 }
    446 
    447 static ItemEMail *edit_person_email_edit( gboolean *error, ItemEMail *email ) {
    448 	ItemEMail *retVal = NULL;
    449 	gchar *sEmail, *sAlias, *sRemarks;
    450 
    451 	*error = TRUE;
    452 	sAlias = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_alias), 0, -1 );
    453 	sRemarks = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_remarks), 0, -1 );
    454 
    455 	sEmail = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_email), 0, -1 );
    456 	g_strstrip(sEmail);
    457 	if (sEmail) {
    458 		if( email == NULL ) {
    459 			email = addritem_create_item_email();
    460 		}
    461 		addritem_email_set_address( email, sEmail );
    462 		addritem_email_set_alias( email, sAlias );
    463 		addritem_email_set_remarks( email, sRemarks );
    464 		retVal = email;
    465 		*error = FALSE;
    466 	}
    467 	else {
    468 		edit_person_status_show( _( "An Email address must be supplied." ) );
    469 	}
    470 
    471 	g_free( sEmail );
    472 	g_free( sAlias );
    473 	g_free( sRemarks );
    474 
    475 	return retVal;
    476 }
    477 
    478 static void edit_person_email_modify( gpointer data ) {
    479 	GtkTreeModel *model;
    480 	GtkTreeIter iter;
    481 	gboolean errFlg = FALSE;
    482 	ItemEMail *email;
    483 
    484 	email = gtkut_tree_view_get_selected_pointer(
    485 			GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
    486 			&model, NULL, &iter);
    487 
    488 	if( email ) {
    489 		edit_person_email_edit( &errFlg, email );
    490 		if( ! errFlg ) {
    491 			gtk_list_store_set(GTK_LIST_STORE(model), &iter,
    492 					EMAIL_COL_EMAIL, email->address,
    493 					EMAIL_COL_ALIAS, email->obj.name,
    494 					EMAIL_COL_REMARKS, email->remarks,
    495 					-1);
    496 			edit_person_email_clear( NULL );
    497 		}
    498 	}
    499 }
    500 
    501 static void edit_person_email_add( gpointer data ) {
    502 	GtkTreeModel *model;
    503 	GtkTreeIter iter, otheriter;
    504 	GtkTreeSelection *sel;
    505 	gboolean errFlg = FALSE, prev_exists = FALSE;
    506 	ItemEMail *email = NULL;
    507 
    508 	email = gtkut_tree_view_get_selected_pointer(
    509 			GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
    510 			&model, &sel, &otheriter);
    511 	if (email != NULL)
    512 		prev_exists = TRUE;
    513 
    514 	email = edit_person_email_edit( &errFlg, NULL );
    515 	if( ! errFlg ) {
    516 		if (prev_exists)
    517 			gtk_list_store_insert_after(GTK_LIST_STORE(model), &iter, &otheriter);
    518 		else /* list is empty */
    519 			gtk_list_store_append(GTK_LIST_STORE(model), &iter);
    520 
    521 		gtk_list_store_set(GTK_LIST_STORE(model), &iter,
    522 					EMAIL_COL_EMAIL, email->address,
    523 					EMAIL_COL_ALIAS, email->obj.name,
    524 					EMAIL_COL_REMARKS, email->remarks,
    525 					EMAIL_COL_PTR, email,
    526 					-1);
    527 		gtk_tree_selection_select_iter(sel, &iter);
    528 		edit_person_email_update_buttons();
    529 
    530 		edit_person_email_clear( NULL );
    531 	}
    532 }
    533 
    534 static gboolean list_find_email(const gchar *addr)
    535 {
    536 	GtkWidget *view = personeditdlg.view_email;
    537 	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
    538 	GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
    539 	GtkTreeIter iter;
    540 	ItemEMail *email;
    541 
    542 	if (!gtk_tree_model_get_iter_first(model, &iter))
    543 		return FALSE;
    544 
    545 	do {
    546 		gtk_tree_model_get(model, &iter, EMAIL_COL_PTR, &email, -1);
    547 		if (!g_ascii_strcasecmp(email->address, addr)) {
    548 			gtk_tree_selection_select_iter(sel, &iter);
    549 			return TRUE;
    550 		}
    551 	} while (gtk_tree_model_iter_next(model, &iter));
    552 
    553 	return FALSE;
    554 }
    555 
    556 /*!
    557  *\brief	Save Gtk object size to prefs dataset
    558  */
    559 static void edit_person_size_allocate_cb(GtkWidget *widget,
    560 					 GtkAllocation *allocation)
    561 {
    562 	cm_return_if_fail(allocation != NULL);
    563 
    564 	gtk_window_get_size(GTK_WINDOW(widget),
    565 		&prefs_common.addressbookeditpersonwin_width, &prefs_common.addressbookeditpersonwin_height);
    566 }
    567 
    568 /* build edit person widgets, return a pointer to the main container of the widgetset (a vbox) */
    569 static GtkWidget* addressbook_edit_person_widgets_create( GtkWidget* container, gboolean *cancelled )
    570 {
    571 	GtkWidget *vbox;
    572 	GtkWidget *vnbox;
    573 	GtkWidget *notebook;
    574 	GtkWidget *hbbox;
    575 	GtkWidget *ok_btn;
    576 	GtkWidget *cancel_btn;
    577 
    578 	vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
    579 	 gtk_container_set_border_width(GTK_CONTAINER(vbox), BORDER_WIDTH);
    580 	gtk_widget_show(vbox);
    581 	gtk_container_add(GTK_CONTAINER(container), vbox);
    582 
    583 	vnbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
    584 	gtk_container_set_border_width(GTK_CONTAINER(vnbox), 4);
    585 	gtk_widget_show(vnbox);
    586 	gtk_box_pack_start(GTK_BOX(vbox), vnbox, TRUE, TRUE, 0);
    587 
    588 	/* Notebook */
    589 	notebook = gtk_notebook_new();
    590 	gtk_widget_show(notebook);
    591 	gtk_box_pack_start(GTK_BOX(vnbox), notebook, TRUE, TRUE, 0);
    592 	gtk_container_set_border_width(GTK_CONTAINER(notebook), 6);
    593 
    594 	/* Button panel */
    595 	if (prefs_common.addressbook_use_editaddress_dialog)
    596 	gtkut_stock_button_set_create(&hbbox, &cancel_btn, NULL, _("_Cancel"),
    597 				      &ok_btn, NULL, _("_OK"),
    598 				      NULL, NULL, NULL);
    599 	else
    600 		gtkut_stock_with_text_button_set_create(&hbbox,
    601 					  &cancel_btn, NULL, _("Discard"),
    602 				      &ok_btn, NULL, _("Apply"),
    603 				      NULL, NULL, NULL);
    604 	gtk_box_pack_end(GTK_BOX(vnbox), hbbox, FALSE, FALSE, 0);
    605 	gtk_widget_grab_default(ok_btn);
    606 
    607 	g_signal_connect(G_OBJECT(ok_btn), "clicked",
    608 			 G_CALLBACK(edit_person_ok), cancelled);
    609 	g_signal_connect(G_OBJECT(cancel_btn), "clicked",
    610 			 G_CALLBACK(edit_person_cancel), cancelled);
    611 	g_signal_connect(G_OBJECT(notebook), "switch_page",
    612 			 G_CALLBACK(edit_person_switch_page), NULL );
    613 
    614 	gtk_widget_show_all(vbox);
    615 
    616 	personeditdlg.notebook   = notebook;
    617 	personeditdlg.ok_btn     = ok_btn;
    618 	personeditdlg.cancel_btn = cancel_btn;
    619 
    620 	return vbox;
    621 }
    622 
    623 static void addressbook_edit_person_dialog_create( gboolean *cancelled ) {
    624 	GtkWidget *window;
    625 	GtkWidget *hsbox;
    626 	GtkWidget *vbox;
    627 	GtkWidget *statusbar;
    628 	static GdkGeometry geometry;
    629 
    630 	window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "editaddress");
    631 	/* gtk_container_set_border_width(GTK_CONTAINER(window), 0); */
    632 	gtk_window_set_title(GTK_WINDOW(window), _("Edit Person Data"));
    633 	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    634 	gtk_window_set_modal(GTK_WINDOW(window), TRUE);
    635 	gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
    636 	g_signal_connect(G_OBJECT(window), "delete_event",
    637 			 G_CALLBACK(edit_person_delete_event),
    638 			 cancelled);
    639 	g_signal_connect(G_OBJECT(window), "size_allocate",
    640 			 G_CALLBACK(edit_person_size_allocate_cb),
    641 			cancelled);
    642 
    643 	vbox = addressbook_edit_person_widgets_create(window, cancelled);
    644 
    645 	/* Status line */
    646 	hsbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
    647 	gtk_box_pack_end(GTK_BOX(vbox), hsbox, FALSE, FALSE, BORDER_WIDTH);
    648 	statusbar = gtk_statusbar_new();
    649 	gtk_box_pack_start(GTK_BOX(hsbox), statusbar, TRUE, TRUE, BORDER_WIDTH);
    650 
    651 	if (!geometry.min_height) {
    652 		geometry.min_width = EDITPERSON_WIDTH;
    653 		geometry.min_height = EDITPERSON_HEIGHT;
    654 	}
    655 
    656 	gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
    657 				      GDK_HINT_MIN_SIZE);
    658 	gtk_window_set_default_size(GTK_WINDOW(window),
    659 				    prefs_common.addressbookeditpersonwin_width,
    660 				    prefs_common.addressbookeditpersonwin_height);
    661 
    662 	personeditdlg.container  = window;
    663 	personeditdlg.statusbar  = statusbar;
    664 	personeditdlg.status_cid = gtk_statusbar_get_context_id( GTK_STATUSBAR(statusbar), "Edit Person Dialog" );
    665 
    666 }
    667 
    668 /* parent must be a box */
    669 static void addressbook_edit_person_widgetset_create( GtkWidget *parent, gboolean *cancelled )
    670 {
    671 	GtkWidget *vbox;
    672 	GtkWidget *label;
    673 
    674 	if ( parent == NULL )
    675 		g_warning("addressbook_edit_person_widgetset_create: parent is NULL");
    676 
    677 	vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    678 	gtk_box_pack_end(GTK_BOX(parent), vbox, TRUE, TRUE, 0);
    679 
    680 	label = gtk_label_new(_("Edit Person Data"));
    681 	gtk_label_set_justify( GTK_LABEL(label), GTK_JUSTIFY_CENTER);
    682 	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
    683 
    684 	addressbook_edit_person_widgets_create(vbox, cancelled);
    685 
    686 	gtk_widget_set_size_request(vbox, EDITPERSON_WIDTH, EDITPERSON_HEIGHT);
    687 
    688 	personeditdlg.container = vbox;
    689 	personeditdlg.title = label;
    690 	personeditdlg.statusbar  = NULL;
    691 	personeditdlg.status_cid = 0;
    692 }
    693 
    694 void addressbook_edit_person_widgetset_hide( void )
    695 {
    696 	if ( personeditdlg.container )
    697 		gtk_widget_hide( personeditdlg.container );
    698 }
    699 
    700 static void addressbook_edit_person_set_picture(void)
    701 {
    702 	GError *error = NULL;
    703 	gchar *filename;
    704 	int width, height, scalewidth, scaleheight;
    705 
    706 	if ( (filename = filesel_select_file_open(_("Choose a picture"), NULL)) ) {
    707 		GdkPixbuf *pixbuf = NULL;
    708 		gdk_pixbuf_get_file_info(filename, &width, &height);
    709 
    710 		if ( width > 128 || height > 128 ) {
    711 			if (width > height) {
    712 				scaleheight = (height * 128) / width;
    713 				scalewidth = 128;
    714 			}
    715 			else {
    716 				scalewidth = (width * 128) / height;
    717 				scaleheight = 128;
    718 			}
    719 			pixbuf = gdk_pixbuf_new_from_file_at_scale(filename,
    720 					scalewidth, scaleheight, TRUE, &error);
    721 		} else {
    722 			pixbuf = gdk_pixbuf_new_from_file(filename, &error);
    723 		}
    724 		if (error) {
    725 			alertpanel_error(_("Failed to import image: \n%s"),
    726 					error->message);
    727 			g_error_free(error);
    728 			error = NULL;
    729 			/* keep the previous picture if any */
    730 			g_free(filename);
    731 			if (pixbuf)
    732 				g_object_unref(pixbuf);
    733 			return;
    734 		}
    735 		personeditdlg.picture_set = TRUE;
    736 		cm_menu_set_sensitive("EditAddressPopup/UnsetPicture", personeditdlg.picture_set);
    737 		g_free(filename);
    738 		gtk_image_set_from_pixbuf(GTK_IMAGE(personeditdlg.image), pixbuf);
    739 		g_object_unref(pixbuf);
    740 	}
    741 }
    742 
    743 static void addressbook_edit_person_clear_picture(void)
    744 {
    745 	GdkPixbuf *pixbuf;
    746 
    747 	stock_pixbuf_gdk(STOCK_PIXMAP_ANONYMOUS, &pixbuf);
    748 	personeditdlg.picture_set = FALSE;
    749 	cm_menu_set_sensitive("EditAddressPopup/UnsetPicture", personeditdlg.picture_set);
    750 	gtk_image_set_from_pixbuf(GTK_IMAGE(personeditdlg.image), pixbuf);
    751 }
    752 
    753 static void addressbook_edit_person_set_picture_menu_cb (GtkAction *action, gpointer data)
    754 {
    755 	addressbook_edit_person_set_picture();
    756 }
    757 
    758 static void addressbook_edit_person_unset_picture_menu_cb (GtkAction *action, gpointer data)
    759 {
    760 	addressbook_edit_person_clear_picture();
    761 }
    762 
    763 static GtkWidget *editaddr_popup_menu = NULL;
    764 static GtkActionEntry editaddr_popup_entries[] =
    765 {
    766 	{"EditAddressPopup",			NULL, "EditAddressPopup", NULL, NULL, NULL },
    767 	{"EditAddressPopup/SetPicture",		NULL, N_("_Set picture"), NULL, NULL, G_CALLBACK(addressbook_edit_person_set_picture_menu_cb) },
    768 	{"EditAddressPopup/UnsetPicture",	NULL, N_("_Unset picture"), NULL, NULL, G_CALLBACK(addressbook_edit_person_unset_picture_menu_cb) },
    769 };
    770 
    771 static void addressbook_edit_person_set_picture_cb(GtkWidget *widget,
    772 		GdkEventButton *event, gpointer data)
    773 {
    774 	if (event->button == 1) {
    775 		addressbook_edit_person_set_picture();
    776 	} else {
    777 		gtk_menu_popup_at_pointer(GTK_MENU(editaddr_popup_menu), NULL);
    778 	}
    779 }
    780 
    781 static gboolean addressbook_edit_person_picture_popup_menu(GtkWidget *widget, gpointer data)
    782 {
    783 	GdkEventButton event;
    784 
    785 	event.button = 3;
    786 	event.time = gtk_get_current_event_time();
    787 
    788 	addressbook_edit_person_set_picture_cb(NULL, &event, data);
    789 
    790 	return TRUE;
    791 }
    792 
    793 static void addressbook_edit_person_page_basic( gint pageNum, gchar *pageLbl ) {
    794 	GtkWidget *vbox;
    795 	GtkWidget *hbox;
    796 	GtkWidget *table;
    797 	GtkWidget *label;
    798 	GtkWidget *ebox_picture;
    799 	GtkWidget *frame_picture;
    800 	GtkWidget *entry_name;
    801 	GtkWidget *entry_fn;
    802 	GtkWidget *entry_ln;
    803 	GtkWidget *entry_nn;
    804 	const gchar *locale;
    805 	gint top = 0;
    806 
    807 	vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 20 );
    808 	hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8 );
    809 
    810 	gtk_widget_show( vbox );
    811 
    812 	if (!editaddr_popup_menu) {
    813 		cm_menu_create_action_group("EditAddressPopup", editaddr_popup_entries,
    814 			G_N_ELEMENTS(editaddr_popup_entries), (gpointer)NULL);
    815 		MENUITEM_ADDUI("/Menus", "EditAddressPopup", "EditAddressPopup", GTK_UI_MANAGER_MENU)
    816 		MENUITEM_ADDUI("/Menus/EditAddressPopup", "SetPicture", "EditAddressPopup/SetPicture", GTK_UI_MANAGER_MENUITEM)
    817 		MENUITEM_ADDUI("/Menus/EditAddressPopup", "UnsetPicture", "EditAddressPopup/UnsetPicture", GTK_UI_MANAGER_MENUITEM)
    818 
    819 		editaddr_popup_menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
    820 			gtk_ui_manager_get_widget(gtkut_ui_manager(), "/Menus/EditAddressPopup")) );
    821 	}
    822 	/* User's picture */
    823 	ebox_picture = gtk_event_box_new();
    824 	frame_picture = gtk_frame_new(_("Photo"));
    825 
    826 	/* Room for a photo */
    827 	personeditdlg.image = gtk_image_new();
    828 	addressbook_edit_person_clear_picture();
    829 
    830 	gtk_container_add(GTK_CONTAINER(ebox_picture), personeditdlg.image);
    831 	gtk_container_add(GTK_CONTAINER(frame_picture), ebox_picture);
    832 	gtk_container_add(GTK_CONTAINER( personeditdlg.notebook ), hbox );
    833 	gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
    834 	gtk_container_set_border_width( GTK_CONTAINER (hbox), BORDER_WIDTH );
    835 
    836 	label = gtk_label_new_with_mnemonic( pageLbl );
    837 	gtk_widget_show( label );
    838 
    839 	gtk_box_pack_start(GTK_BOX(hbox), frame_picture, TRUE, TRUE, 0);
    840 
    841 	gtk_notebook_set_tab_label(
    842 		GTK_NOTEBOOK( personeditdlg.notebook ),
    843 		gtk_notebook_get_nth_page( GTK_NOTEBOOK( personeditdlg.notebook ), pageNum ), label );
    844 
    845 	g_signal_connect(G_OBJECT(ebox_picture), "popup-menu",
    846 			 G_CALLBACK(addressbook_edit_person_picture_popup_menu), NULL);
    847 	g_signal_connect(G_OBJECT(ebox_picture), "button_press_event",
    848 			G_CALLBACK(addressbook_edit_person_set_picture_cb), NULL);
    849 
    850 	table = gtk_grid_new();
    851 
    852 #define ATTACH_ROW(text, entry) \
    853 { \
    854 	label = gtk_label_new(text); \
    855 	gtk_grid_attach(GTK_GRID(table), label, 0, top, 1, 1); \
    856 	gtk_label_set_xalign(GTK_LABEL(label), 0.0); \
    857  \
    858 	entry = gtk_entry_new(); \
    859 	gtk_grid_attach(GTK_GRID(table), entry, 1, top, 1, 1); \
    860 	gtk_widget_set_hexpand(entry, TRUE); \
    861 	gtk_widget_set_halign(entry, GTK_ALIGN_FILL); \
    862 	top++; \
    863 }
    864 
    865 #define ATTACH_HIDDEN_ROW(text, entry) \
    866 { \
    867 	entry = gtk_entry_new(); \
    868 }
    869 
    870 	ATTACH_ROW(_("Display Name"), entry_name);
    871 	locale = conv_get_current_locale();
    872 	if (locale &&
    873 	    (!g_ascii_strncasecmp(locale, "hu", 2) ||
    874 	     !g_ascii_strncasecmp(locale, "ja", 2) ||
    875 	     !g_ascii_strncasecmp(locale, "ko", 2) ||
    876 	     !g_ascii_strncasecmp(locale, "vi", 2) ||
    877 	     !g_ascii_strncasecmp(locale, "zh", 2))) {
    878 		ATTACH_ROW(_("Last Name"), entry_ln);
    879 		ATTACH_ROW(_("First Name"), entry_fn);
    880 	} else {
    881 		ATTACH_ROW(_("First Name"), entry_fn);
    882 		ATTACH_ROW(_("Last Name"), entry_ln);
    883 	}
    884 	ATTACH_ROW(_("Nickname"), entry_nn);
    885 #undef ATTACH_ROW
    886 #undef ATTACH_HIDDEN_ROW
    887 	gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
    888 	gtk_box_pack_end(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
    889 	gtk_container_set_border_width( GTK_CONTAINER(table), 8 );
    890 	gtk_grid_set_row_spacing(GTK_GRID(table), 15);
    891 	gtk_grid_set_column_spacing(GTK_GRID(table), 8);
    892 
    893 	gtk_widget_show_all(vbox);
    894 	personeditdlg.entry_name  = entry_name;
    895 	personeditdlg.entry_first = entry_fn;
    896 	personeditdlg.entry_last  = entry_ln;
    897 	personeditdlg.entry_nick  = entry_nn;
    898 }
    899 
    900 static gboolean email_adding = FALSE, email_saving = FALSE;
    901 
    902 static void edit_person_entry_email_changed (GtkWidget *entry, gpointer data)
    903 {
    904 	GtkTreeModel *model = gtk_tree_view_get_model(
    905 			GTK_TREE_VIEW(personeditdlg.view_email));
    906 	gboolean non_empty = (gtk_tree_model_iter_n_children(model, NULL) > 0);
    907 
    908 	if (personeditdlg.read_only)
    909 		return;
    910 
    911 	if (gtk_entry_get_text(GTK_ENTRY(personeditdlg.entry_email)) == NULL
    912 	||  strlen(gtk_entry_get_text(GTK_ENTRY(personeditdlg.entry_email))) == 0) {
    913 		gtk_widget_set_sensitive(personeditdlg.email_add,FALSE);
    914 		gtk_widget_set_sensitive(personeditdlg.email_mod,FALSE);
    915 		email_adding = FALSE;
    916 		email_saving = FALSE;
    917 	} else if (list_find_email(gtk_entry_get_text(GTK_ENTRY(personeditdlg.entry_email)))) {
    918 		gtk_widget_set_sensitive(personeditdlg.email_add,FALSE);
    919 		gtk_widget_set_sensitive(personeditdlg.email_mod,non_empty);
    920 		email_adding = FALSE;
    921 		email_saving = non_empty;
    922 	} else {
    923 		gtk_widget_set_sensitive(personeditdlg.email_add,TRUE);
    924 		gtk_widget_set_sensitive(personeditdlg.email_mod,non_empty);
    925 		email_adding = TRUE;
    926 		email_saving = non_empty;
    927 	}
    928 }
    929 
    930 static gboolean edit_person_entry_email_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
    931 {
    932 	if (event && (event->keyval == GDK_KEY_KP_Enter ||
    933 	    event->keyval == GDK_KEY_Return)) {
    934 		if (email_saving)
    935 			edit_person_email_modify(NULL);
    936 		else if (email_adding)
    937 			edit_person_email_add(NULL);
    938 	}
    939 	return FALSE;
    940 }
    941 
    942 
    943 static void addressbook_edit_person_page_email( gint pageNum, gchar *pageLbl ) {
    944 	GtkWidget *vbox;
    945 	GtkWidget *hbox;
    946 	GtkWidget *vboxl;
    947 	GtkWidget *vboxb;
    948 	GtkWidget *vbuttonbox;
    949 	GtkWidget *buttonUp;
    950 	GtkWidget *buttonDown;
    951 	GtkWidget *buttonDel;
    952 	GtkWidget *buttonMod;
    953 	GtkWidget *buttonAdd;
    954 
    955 	GtkWidget *table;
    956 	GtkWidget *label;
    957 	GtkWidget *scrollwin;
    958 	GtkWidget *view;
    959 	GtkWidget *entry_email;
    960 	GtkWidget *entry_alias;
    961 	GtkWidget *entry_remarks;
    962 	GtkListStore *store;
    963 	GtkTreeViewColumn *col;
    964 	GtkCellRenderer *rdr;
    965 	GtkTreeSelection *sel;
    966 
    967 	vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8 );
    968 	gtk_widget_show( vbox );
    969 	gtk_container_add( GTK_CONTAINER( personeditdlg.notebook ), vbox );
    970 	gtk_container_set_border_width( GTK_CONTAINER (vbox), BORDER_WIDTH );
    971 
    972 	label = gtk_label_new_with_mnemonic( pageLbl );
    973 	gtk_widget_show( label );
    974 	gtk_notebook_set_tab_label(
    975 		GTK_NOTEBOOK( personeditdlg.notebook ),
    976 		gtk_notebook_get_nth_page( GTK_NOTEBOOK( personeditdlg.notebook ), pageNum ), label );
    977 
    978 	/* Split into two areas */
    979 	hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0 );
    980 	gtk_container_add( GTK_CONTAINER( vbox ), hbox );
    981 
    982 	/* Address list */
    983 	vboxl = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4 );
    984 	gtk_container_add( GTK_CONTAINER( hbox ), vboxl );
    985 	gtk_container_set_border_width( GTK_CONTAINER(vboxl), 4 );
    986 
    987 	scrollwin = gtk_scrolled_window_new( NULL, NULL );
    988 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
    989 				       GTK_POLICY_AUTOMATIC,
    990 				       GTK_POLICY_AUTOMATIC);
    991 	gtk_scrolled_window_set_propagate_natural_height(GTK_SCROLLED_WINDOW(scrollwin), TRUE);
    992 
    993 	store = gtk_list_store_new(EMAIL_N_COLS,
    994 			G_TYPE_STRING,
    995 			G_TYPE_STRING,
    996 			G_TYPE_STRING,
    997 			G_TYPE_POINTER,
    998 			-1);
    999 
   1000 	view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
   1001 	g_object_unref(store);
   1002 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), TRUE);
   1003 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
   1004 	gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
   1005 
   1006 	rdr = gtk_cell_renderer_text_new();
   1007 	col = gtk_tree_view_column_new_with_attributes(_("Email Address"), rdr,
   1008 			"markup", EMAIL_COL_EMAIL, NULL);
   1009 	gtk_tree_view_column_set_min_width(col, EMAIL_COL_WIDTH_EMAIL);
   1010 	gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
   1011 
   1012 	col = gtk_tree_view_column_new_with_attributes(_("Alias"), rdr,
   1013 			"markup", EMAIL_COL_ALIAS, NULL);
   1014 	gtk_tree_view_column_set_min_width(col, EMAIL_COL_WIDTH_ALIAS);
   1015 	gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
   1016 
   1017 	col = gtk_tree_view_column_new_with_attributes(_("Remarks"), rdr,
   1018 			"markup", EMAIL_COL_REMARKS, NULL);
   1019 	gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
   1020 
   1021 	gtk_container_add( GTK_CONTAINER(scrollwin), view );
   1022 
   1023 	/* Data entry area */
   1024 	table = gtk_grid_new();
   1025 
   1026 	gtk_container_add( GTK_CONTAINER(vboxl), scrollwin );
   1027 	gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0);
   1028 	gtk_container_set_border_width( GTK_CONTAINER(table), 4 );
   1029 	gtk_grid_set_row_spacing(GTK_GRID(table), 4);
   1030 	gtk_grid_set_column_spacing(GTK_GRID(table), 4);
   1031 
   1032 	entry_email = gtk_entry_new();
   1033 	entry_alias = gtk_entry_new();
   1034 	entry_remarks = gtk_entry_new();
   1035 
   1036 	/* First row */
   1037 	label = gtk_label_new(_("Email Address"));
   1038 	gtk_label_set_xalign(GTK_LABEL(label), 0.0);
   1039 	gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1);
   1040 
   1041 	gtk_grid_attach(GTK_GRID(table), entry_email, 1, 0, 1, 1);
   1042 	gtk_widget_set_hexpand(entry_email, TRUE);
   1043 	gtk_widget_set_halign(entry_email, GTK_ALIGN_FILL);
   1044 
   1045 	/* Next row */
   1046 	label = gtk_label_new(_("Alias"));
   1047 	gtk_label_set_xalign(GTK_LABEL(label), 0.0);
   1048 	gtk_grid_attach(GTK_GRID(table), label, 0, 1, 1, 1);
   1049 
   1050 	gtk_grid_attach(GTK_GRID(table), entry_alias, 1, 1, 1, 1);
   1051 	gtk_widget_set_hexpand(entry_alias, TRUE);
   1052 	gtk_widget_set_halign(entry_alias, GTK_ALIGN_FILL);
   1053 
   1054 	/* Next row */
   1055 	label = gtk_label_new(_("Remarks"));
   1056 	gtk_label_set_xalign(GTK_LABEL(label), 0.0);
   1057 	gtk_grid_attach(GTK_GRID(table), label, 0, 2, 1, 1);
   1058 
   1059 	gtk_grid_attach(GTK_GRID(table), entry_remarks, 1, 2, 1, 1);
   1060 	gtk_widget_set_hexpand(entry_remarks, TRUE);
   1061 	gtk_widget_set_halign(entry_remarks, GTK_ALIGN_FILL);
   1062 
   1063 	/* Button box */
   1064 	vboxb = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4 );
   1065 	gtk_box_pack_start(GTK_BOX(hbox), vboxb, FALSE, FALSE, 2);
   1066 
   1067 	vbuttonbox = gtk_button_box_new(GTK_ORIENTATION_VERTICAL);
   1068 	gtk_button_box_set_layout( GTK_BUTTON_BOX(vbuttonbox), GTK_BUTTONBOX_START );
   1069 	gtk_box_set_spacing( GTK_BOX(vbuttonbox), 8 );
   1070 	gtk_container_set_border_width( GTK_CONTAINER(vbuttonbox), 4 );
   1071 	gtk_container_add( GTK_CONTAINER(vboxb), vbuttonbox );
   1072 
   1073 	buttonUp = gtkut_stock_button("go-up", _("_Up"));
   1074 	buttonDown = gtkut_stock_button("go-down", _("_Down"));
   1075 	buttonDel = gtkut_stock_button("edit-delete", _("D_elete"));
   1076 	buttonMod = gtkut_stock_button("document-save", _("_Save"));
   1077 	buttonAdd = gtkut_stock_button("list-add", _("_Add"));
   1078 
   1079 	gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonUp );
   1080 	gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDown );
   1081 	gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonDel );
   1082 	gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonMod );
   1083 	gtk_container_add( GTK_CONTAINER(vbuttonbox), buttonAdd );
   1084 
   1085 	gtk_widget_show_all(vbox);
   1086 
   1087 	/* Event handlers */
   1088 	g_signal_connect( G_OBJECT(view), "cursor-changed",
   1089 			  G_CALLBACK( edit_person_email_cursor_changed ), NULL );
   1090 	g_signal_connect( G_OBJECT(buttonUp), "clicked",
   1091 			  G_CALLBACK( edit_person_email_move_up ), NULL );
   1092 	g_signal_connect( G_OBJECT(buttonDown), "clicked",
   1093 			  G_CALLBACK( edit_person_email_move_down ), NULL );
   1094 	g_signal_connect( G_OBJECT(buttonDel), "clicked",
   1095 			  G_CALLBACK( edit_person_email_delete ), NULL );
   1096 	g_signal_connect( G_OBJECT(buttonMod), "clicked",
   1097 			  G_CALLBACK( edit_person_email_modify ), NULL );
   1098 	g_signal_connect( G_OBJECT(buttonAdd), "clicked",
   1099 			  G_CALLBACK( edit_person_email_add ), NULL );
   1100 	g_signal_connect(G_OBJECT(entry_email), "changed",
   1101 			 G_CALLBACK(edit_person_entry_email_changed), NULL);
   1102 	g_signal_connect(G_OBJECT(entry_email), "key_press_event",
   1103 			 G_CALLBACK(edit_person_entry_email_pressed), NULL);
   1104 	g_signal_connect(G_OBJECT(entry_alias), "key_press_event",
   1105 			 G_CALLBACK(edit_person_entry_email_pressed), NULL);
   1106 	g_signal_connect(G_OBJECT(entry_remarks), "key_press_event",
   1107 			 G_CALLBACK(edit_person_entry_email_pressed), NULL);
   1108 
   1109 	personeditdlg.view_email   = view;
   1110 	personeditdlg.entry_email   = entry_email;
   1111 	personeditdlg.entry_alias   = entry_alias;
   1112 	personeditdlg.entry_remarks = entry_remarks;
   1113 	personeditdlg.email_up = buttonUp;
   1114 	personeditdlg.email_down = buttonDown;
   1115 	personeditdlg.email_del = buttonDel;
   1116 	personeditdlg.email_mod = buttonMod;
   1117 	personeditdlg.email_add = buttonAdd;
   1118 }
   1119 
   1120 static void addressbook_edit_person_create( GtkWidget *parent, gboolean *cancelled ) {
   1121 	if (prefs_common.addressbook_use_editaddress_dialog)
   1122 		addressbook_edit_person_dialog_create( cancelled );
   1123 	else
   1124 		addressbook_edit_person_widgetset_create( parent, cancelled );
   1125 	addressbook_edit_person_page_basic( PAGE_BASIC, _( "_User Data" ) );
   1126 	addressbook_edit_person_page_email( PAGE_EMAIL, _( "_Email Addresses" ) );
   1127 	gtk_widget_show_all( personeditdlg.container );
   1128 }
   1129 
   1130 /*
   1131 * Return list of email items.
   1132 */
   1133 static GList *edit_person_build_email_list() {
   1134 	GtkWidget *view = personeditdlg.view_email;
   1135 	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
   1136 	GtkTreeIter iter;
   1137 	GList *listEMail = NULL;
   1138 	ItemEMail *email;
   1139 
   1140 	if (!gtk_tree_model_get_iter_first(model, &iter))
   1141 		return NULL;
   1142 
   1143 	do {
   1144 		gtk_tree_model_get(model, &iter, EMAIL_COL_PTR, &email, -1);
   1145 		listEMail = g_list_append( listEMail, email );
   1146 	} while (gtk_tree_model_iter_next(model, &iter));
   1147 
   1148 	return listEMail;
   1149 }
   1150 
   1151 static void update_sensitivity(void)
   1152 {
   1153 	gtk_widget_set_sensitive(personeditdlg.entry_name,    !personeditdlg.read_only);
   1154 	gtk_widget_set_sensitive(personeditdlg.entry_first,   !personeditdlg.read_only);
   1155 	gtk_widget_set_sensitive(personeditdlg.entry_last,    !personeditdlg.read_only);
   1156 	gtk_widget_set_sensitive(personeditdlg.entry_nick,    !personeditdlg.read_only);
   1157 	gtk_widget_set_sensitive(personeditdlg.entry_email,   !personeditdlg.read_only);
   1158 	gtk_widget_set_sensitive(personeditdlg.entry_alias,   !personeditdlg.read_only);
   1159 	gtk_widget_set_sensitive(personeditdlg.entry_remarks, !personeditdlg.read_only);
   1160 	gtk_widget_set_sensitive(personeditdlg.email_up,      !personeditdlg.read_only);
   1161 	gtk_widget_set_sensitive(personeditdlg.email_down,    !personeditdlg.read_only);
   1162 	gtk_widget_set_sensitive(personeditdlg.email_del,     !personeditdlg.read_only);
   1163 	gtk_widget_set_sensitive(personeditdlg.email_mod,     !personeditdlg.read_only);
   1164 	gtk_widget_set_sensitive(personeditdlg.email_add,     !personeditdlg.read_only);
   1165 }
   1166 
   1167 static void addressbook_edit_person_flush_transient( void )
   1168 {
   1169 	ItemPerson *person = current_person;
   1170 	EditAddressPostUpdateCallback callback = edit_person_close_post_update_cb;
   1171 
   1172 	/* reset transient data */
   1173 	current_abf = NULL;
   1174 	current_person = NULL;
   1175 	current_parent_folder = NULL;
   1176 	edit_person_close_post_update_cb = NULL;
   1177 
   1178 	/* post action to perform on addressbook side */
   1179 	if (callback)
   1180 		callback( person );
   1181 }
   1182 
   1183 void addressbook_edit_person_invalidate( AddressBookFile *abf, ItemFolder *parent_folder,
   1184 										 ItemPerson *person )
   1185 {
   1186 	if (current_abf == NULL &&
   1187 		current_person == NULL &&
   1188 		current_parent_folder == NULL)
   1189 		/* edit address form is already hidden */
   1190 		return;
   1191 
   1192 	/* unconditional invalidation or invalidating the currently edited item */
   1193 	if ( ( abf == NULL && person == NULL && parent_folder == NULL )
   1194 		|| (current_abf == abf ||
   1195 			current_person == person ||
   1196 			current_parent_folder == parent_folder))
   1197 		addressbook_edit_person_close( TRUE );
   1198 }
   1199 
   1200 static gboolean addressbook_edit_person_close( gboolean cancelled )
   1201 {
   1202 	GList *listEMail = NULL;
   1203 	GError *error = NULL;
   1204 	GtkTreeModel *model;
   1205 
   1206 	listEMail = edit_person_build_email_list();
   1207 	if( cancelled ) {
   1208 		model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_email));
   1209 		gtk_list_store_clear(GTK_LIST_STORE(model));
   1210 		addritem_free_list_email( listEMail );
   1211 
   1212 		if (!prefs_common.addressbook_use_editaddress_dialog)
   1213 			gtk_widget_hide( personeditdlg.container );
   1214 
   1215 		/* no callback, as we're discarding the form */
   1216 		edit_person_close_post_update_cb = NULL;
   1217 		addressbook_edit_person_flush_transient();
   1218 		current_person = NULL;
   1219 
   1220 		/* set focus to the address list (this is done by the post_update_cb usually) */
   1221 		addressbook_address_list_set_focus();
   1222 		return FALSE;
   1223 	}
   1224 
   1225 	if( current_person && current_abf ) {
   1226 		addrbook_update_address_list( current_abf, current_person, listEMail );
   1227 	} else {
   1228 		/* Create new current_person and email list */
   1229 		if( ! cancelled && current_abf ) {
   1230 			current_person = addrbook_add_address_list( current_abf, current_parent_folder, listEMail );
   1231 		}
   1232 	}
   1233 	listEMail = NULL;
   1234 
   1235 	if(!cancelled && current_person != NULL) {
   1236 		/* Set current_person stuff */
   1237 
   1238 		gchar *name;
   1239 		gchar *cn = edit_person_get_common_name_from_widgets();
   1240 
   1241 		addritem_person_set_common_name( current_person, cn );
   1242 		g_free( cn );
   1243 
   1244 		name = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_first), 0, -1 );
   1245 		addritem_person_set_first_name( current_person, name );
   1246 		g_free( name );
   1247 		name = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_last), 0, -1 );
   1248 		addritem_person_set_last_name( current_person, name );
   1249 		g_free( name );
   1250 		name = gtk_editable_get_chars( GTK_EDITABLE(personeditdlg.entry_nick), 0, -1 );
   1251 		addritem_person_set_nick_name( current_person, name );
   1252 		g_free( name );
   1253 	}
   1254 
   1255 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_email));
   1256 	gtk_list_store_clear(GTK_LIST_STORE(model));
   1257 
   1258 	if (!prefs_common.addressbook_use_editaddress_dialog)
   1259 		gtk_widget_hide( personeditdlg.container );
   1260 
   1261 	addressbook_edit_person_flush_transient();
   1262 
   1263 	return TRUE;
   1264 }
   1265 
   1266 /*
   1267 * Edit person.
   1268 * Enter: abf    Address book.
   1269 *        parent Parent folder for person (or NULL if adding to root folder). Argument is
   1270 *               only required for new objects).
   1271 *        person Person to edit, or NULL for a new person object.
   1272 *        pgMail If TRUE, E-Mail page will be activated.
   1273 * Return: Edited object, or NULL if cancelled.*/
   1274 ItemPerson *addressbook_edit_person( AddressBookFile *abf, ItemFolder *parent_folder, ItemPerson *person,
   1275 									 gboolean pgMail, GtkWidget *parent_container,
   1276 									 void (*post_update_cb) (ItemPerson *person),
   1277 									 gboolean get_focus) {
   1278 	static gboolean cancelled;
   1279 	GError *error = NULL;
   1280 	GdkPixbuf *pixbuf = NULL;
   1281 	GtkTreeModel *model;
   1282 	GtkTreeSelection *sel;
   1283 	GtkTreeIter iter;
   1284 
   1285 	/* set transient data */
   1286 	current_abf = abf;
   1287 	current_person = person;
   1288 	current_parent_folder = parent_folder;
   1289 	edit_person_close_post_update_cb = post_update_cb;
   1290 
   1291 	if( personeditdlg.container ) {
   1292 		gtk_widget_destroy(personeditdlg.container);
   1293 		personeditdlg.container = NULL;
   1294 	}
   1295 	addressbook_edit_person_create(parent_container, &cancelled);
   1296 
   1297 	/* typically, get focus when dialog mode is enabled, or when editing a new address */
   1298 	if( get_focus ) {
   1299 		gtk_widget_grab_focus(personeditdlg.ok_btn);
   1300 		gtk_widget_grab_focus(personeditdlg.entry_name);
   1301 	}
   1302 
   1303 	personeditdlg.read_only = (current_abf == NULL);
   1304 	update_sensitivity();
   1305 
   1306 	gtk_widget_show(personeditdlg.container);
   1307 	if (prefs_common.addressbook_use_editaddress_dialog)
   1308 		manage_window_set_transient(GTK_WINDOW(personeditdlg.container));
   1309 	else
   1310 		if (get_focus)
   1311 			addressbook_address_list_disable_some_actions();
   1312 
   1313 	/* Clear all fields */
   1314 	edit_person_status_show( "" );
   1315 
   1316 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_email));
   1317 	gtk_list_store_clear(GTK_LIST_STORE(model));
   1318 
   1319 	gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_name), "" );
   1320 	gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_first), "" );
   1321 	gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_last), "" );
   1322 	gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_nick), "" );
   1323 
   1324 	personeditdlg.editNew = FALSE;
   1325 	if( current_person ) {
   1326 		gchar *filename = NULL;
   1327 
   1328 		if( ADDRITEM_NAME(current_person) )
   1329 			gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_name), ADDRITEM_NAME(person) );
   1330 		if( current_person->firstName )
   1331 			gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_first), current_person->firstName );
   1332 		if( current_person->lastName )
   1333 			gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_last), current_person->lastName );
   1334 		if( current_person->nickName )
   1335 			gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_nick), current_person->nickName );
   1336 		edit_person_load_email( current_person );
   1337 	}
   1338 	else {
   1339 		personeditdlg.editNew = TRUE;
   1340 	}
   1341 
   1342 	/* Select appropriate start page */
   1343 	if( pgMail ) {
   1344 		gtk_notebook_set_current_page( GTK_NOTEBOOK(personeditdlg.notebook), PAGE_EMAIL );
   1345 	}
   1346 	else {
   1347 		gtk_notebook_set_current_page( GTK_NOTEBOOK(personeditdlg.notebook), PAGE_BASIC );
   1348 	}
   1349 
   1350 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(personeditdlg.view_email));
   1351 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_email));
   1352 	if (gtk_tree_model_get_iter_first(model, &iter)) {
   1353 		gtk_tree_selection_select_iter(sel, &iter);
   1354 		edit_person_email_cursor_changed(
   1355 				GTK_TREE_VIEW(personeditdlg.view_email), NULL);
   1356 	}
   1357 
   1358 	edit_person_email_clear( NULL );
   1359 
   1360 	if (prefs_common.addressbook_use_editaddress_dialog) {
   1361 		gtk_main();
   1362 		gtk_widget_hide( personeditdlg.container );
   1363 
   1364 		if (!addressbook_edit_person_close( cancelled )) {
   1365 			return NULL;
   1366 		}
   1367 	}
   1368 
   1369 	return person;
   1370 }