[Commits] [SCM] claws branch, gtk3, updated. 3.16.0-116-g8b3d40c

ticho at claws-mail.org ticho at claws-mail.org
Sat Mar 3 18:00:17 CET 2018


The branch, gtk3 has been updated
       via  8b3d40c534b99be07d5b89ab4742b07a4260d1fa (commit)
       via  04e54f9684e0a8e51072f37ae253ab79ae0eccf7 (commit)
       via  caa451cc1ce483333091f7ffab6be901e7a9f2b8 (commit)
       via  50fe0ebcf6e8f3de1f2e8c8a2eaef90d63cf79b0 (commit)
       via  b7e39594374d6d5fc08430a8cc83e83fd655eee4 (commit)
       via  01f71039837bafaeaa491754e2ca94bdb6225c2f (commit)
      from  b8cee3c045f36247d923b2daab8b05f3d75d0d07 (commit)

Summary of changes:
 src/account.c                           |   31 +-
 src/addressadd.c                        |   13 +-
 src/addressbook_foldersel.c             |  251 +++++------
 src/editaddress.c                       |  730 ++++++++++++++++++++-----------
 src/editaddress_other_attributes_ldap.c |  213 +++++----
 src/editaddress_other_attributes_ldap.h |   13 +-
 src/editldap_basedn.c                   |   10 +-
 src/gtk/gtkutils.c                      |   44 ++
 src/gtk/gtkutils.h                      |   11 +
 src/importldif.c                        |   21 +-
 src/mimeview.c                          |   13 +-
 src/plugins/pgpcore/select-keys.c       |   12 +-
 src/ssl_manager.c                       |   30 +-
 13 files changed, 825 insertions(+), 567 deletions(-)


- Log -----------------------------------------------------------------
commit 8b3d40c534b99be07d5b89ab4742b07a4260d1fa
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sat Mar 3 17:37:06 2018 +0100

    Replace GtkSCTree in addressbook_foldersel.c with GtkTreeView.

diff --git a/src/addressbook_foldersel.c b/src/addressbook_foldersel.c
index d53f44a..6b8c41f 100644
--- a/src/addressbook_foldersel.c
+++ b/src/addressbook_foldersel.c
@@ -42,6 +42,13 @@
 #include "addrindex.h"
 #include "manage_window.h"
 
+enum {
+	COL_ICON,
+	COL_NAME,
+	COL_PTR,
+	N_COLS
+};
+
 typedef struct {
 	AddressBookFile	*book;
 	ItemFolder	*folder;
@@ -56,7 +63,7 @@ typedef struct {
 
 static struct _AddressBookFolderSel_dlg {
 	GtkWidget *window;
-	GtkWidget *tree_folder;
+	GtkWidget *view_folder;
 	GtkWidget *ok_btn;
 	GtkWidget *cancel_btn;
 	gint status_cid;
@@ -98,22 +105,34 @@ static gboolean addressbook_foldersel_key_pressed( GtkWidget *widget, GdkEventKe
 	return FALSE;
 }
 
+static void set_selected_ptr()
+{
+	GtkWidget *view = addressbook_foldersel_dlg.view_folder;
+
+	addressbook_foldersel_dlg.fiSelected =
+		gtkut_tree_view_get_selected_pointer(GTK_TREE_VIEW(view), COL_PTR,
+				NULL, NULL, NULL);
+}
+
 static void addressbook_foldersel_ok( GtkWidget *widget, gboolean *cancelled )
 {
+	set_selected_ptr();
 	addressbook_foldersel_cancelled = FALSE;
 	gtk_main_quit();
 }
 
 static void addressbook_foldersel_cancel( GtkWidget *widget, gboolean *cancelled )
 {
+	set_selected_ptr();
 	addressbook_foldersel_cancelled = TRUE;
 	gtk_main_quit();
 }
 
-static void addressbook_foldersel_folder_select( GtkCMCTree *ctree, GtkCMCTreeNode *node,
-				      gint column, gpointer data )
+static void addressbook_foldersel_row_activated(GtkTreeView *view,
+		GtkTreePath *path, GtkTreeViewColumn *col,
+		gpointer user_data)
 {
-	addressbook_foldersel_dlg.fiSelected = gtk_cmctree_node_get_row_data( ctree, node );
+	addressbook_foldersel_ok(NULL, NULL);
 }
 
 static gboolean addressbook_foldersel_tree_button( GtkCMCTree *ctree, GdkEventButton *event, gpointer data )
@@ -144,14 +163,17 @@ static void addressbook_foldersel_create( void )
 {
 	GtkWidget *window;
 	GtkWidget *vbox;
-	GtkWidget *tree_folder;
+	GtkWidget *view;
 	GtkWidget *vlbox;
 	GtkWidget *tree_win;
 	GtkWidget *hbbox;
 	GtkWidget *ok_btn;
 	GtkWidget *cancel_btn;
 	static GdkGeometry geometry;
-	gchar *titles[1];
+	GtkTreeStore *store;
+	GtkTreeSelection *sel;
+	GtkCellRenderer *rdr;
+	GtkTreeViewColumn *col;
 
 	window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "addressbook_foldersel" );
 	gtk_container_set_border_width( GTK_CONTAINER(window), 0 );
@@ -179,18 +201,31 @@ static void addressbook_foldersel_create( void )
 				        GTK_POLICY_AUTOMATIC );
 	gtk_box_pack_start( GTK_BOX(vlbox), tree_win, TRUE, TRUE, 0 );
 
-	titles[0] = _( "Address Book") ;
+	store = gtk_tree_store_new(N_COLS,
+			GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
 
-	tree_folder = gtk_sctree_new_with_titles( 1, 0, titles );
-	gtk_container_add( GTK_CONTAINER(tree_win), tree_folder );
-	gtk_cmclist_column_titles_show( GTK_CMCLIST(tree_folder) );
-	gtk_cmctree_set_line_style(GTK_CMCTREE(tree_folder), GTK_CMCTREE_LINES_NONE);
-	gtk_cmctree_set_expander_style(GTK_CMCTREE(tree_folder),
-			     GTK_CMCTREE_EXPANDER_TRIANGLE);
-	gtk_sctree_set_stripes(GTK_SCTREE(tree_folder), prefs_common.use_stripes_everywhere);
-	gtk_cmclist_set_selection_mode( GTK_CMCLIST(tree_folder), GTK_SELECTION_BROWSE );
-	gtk_cmctree_set_indent( GTK_CMCTREE(tree_folder), CTREE_INDENT );
-	gtk_cmclist_set_auto_sort( GTK_CMCLIST(tree_folder), TRUE );
+	view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), TRUE);
+	gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(view), FALSE);
+	gtk_tree_view_set_search_column(GTK_TREE_VIEW(view), COL_NAME);
+
+	col = gtk_tree_view_column_new();
+	rdr = gtk_cell_renderer_pixbuf_new();
+	gtk_cell_renderer_set_padding(rdr, 0, 0);
+	gtk_tree_view_column_pack_start(col, rdr, FALSE);
+	gtk_tree_view_column_set_attributes(col, rdr,
+			"pixbuf", COL_ICON, NULL);
+	rdr = gtk_cell_renderer_text_new();
+	gtk_tree_view_column_pack_start(col, rdr, TRUE);
+	gtk_tree_view_column_set_attributes(col, rdr,
+			"markup", COL_NAME, NULL);
+	gtk_tree_view_column_set_title(col, _("Address Book"));
+	gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
+
+	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
+	gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
+
+	gtk_container_add( GTK_CONTAINER(tree_win), view );
 
 	/* Button panel */
 	gtkut_stock_button_set_create( &hbbox, &cancel_btn, GTK_STOCK_CANCEL,
@@ -200,14 +235,12 @@ static void addressbook_foldersel_create( void )
 	gtk_container_set_border_width( GTK_CONTAINER(hbbox), 0 );
 	gtk_widget_grab_default( ok_btn );
 
+	g_signal_connect( G_OBJECT(view), "row-activated",
+			G_CALLBACK(addressbook_foldersel_row_activated), NULL);
 	g_signal_connect( G_OBJECT(ok_btn), "clicked",
 			 G_CALLBACK(addressbook_foldersel_ok), NULL );
 	g_signal_connect( G_OBJECT(cancel_btn), "clicked",
 			 G_CALLBACK(addressbook_foldersel_cancel), NULL );
-	g_signal_connect( G_OBJECT(tree_folder), "tree_select_row",
-			 G_CALLBACK(addressbook_foldersel_folder_select), NULL );
-	g_signal_connect( G_OBJECT(tree_folder), "button_press_event",
-			 G_CALLBACK(addressbook_foldersel_tree_button), NULL );
 
 	if ( !geometry.min_height ) {
 		geometry.min_width = 300;
@@ -222,7 +255,7 @@ static void addressbook_foldersel_create( void )
 	gtk_widget_show_all( vbox );
 
 	addressbook_foldersel_dlg.window      = window;
-	addressbook_foldersel_dlg.tree_folder = tree_folder;
+	addressbook_foldersel_dlg.view_folder = view;
 	addressbook_foldersel_dlg.ok_btn      = ok_btn;
 	addressbook_foldersel_dlg.cancel_btn  = cancel_btn;
 
@@ -232,76 +265,76 @@ static void addressbook_foldersel_create( void )
 	stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderXpm);
 }
 
-static void addressbook_foldersel_load_folder( GtkCMCTreeNode *parentNode, ItemFolder *parentFolder,
-					FolderInfo *fiParent, FolderPathMatch *match )
+static gboolean tree_clear_foreach_func(GtkTreeModel *model,
+		GtkTreePath *path, GtkTreeIter *iter,
+		gpointer user_data)
+{
+	FolderInfo *fi;
+
+	gtk_tree_model_get(model, iter, COL_PTR, &fi, -1);
+	if (fi != NULL) {
+		addressbook_foldersel_free_folderinfo(fi);
+	}
+	gtk_tree_store_set(GTK_TREE_STORE(model), iter, COL_PTR, NULL, -1);
+	return FALSE;
+}
+
+static void addressbook_foldersel_tree_clear()
+{
+	GtkWidget *view = addressbook_foldersel_dlg.view_folder;
+	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
+
+	gtk_tree_model_foreach(model, tree_clear_foreach_func, NULL);
+	gtk_tree_store_clear(GTK_TREE_STORE(model));
+}
+
+static void addressbook_foldersel_load_folder( GtkTreeIter *parent_iter,
+		ItemFolder *parentFolder, FolderInfo *fiParent)
 {
-	GtkCMCTree *tree = GTK_CMCTREE( addressbook_foldersel_dlg.tree_folder );
+	GtkWidget *view = addressbook_foldersel_dlg.view_folder;
+	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
+	GtkTreeIter iter;
 	GList *list;
 	ItemFolder *folder;
-	gchar *fName;
-	gchar **name;
-	GtkCMCTreeNode *node;
+	gchar *name;
 	FolderInfo *fi;
-	FolderPathMatch *nextmatch = NULL;
 
 	list = parentFolder->listFolder;
 	while ( list ) {
 		folder = list->data;
-		fName = g_strdup( ADDRITEM_NAME(folder) );
-
-		name = &fName;
-		node = gtk_cmctree_insert_node( tree, parentNode, NULL, name, FOLDER_SPACING,
-				folderXpm, folderXpm,
-				FALSE, TRUE );
-
-		/* match folder name, match pointer will be set to NULL if next recursive call
-		   doesn't need to match subfolder name */
-		if ( match != NULL &&
-			 match->matched == FALSE ) {
-			if ( strcmp(match->folder_path[match->index], folder->obj.uid) == 0 ) {
-				/* folder name matches, prepare next subfolder match */
-
-				debug_print("matched folder name '%s'\n", fName);
-
-				match->index++;
-
-				if ( match->folder_path[match->index] == NULL ) {
-					/* we've matched all elements */
-					match->matched = TRUE;
-					match->node = node;
-					debug_print("book/folder path matched!\n");
-				} else {
-					/* keep on matching */
-					nextmatch = match;
-				}
-			}
-		}
-
-		g_free( fName );
+		name = g_strdup( ADDRITEM_NAME(folder) );
 
 		fi = addressbook_foldersel_create_folderinfo( fiParent->book, folder );
-		gtk_cmctree_node_set_row_data_full( tree, node, fi,
-				( GDestroyNotify ) addressbook_foldersel_free_folderinfo );
-		addressbook_foldersel_load_folder( node, folder, fi, nextmatch );
+
+		debug_print("adding folder '%s'\n", name);
+		gtk_tree_store_append(GTK_TREE_STORE(model), &iter, parent_iter);
+		gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
+				COL_ICON, folderXpm,
+				COL_NAME, name,
+				COL_PTR, fi,
+				-1);
+		g_free(name);
+
+		addressbook_foldersel_load_folder( parent_iter, folder, fi );
 		list = g_list_next( list );
 	}
 }
 
-static void addressbook_foldersel_load_data( AddressIndex *addrIndex, 
-					     FolderPathMatch* match )
+static void addressbook_foldersel_load_data( AddressIndex *addrIndex )
 {
 	AddressDataSource *ds;
 	GList *list, *nodeDS;
-	gchar **name;
-	gchar *dsName;
+	gchar *name;
 	ItemFolder *rootFolder;
 	AddressBookFile *abf;
 	FolderInfo *fi;
-	GtkCMCTree *tree = GTK_CMCTREE( addressbook_foldersel_dlg.tree_folder );
-	GtkCMCTreeNode *node;
-	FolderPathMatch *nextmatch;
+	GtkWidget *view = addressbook_foldersel_dlg.view_folder;
+	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
+	GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
+	GtkTreeIter iter;
+
+	addressbook_foldersel_tree_clear();
 
-	gtk_cmclist_clear( GTK_CMCLIST( tree ) );
 	list = addrindex_get_interface_list( addrIndex );
 	while ( list ) {
 		AddressInterface *interface = list->data;
@@ -309,7 +342,7 @@ static void addressbook_foldersel_load_data( AddressIndex *addrIndex,
 			nodeDS = interface->listSource;
 			while ( nodeDS ) {
 				ds = nodeDS->data;
-				dsName = g_strdup( addrindex_ds_get_name( ds ) );
+				name = g_strdup( addrindex_ds_get_name( ds ) );
 
 				/* Read address book */
 				if( ! addrindex_ds_get_read_flag( ds ) ) {
@@ -318,55 +351,34 @@ static void addressbook_foldersel_load_data( AddressIndex *addrIndex,
 
 				/* Add node for address book */
 				abf = ds->rawDataSource;
-				name = &dsName;
-				node = gtk_cmctree_insert_node( tree, NULL, NULL,
-						name, FOLDER_SPACING, bookXpm,
-						bookXpm,
-						FALSE, TRUE );
-				g_free( dsName );
-
-				/* try to match subfolders if this book is the right book
-					(and if there's smth to match, and not yet matched) */
-				nextmatch = NULL;
-				if ( match->folder_path != NULL &&
-					 match->matched == FALSE &&
-					 match->folder_path[0] != NULL &&
-					 strcmp(match->folder_path[0], abf->fileName) == 0 ) {
-
-					debug_print("matched book name '%s'\n", abf->fileName);
-
-					match->index = 1;
-
-					if ( match->folder_path[match->index] == NULL ) {
-						/* we've matched all elements */
-						match->matched = TRUE;
-						match->node = node;
-						debug_print("book path matched!\n");
-					} else {
-						/* keep on matching */
-						nextmatch = match;
-					}
-				}
-
 				fi = addressbook_foldersel_create_folderinfo( abf, NULL );
-				gtk_cmctree_node_set_row_data_full( tree, node, fi,
-						( GDestroyNotify ) addressbook_foldersel_free_folderinfo );
+
+				debug_print("adding AB '%s'\n", name);
+				gtk_tree_store_append(GTK_TREE_STORE(model), &iter, NULL);
+				gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
+						COL_ICON, bookXpm,
+						COL_NAME, name,
+						COL_PTR, fi,
+						-1);
+				g_free(name);
 
 				rootFolder = addrindex_ds_get_root_folder( ds );
-				addressbook_foldersel_load_folder( node, rootFolder, fi, nextmatch );
+				addressbook_foldersel_load_folder( &iter, rootFolder, fi );
 
 				nodeDS = g_list_next( nodeDS );
 			}
 		}
 		list = g_list_next( list );
 	}
+
+	if (gtk_tree_model_get_iter_first(model, &iter))
+		gtk_tree_selection_select_iter(sel, &iter);
 }
 
 gboolean addressbook_foldersel_selection( AddressIndex *addrIndex,
 					AddressBookFile **book, ItemFolder **folder, 
 					const gchar* path)
 {
-	FolderPathMatch folder_path_match = { NULL, FALSE, 0, NULL };
 	gboolean retVal = FALSE;
 	addressbook_foldersel_cancelled = FALSE;
 
@@ -379,31 +391,8 @@ gboolean addressbook_foldersel_selection( AddressIndex *addrIndex,
 	
 	addressbook_foldersel_dlg.fiSelected = NULL;
 
-	/* split the folder path we've received, we'll try to match this path, subpath by
-	   subpath against the book/folder structure in order to select the folder that
-       corresponds to what we received */
-
-	if ( path != NULL ) {
-		if ( g_utf8_collate(path, _("Any")) == 0 || strcasecmp(path, "Any") ==0 || *path == '\0' )
-			/* consider "Any" (both translated or untranslated forms) and ""
-			   as valid addressbook roots */
-			folder_path_match.matched = TRUE;
-		else
-			folder_path_match.folder_path = g_strsplit( path, "/", 256 );
-	}
-
-	addressbook_foldersel_load_data( addrIndex, &folder_path_match );
-
-	if ( folder_path_match.folder_path != NULL && folder_path_match.matched == FALSE)
-		g_warning("addressbook_foldersel_load_data: couldn't match book/folder path '%s'", path);
-
-	g_strfreev( folder_path_match.folder_path );
+	addressbook_foldersel_load_data( addrIndex );
 
-	if ( folder_path_match.node != NULL)
-		gtk_cmctree_select( GTK_CMCTREE( addressbook_foldersel_dlg.tree_folder ),
-							GTK_CMCTREE_NODE( folder_path_match.node ) );
-	else
-		gtk_cmclist_select_row( GTK_CMCLIST( addressbook_foldersel_dlg.tree_folder ), 0, 0 );
 	gtk_widget_show(addressbook_foldersel_dlg.window);
 
 	gtk_main();
@@ -421,7 +410,7 @@ gboolean addressbook_foldersel_selection( AddressIndex *addrIndex,
 		}
 	}
 
-	gtk_cmclist_clear( GTK_CMCLIST( addressbook_foldersel_dlg.tree_folder ) );
+	addressbook_foldersel_tree_clear();
 
 	return retVal;
 }

commit 04e54f9684e0a8e51072f37ae253ab79ae0eccf7
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sat Mar 3 10:28:23 2018 +0100

    Replace both GtkCMCLists in Edit Person dialog With GtkTreeView.
    
    One for email list, one for attribute list.

diff --git a/src/editaddress.c b/src/editaddress.c
index 3ab3df2..51b78ce 100644
--- a/src/editaddress.c
+++ b/src/editaddress.c
@@ -53,35 +53,29 @@ static ItemFolder *current_parent_folder = NULL;
 static EditAddressPostUpdateCallback edit_person_close_post_update_cb = NULL;
 
 typedef enum {
-	EMAIL_COL_EMAIL   = 0,
-	EMAIL_COL_ALIAS   = 1,
-	EMAIL_COL_REMARKS = 2
+	EMAIL_COL_EMAIL,
+	EMAIL_COL_ALIAS,
+	EMAIL_COL_REMARKS,
+	EMAIL_COL_PTR
 } PersonEditEMailColumnPos;
 
-typedef enum {
-	ATTRIB_COL_NAME    = 0,
-	ATTRIB_COL_VALUE   = 1
-} PersonEditAttribColumnPos;
-
 #define EDITPERSON_WIDTH      520
 #define EDITPERSON_HEIGHT     320
 
 #ifndef GENERIC_UMPC
-# define EMAIL_N_COLS          3
+# define EMAIL_N_COLS          4
 # define EMAIL_COL_WIDTH_EMAIL 180
 # define EMAIL_COL_WIDTH_ALIAS 80
 #else
-# define EMAIL_N_COLS          1
+# define EMAIL_N_COLS          2
 # define EMAIL_COL_WIDTH_EMAIL 130
 # define EMAIL_COL_WIDTH_ALIAS 130
 #endif
 
 #ifndef GENERIC_UMPC
-# define ATTRIB_N_COLS          2
 # define ATTRIB_COL_WIDTH_NAME  240
 # define ATTRIB_COL_WIDTH_VALUE 0
 #else
-# define ATTRIB_N_COLS          2
 # define ATTRIB_COL_WIDTH_NAME  120
 # define ATTRIB_COL_WIDTH_VALUE 120
 #endif
@@ -190,6 +184,68 @@ static void edit_person_ok(GtkWidget *widget, gboolean *cancelled) {
 		addressbook_edit_person_close( *cancelled );
 }
 
+/* Updated up/down buttons sensitivity, depending on list
+ * cursor position */
+static void edit_person_email_update_buttons()
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter, otheriter;
+	GtkTreePath *path;
+	gboolean has_prev;
+	ItemEMail *email;
+
+	email = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
+			&model, NULL, &iter);
+
+	if (email) {
+		if (!personeditdlg.read_only) {
+			otheriter = iter;
+			path = gtk_tree_model_get_path(model, &otheriter);
+			has_prev = gtk_tree_path_prev(path);
+			if (has_prev) {
+				gtk_tree_model_get_iter(model, &otheriter, path);
+			}
+			gtk_widget_set_sensitive(personeditdlg.email_up, has_prev);
+
+			otheriter = iter;
+			gtk_widget_set_sensitive(personeditdlg.email_down,
+					gtk_tree_model_iter_next(model, &otheriter));
+		}
+	} else {
+		gtk_widget_set_sensitive(personeditdlg.email_del, FALSE);
+		gtk_widget_set_sensitive(personeditdlg.email_up, FALSE);
+		gtk_widget_set_sensitive(personeditdlg.email_down, FALSE);
+	}
+}
+
+static void edit_person_email_cursor_changed(GtkTreeView *view,
+		gpointer user_data)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	ItemEMail *email;
+
+	email = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
+			&model, NULL, &iter);
+
+	if (email != NULL) {
+		if (email->address != NULL)
+			gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_email),
+					email->address);
+		if (ADDRITEM_NAME(email) != NULL)
+			gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_alias),
+					ADDRITEM_NAME(email));
+		if (email->remarks != NULL)
+			gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_remarks),
+					email->remarks);
+	}
+
+	edit_person_email_update_buttons();
+}
+
+
 static gint edit_person_delete_event(GtkWidget *widget, GdkEventAny *event, gboolean *cancelled) {
 	*cancelled = TRUE;
 	if (prefs_common.addressbook_use_editaddress_dialog)
@@ -293,96 +349,136 @@ static void edit_person_switch_page( GtkNotebook *notebook, gpointer page,
 */
 static void edit_person_load_email( ItemPerson *person ) {
 	GList *node = person->listEMail;
-	GtkCMCList *clist = GTK_CMCLIST(personeditdlg.clist_email);
-	gchar *text[ EMAIL_N_COLS ];
+	GtkTreeModel *model = gtk_tree_view_get_model(
+			GTK_TREE_VIEW(personeditdlg.view_email));
+	GtkTreeIter iter;
+
 	while( node ) {
 		ItemEMail *emorig = ( ItemEMail * ) node->data;
 		ItemEMail *email = addritem_copyfull_item_email( emorig );
-		gint row;
-		text[ EMAIL_COL_EMAIL   ] = email->address;
+
+		gtk_list_store_append(GTK_LIST_STORE(model), &iter);
+		gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+				EMAIL_COL_EMAIL, email->address,
 #ifndef GENERIC_UMPC
-		text[ EMAIL_COL_ALIAS   ] = email->obj.name;
-		text[ EMAIL_COL_REMARKS ] = email->remarks;
+				EMAIL_COL_ALIAS, email->obj.name,
+				EMAIL_COL_REMARKS, email->remarks,
 #endif
-		row = gtk_cmclist_append( clist, text );
-		gtk_cmclist_set_row_data( clist, row, email );
+				EMAIL_COL_PTR, email,
+				-1);
+
 		node = g_list_next( node );
 	}
 }
 
-static void edit_person_email_list_selected( GtkCMCList *clist, gint row, gint column, GdkEvent *event, gpointer data ) {
-	ItemEMail *email = gtk_cmclist_get_row_data( clist, row );
+static void edit_person_email_move_up( gpointer data ) {
+	GtkTreeModel *model;
+	GtkTreeIter iter, otheriter;
+	GtkTreePath *path;
+	ItemEMail *email;
+	gboolean has_prev;
+
+	edit_person_email_clear( NULL );
+	edit_person_status_show( NULL );
+
+	email = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
+			&model, NULL, &iter);
+
 	if( email ) {
-		if( email->address )
-			gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_email), email->address );
-		if( ADDRITEM_NAME(email) )
-			gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_alias), ADDRITEM_NAME(email) );
-		if( email->remarks )
-			gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_remarks), email->remarks );
-		if (!personeditdlg.read_only) {
-			gtk_widget_set_sensitive(personeditdlg.email_del, TRUE);
-			gtk_widget_set_sensitive(personeditdlg.email_up, row > 0);
-			gtk_widget_set_sensitive(personeditdlg.email_down, gtk_cmclist_get_row_data(clist, row + 1) != NULL);
+		otheriter = iter;
+		/* GTK+2 does not have gtk_tree_model_iter_previous(), so
+		 * we have to go through GtkTreePath */
+		path = gtk_tree_model_get_path(model, &otheriter);
+		has_prev = gtk_tree_path_prev(path);
+		if (has_prev) {
+			gtk_tree_model_get_iter(model, &otheriter, path);
+			gtk_list_store_move_before(GTK_LIST_STORE(model), &iter, &otheriter);
 		}
-	} else {
-		gtk_widget_set_sensitive(personeditdlg.email_del, FALSE);
-		gtk_widget_set_sensitive(personeditdlg.email_up, FALSE);
-		gtk_widget_set_sensitive(personeditdlg.email_down, FALSE);
+		gtk_tree_path_free(path);
 	}
-	personeditdlg.rowIndEMail = row;
-	edit_person_status_show( NULL );
+
+	edit_person_email_update_buttons();
 }
 
-static void edit_person_email_move( gint dir ) {
-	GtkCMCList *clist = GTK_CMCLIST(personeditdlg.clist_email);
-	gint row = personeditdlg.rowIndEMail + dir;
-	ItemEMail *email = gtk_cmclist_get_row_data( clist, row );
+static void edit_person_email_move_down( gpointer data ) {
+	GtkTreeModel *model;
+	GtkTreeIter iter, otheriter;
+	ItemEMail *email;
+
+	edit_person_email_clear( NULL );
+	edit_person_status_show( NULL );
+
+	email = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
+			&model, NULL, &iter);
+
 	if( email ) {
-		gtk_cmclist_row_move( clist, personeditdlg.rowIndEMail, row );
-		personeditdlg.rowIndEMail = row;
-		if (!personeditdlg.read_only) {
-			gtk_widget_set_sensitive(personeditdlg.email_up, row > 0);
-			gtk_widget_set_sensitive(personeditdlg.email_down, gtk_cmclist_get_row_data(clist, row + 1) != NULL);
+		otheriter = iter;
+		if (gtk_tree_model_iter_next(model, &otheriter)) {
+			gtk_list_store_move_after(GTK_LIST_STORE(model), &iter, &otheriter);
 		}
-	} else {
-		gtk_widget_set_sensitive(personeditdlg.email_up, FALSE);
-		gtk_widget_set_sensitive(personeditdlg.email_down, FALSE);
 	}
-	edit_person_email_clear( NULL );
-	edit_person_status_show( NULL );
-}
 
-static void edit_person_email_move_up( gpointer data ) {
-	edit_person_email_move( -1 );
+	edit_person_email_update_buttons();
 }
 
-static void edit_person_email_move_down( gpointer data ) {
-	edit_person_email_move( +1 );
+static void edit_person_attrib_cursor_changed(GtkTreeView *view,
+		gpointer user_data)
+{
+	UserAttribute *attrib = gtkut_tree_view_get_selected_pointer(
+			view, ATTRIB_COL_PTR, NULL, NULL, NULL);
+
+	if( attrib && !personeditdlg.read_only && !personeditdlg.ldap ) {
+		gtk_entry_set_text( GTK_ENTRY(gtk_bin_get_child(GTK_BIN((personeditdlg.entry_atname))) ), attrib->name );
+		gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atvalue), attrib->value );
+		gtk_widget_set_sensitive(personeditdlg.attrib_del, TRUE);
+	} else {
+		gtk_widget_set_sensitive(personeditdlg.attrib_del, FALSE);
+	}
+	edit_person_status_show( NULL );
 }
 
+
 static void edit_person_email_delete( gpointer data ) {
-	GtkCMCList *clist = GTK_CMCLIST(personeditdlg.clist_email);
-	gint row = personeditdlg.rowIndEMail;
-	ItemEMail *email = gtk_cmclist_get_row_data( clist, row );
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	GtkTreeSelection *sel;
+	ItemEMail *email;
+	gboolean has_row;
+	gint n;
+
 	edit_person_email_clear( NULL );
+	edit_person_status_show( NULL );
+
+	email = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
+			&model, &sel, &iter);
+
 	if( email ) {
-		/* Remove list entry */
-		gtk_cmclist_remove( clist, row );
+		/* Remove list entry and set iter to next row, if any */
+		has_row = gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
 		addritem_free_item_email( email );
 		email = NULL;
 	}
 
 	/* Position hilite bar */
-	email = gtk_cmclist_get_row_data( clist, row );
-	if( ! email ) {
-		personeditdlg.rowIndEMail = -1 + row;
-	}
-	if (!personeditdlg.read_only) {
-		gtk_widget_set_sensitive(personeditdlg.email_del, gtk_cmclist_get_row_data(clist, 0) != NULL);
-		gtk_widget_set_sensitive(personeditdlg.email_up, gtk_cmclist_get_row_data(clist, personeditdlg.rowIndEMail + 1) != NULL);
-		gtk_widget_set_sensitive(personeditdlg.email_down, gtk_cmclist_get_row_data(clist, personeditdlg.rowIndEMail - 1) != NULL);
+	if (!has_row) {
+		/* The removed row was the last in the list, so iter is not
+		 * valid. Find out if there is at least one row remaining
+		 * in the list, and select the last one if so. */
+		n = gtk_tree_model_iter_n_children(model, NULL);
+		if (n > 0 && gtk_tree_model_iter_nth_child(model, &iter, NULL, n-1)) {
+			/* It exists */
+			has_row = TRUE;
+		}
 	}
-	edit_person_status_show( NULL );
+
+	if (has_row)
+		gtk_tree_selection_select_iter(sel, &iter);
+
+	edit_person_email_cursor_changed(
+			GTK_TREE_VIEW(personeditdlg.view_email), NULL);
 }
 
 static ItemEMail *edit_person_email_edit( gboolean *error, ItemEMail *email ) {
@@ -418,147 +514,168 @@ static ItemEMail *edit_person_email_edit( gboolean *error, ItemEMail *email ) {
 }
 
 static void edit_person_email_modify( gpointer data ) {
+	GtkTreeModel *model;
+	GtkTreeIter iter;
 	gboolean errFlg = FALSE;
-	GtkCMCList *clist = GTK_CMCLIST(personeditdlg.clist_email);
-	gint row = personeditdlg.rowIndEMail;
-	ItemEMail *email = gtk_cmclist_get_row_data( clist, row );
+	ItemEMail *email;
+
+	email = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
+			&model, NULL, &iter);
+
 	if( email ) {
 		edit_person_email_edit( &errFlg, email );
 		if( ! errFlg ) {
-			gtk_cmclist_set_text( clist, row, EMAIL_COL_EMAIL, email->address );
-			gtk_cmclist_set_text( clist, row, EMAIL_COL_ALIAS, email->obj.name );
-			gtk_cmclist_set_text( clist, row, EMAIL_COL_REMARKS, email->remarks );
+			gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+					EMAIL_COL_EMAIL, email->address,
+#ifndef GENERIC_UMPC
+					EMAIL_COL_ALIAS, email->obj.name,
+					EMAIL_COL_REMARKS, email->remarks,
+#endif
+					-1);
 			edit_person_email_clear( NULL );
 		}
 	}
 }
 
 static void edit_person_email_add( gpointer data ) {
-	GtkCMCList *clist = GTK_CMCLIST(personeditdlg.clist_email);
+	GtkTreeModel *model;
+	GtkTreeIter iter, otheriter;
+	GtkTreeSelection *sel;
 	gboolean errFlg = FALSE;
 	ItemEMail *email = NULL;
-	gint row = personeditdlg.rowIndEMail;
-	if( gtk_cmclist_get_row_data( clist, row ) == NULL ) row = 0;
+
+	email = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(personeditdlg.view_email), EMAIL_COL_PTR,
+			&model, &sel, &otheriter);
 
 	email = edit_person_email_edit( &errFlg, NULL );
 	if( ! errFlg ) {
-		gchar *text[ EMAIL_N_COLS ];
-		text[ EMAIL_COL_EMAIL   ] = email->address;
+		gtk_list_store_insert_after(GTK_LIST_STORE(model), &iter, &otheriter);
+		gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+					EMAIL_COL_EMAIL, email->address,
 #ifndef GENERIC_UMPC
-		text[ EMAIL_COL_ALIAS   ] = email->obj.name;
-		text[ EMAIL_COL_REMARKS ] = email->remarks;
+					EMAIL_COL_ALIAS, email->obj.name,
+					EMAIL_COL_REMARKS, email->remarks,
 #endif
-		row = gtk_cmclist_insert( clist, 1 + row, text );
-		gtk_cmclist_set_row_data( clist, row, email );
-		gtk_cmclist_select_row( clist, row, 0 );
+					EMAIL_COL_PTR, email,
+					-1);
+		gtk_tree_selection_select_iter(sel, &iter);
+		edit_person_email_update_buttons();
+
 		edit_person_email_clear( NULL );
 	}
 }
 
-/*
-* Comparison using cell contents (text in first column). Used for sort
-* address index widget.
-*/
-static gint edit_person_attrib_compare_func(
-	GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2 )
+static gboolean list_find_email(const gchar *addr)
 {
-	GtkCMCell *cell1 = ((GtkCMCListRow *)ptr1)->cell;
-	GtkCMCell *cell2 = ((GtkCMCListRow *)ptr2)->cell;
-	gchar *name1 = NULL, *name2 = NULL;
-
-	if( cell1 ) name1 = cell1->u.text;
-	if( cell2 ) name2 = cell2->u.text;
-	if( ! name1 ) return ( name2 != NULL );
-	if( ! name2 ) return -1;
-	return g_utf8_collate( name1, name2 );
-}
+	GtkWidget *view = personeditdlg.view_email;
+	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
+	GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
+	GtkTreeIter iter;
+	ItemEMail *email;
 
-static gboolean list_find_attribute(const gchar *attr)
-{
-	GtkCMCList *clist = GTK_CMCLIST(personeditdlg.clist_attrib);
-	UserAttribute *attrib;
-	gint row = 0;
-	while( (attrib = gtk_cmclist_get_row_data( clist, row )) ) {
-		if (!g_ascii_strcasecmp(attrib->name, attr)) {
-			gtk_cmclist_select_row(clist, row, 0);
+	if (!gtk_tree_model_get_iter_first(model, &iter))
+		return FALSE;
+
+	do {
+		gtk_tree_model_get(model, &iter, EMAIL_COL_PTR, &email, -1);
+		if (!g_ascii_strcasecmp(email->address, addr)) {
+			gtk_tree_selection_select_iter(sel, &iter);
 			return TRUE;
 		}
-		row++;
-	}
+	} while (gtk_tree_model_iter_next(model, &iter));
+
 	return FALSE;
 }
 
-static gboolean list_find_email(const gchar *addr)
+static gboolean list_find_attribute(const gchar *attr)
 {
-	GtkCMCList *clist = GTK_CMCLIST(personeditdlg.clist_email);
-	ItemEMail *email;
-	gint row = 0;
-	while( (email = gtk_cmclist_get_row_data( clist, row )) ) {
-		if (!g_ascii_strcasecmp(email->address, addr)) {
-			gtk_cmclist_select_row(clist, row, 0);
+	GtkWidget *view = personeditdlg.view_attrib;
+	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
+	GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
+	GtkTreeIter iter;
+	UserAttribute *attrib;
+
+	if (!gtk_tree_model_get_iter_first(model, &iter))
+		return FALSE;
+
+	do {
+		gtk_tree_model_get(model, &iter, ATTRIB_COL_PTR, &attrib, -1);
+		if (!g_ascii_strcasecmp(attrib->name, attr)) {
+			gtk_tree_selection_select_iter(sel, &iter);
 			return TRUE;
 		}
-		row++;
-	}
+	} while (gtk_tree_model_iter_next(model, &iter));
+
 	return FALSE;
 }
 
 /*
-* Load clist with a copy of person's email addresses.
+* Load list with a copy of person's email addresses.
 */
 static void edit_person_load_attrib( ItemPerson *person ) {
 	GList *node = person->listAttrib;
-	GtkCMCList *clist = GTK_CMCLIST(personeditdlg.clist_attrib);
-	gchar *text[ ATTRIB_N_COLS ];
+	GtkWidget *view = personeditdlg.view_attrib;
+	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
+	GtkTreeIter iter;
+
 	while( node ) {
 		UserAttribute *atorig = ( UserAttribute * ) node->data;
 		UserAttribute *attrib = addritem_copy_attribute( atorig );
-		gint row;
+
 		debug_print("name: %s value: %s\n", attrib->name, attrib->value);
-		text[ ATTRIB_COL_NAME  ] = attrib->name;
-		text[ ATTRIB_COL_VALUE ] = attrib->value;
 
-		row = gtk_cmclist_append( clist, text );
-		gtk_cmclist_set_row_data( clist, row, attrib );
-		node = g_list_next( node );
-	}
-}
+		gtk_list_store_append(GTK_LIST_STORE(model), &iter);
+		gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+				ATTRIB_COL_NAME, attrib->name,
+				ATTRIB_COL_VALUE, attrib->value,
+				ATTRIB_COL_PTR, attrib,
+				-1);
 
-static void edit_person_attrib_list_selected( GtkCMCList *clist, gint row, gint column, GdkEvent *event, gpointer data ) {
-	UserAttribute *attrib = gtk_cmclist_get_row_data( clist, row );
-	if( attrib && !personeditdlg.read_only && !personeditdlg.ldap ) {
-		gtk_entry_set_text( GTK_ENTRY(gtk_bin_get_child(GTK_BIN((personeditdlg.entry_atname))) ), attrib->name );
-		gtk_entry_set_text( GTK_ENTRY(personeditdlg.entry_atvalue), attrib->value );
-		gtk_widget_set_sensitive(personeditdlg.attrib_del, TRUE);
-	} else {
-		gtk_widget_set_sensitive(personeditdlg.attrib_del, FALSE);
+		node = g_list_next( node );
 	}
-	personeditdlg.rowIndAttrib = row;
-	edit_person_status_show( NULL );
 }
 
-static void edit_person_attrib_delete( gpointer data ) {
-	GtkCMCList *clist = GTK_CMCLIST(personeditdlg.clist_attrib);
-	gint row = personeditdlg.rowIndAttrib;
-	UserAttribute *attrib = gtk_cmclist_get_row_data( clist, row );
-	edit_person_attrib_clear( NULL );
-	if( attrib ) {
-		/* Remove list entry */
-		gtk_cmclist_remove( clist, row );
-		addritem_free_attribute( attrib );
+static void edit_person_attrib_delete(gpointer data) {
+	UserAttribute *attrib;
+	GtkTreeModel *model;
+	GtkTreeSelection *sel;
+	GtkTreeIter iter;
+	gboolean has_row = FALSE;
+	gint n;
+
+	edit_person_attrib_clear(NULL);
+	edit_person_status_show(NULL);
+
+	attrib = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(personeditdlg.view_attrib), ATTRIB_COL_PTR,
+			&model, &sel, &iter);
+
+	if (attrib) {
+		/* Remove list entry, and set iter to next row, if any */
+		has_row = gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
+		addritem_free_attribute(attrib);
 		attrib = NULL;
 	}
 
 	/* Position hilite bar */
-	attrib = gtk_cmclist_get_row_data( clist, row );
-	if( ! attrib ) {
-		personeditdlg.rowIndAttrib = -1 + row;
-	} 
-	
-	if (!personeditdlg.read_only && !personeditdlg.ldap)
-		gtk_widget_set_sensitive(personeditdlg.attrib_del, gtk_cmclist_get_row_data(clist, 0) != NULL);
-	
-	edit_person_status_show( NULL );
+	if (!has_row) {
+		/* The removed row was the last in the list, so iter is not
+		 * valid. Find out if there is at least one row remaining
+		 * in the list, and select the last one if so. */
+		n = gtk_tree_model_iter_n_children(model, NULL);
+		if (n > 0 && gtk_tree_model_iter_nth_child(model, &iter, NULL, n-1)) {
+			/* It exists. */
+			has_row = TRUE;
+		}
+	}
+
+	if (has_row)
+		gtk_tree_selection_select_iter(sel, &iter);
+
+	edit_person_attrib_cursor_changed(
+			GTK_TREE_VIEW(personeditdlg.view_attrib), NULL);
 }
 
 static UserAttribute *edit_person_attrib_edit( gboolean *error, UserAttribute *attrib ) {
@@ -592,38 +709,58 @@ static UserAttribute *edit_person_attrib_edit( gboolean *error, UserAttribute *a
 	return retVal;
 }
 
-static void edit_person_attrib_modify( gpointer data ) {
+static void edit_person_attrib_modify(gpointer data) {
 	gboolean errFlg = FALSE;
-	GtkCMCList *clist = GTK_CMCLIST(personeditdlg.clist_attrib);
-	gint row = personeditdlg.rowIndAttrib;
-	UserAttribute *attrib = gtk_cmclist_get_row_data( clist, row );
-	if( attrib ) {
-		edit_person_attrib_edit( &errFlg, attrib );
-		if( ! errFlg ) {
-			gtk_cmclist_set_text( clist, row, ATTRIB_COL_NAME, attrib->name );
-			gtk_cmclist_set_text( clist, row, ATTRIB_COL_VALUE, attrib->value );
-			edit_person_attrib_clear( NULL );
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	UserAttribute *attrib;
+
+	attrib = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(personeditdlg.view_attrib), ATTRIB_COL_PTR,
+			&model, NULL, &iter);
+	if (attrib) {
+		edit_person_attrib_edit(&errFlg, attrib);
+		if (!errFlg) {
+			gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+					ATTRIB_COL_NAME, attrib->name,
+					ATTRIB_COL_VALUE, attrib->value,
+					-1);
+			edit_person_attrib_clear(NULL);
 		}
 	}
 }
 
-static void edit_person_attrib_add( gpointer data ) {
-	GtkCMCList *clist = GTK_CMCLIST(personeditdlg.clist_attrib);
+static void edit_person_attrib_add(gpointer data) {
 	gboolean errFlg = FALSE;
-	UserAttribute *attrib = NULL;
-	gint row = personeditdlg.rowIndAttrib;
-	if( gtk_cmclist_get_row_data( clist, row ) == NULL ) row = 0;
+	GtkTreeModel *model;
+	GtkTreeSelection *sel;
+	GtkTreeIter iter, iter2;
+	UserAttribute *attrib;
 
-	attrib = edit_person_attrib_edit( &errFlg, NULL );
-	if( ! errFlg ) {
-		gchar *text[ ATTRIB_N_COLS ];
-		text[ ATTRIB_COL_NAME  ] = attrib->name;
-		text[ ATTRIB_COL_VALUE ] = attrib->value;
-
-		row = gtk_cmclist_insert( clist, 1 + row, text );
-		gtk_cmclist_set_row_data( clist, row, attrib );
-		gtk_cmclist_select_row( clist, row, 0 );
-		edit_person_attrib_clear( NULL );
+	attrib = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(personeditdlg.view_attrib), ATTRIB_COL_PTR,
+			&model, &sel, &iter);
+
+	if (attrib == NULL) {
+		/* No row selected, or list empty, add it as first row. */
+		gtk_list_store_insert(GTK_LIST_STORE(model), &iter, 0);
+	} else {
+		/* Add it after the currently selected row. */
+		gtk_list_store_insert_after(GTK_LIST_STORE(model), &iter2,
+				&iter);
+		iter = iter2;
+	}
+
+	/* Grab the values from text entries, and fill out the new row. */
+	attrib = edit_person_attrib_edit(&errFlg, NULL);
+	if (!errFlg) {
+		gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+				ATTRIB_COL_NAME, attrib->name,
+				ATTRIB_COL_VALUE, attrib->value,
+				ATTRIB_COL_PTR, attrib,
+				-1);
+		gtk_tree_selection_select_iter(sel, &iter);
+		edit_person_attrib_clear(NULL);
 	}
 }
 
@@ -990,7 +1127,9 @@ static gboolean email_adding = FALSE, email_saving = FALSE;
 
 static void edit_person_entry_email_changed (GtkWidget *entry, gpointer data)
 {
-	gboolean non_empty = gtk_cmclist_get_row_data(GTK_CMCLIST(personeditdlg.clist_email), 0) != NULL;
+	GtkTreeModel *model = gtk_tree_view_get_model(
+			GTK_TREE_VIEW(personeditdlg.view_email));
+	gboolean non_empty = (gtk_tree_model_iter_n_children(model, NULL) > 0);
 
 	if (personeditdlg.read_only)
 		return;
@@ -1040,21 +1179,17 @@ static void addressbook_edit_person_page_email( gint pageNum, gchar *pageLbl ) {
 
 	GtkWidget *table;
 	GtkWidget *label;
-	GtkWidget *clist_swin;
-	GtkWidget *clist;
+	GtkWidget *scrollwin;
+	GtkWidget *view;
 	GtkWidget *entry_email;
 	GtkWidget *entry_alias;
 	GtkWidget *entry_remarks;
 	gint top;
+	GtkListStore *store;
+	GtkTreeViewColumn *col;
+	GtkCellRenderer *rdr;
+	GtkTreeSelection *sel;
 
-	gchar *titles[ EMAIL_N_COLS ];
-	gint i;
-
-	titles[ EMAIL_COL_EMAIL   ] = _("Email Address");
-#ifndef GENERIC_UMPC
-	titles[ EMAIL_COL_ALIAS   ] = _("Alias");
-	titles[ EMAIL_COL_REMARKS ] = _("Remarks");
-#endif
 	vbox = gtk_vbox_new( FALSE, 8 );
 	gtk_widget_show( vbox );
 	gtk_container_add( GTK_CONTAINER( personeditdlg.notebook ), vbox );
@@ -1075,31 +1210,58 @@ static void addressbook_edit_person_page_email( gint pageNum, gchar *pageLbl ) {
 	gtk_container_add( GTK_CONTAINER( hbox ), vboxl );
 	gtk_container_set_border_width( GTK_CONTAINER(vboxl), 4 );
 
-	clist_swin = gtk_scrolled_window_new( NULL, NULL );
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
+	scrollwin = gtk_scrolled_window_new( NULL, NULL );
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
 				       GTK_POLICY_AUTOMATIC,
 				       GTK_POLICY_AUTOMATIC);
 
-	clist = gtk_cmclist_new_with_titles( EMAIL_N_COLS, titles );
+	store = gtk_list_store_new(EMAIL_N_COLS,
+			G_TYPE_STRING,
+#ifndef GENERIC_UMPC
+			G_TYPE_STRING,
+			G_TYPE_STRING,
+#endif
+			G_TYPE_POINTER,
+			-1);
 
-	gtk_container_add( GTK_CONTAINER(clist_swin), clist );
-	gtk_cmclist_set_selection_mode( GTK_CMCLIST(clist), GTK_SELECTION_BROWSE );
-	gtk_cmclist_set_column_width( GTK_CMCLIST(clist), EMAIL_COL_EMAIL, EMAIL_COL_WIDTH_EMAIL );
-	gtk_cmclist_set_column_width( GTK_CMCLIST(clist), EMAIL_COL_ALIAS, EMAIL_COL_WIDTH_ALIAS );
+	view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+	g_object_unref(store);
+#ifndef GENERIC_UMPC
+	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), TRUE);
+#else
+	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
+#endif
+	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
+	gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
+
+	rdr = gtk_cell_renderer_text_new();
+	col = gtk_tree_view_column_new_with_attributes(_("Email Address"), rdr,
+			"markup", EMAIL_COL_EMAIL, NULL);
+	gtk_tree_view_column_set_min_width(col, EMAIL_COL_WIDTH_EMAIL);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
+
+#ifndef GENERIC_UMPC
+	col = gtk_tree_view_column_new_with_attributes(_("Alias"), rdr,
+			"markup", EMAIL_COL_ALIAS, NULL);
+	gtk_tree_view_column_set_min_width(col, EMAIL_COL_WIDTH_ALIAS);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
+
+	col = gtk_tree_view_column_new_with_attributes(_("Remarks"), rdr,
+			"markup", EMAIL_COL_REMARKS, NULL);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
+#endif
 
-	for( i = 0; i < EMAIL_N_COLS; i++ )
-		gtk_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button, FALSE);
+	gtk_container_add( GTK_CONTAINER(scrollwin), view );
 
 	/* Data entry area */
 	table = gtk_table_new( 4, 2, FALSE);
 
 #ifndef GENERIC_UMPC
-	gtk_container_add( GTK_CONTAINER(vboxl), clist_swin );
+	gtk_container_add( GTK_CONTAINER(vboxl), scrollwin );
 	gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0);
 #else
 	gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0);
-	gtk_container_add( GTK_CONTAINER(vboxl), clist_swin );
-	gtk_cmclist_column_titles_hide(GTK_CMCLIST(clist));
+	gtk_container_add( GTK_CONTAINER(vboxl), scrollwin );
 #endif
 	gtk_container_set_border_width( GTK_CONTAINER(table), 4 );
 	gtk_table_set_row_spacings(GTK_TABLE(table), 4);
@@ -1167,8 +1329,8 @@ static void addressbook_edit_person_page_email( gint pageNum, gchar *pageLbl ) {
 	gtk_widget_show_all(vbox);
 
 	/* Event handlers */
-	g_signal_connect( G_OBJECT(clist), "select_row",
-			  G_CALLBACK( edit_person_email_list_selected), NULL );
+	g_signal_connect( G_OBJECT(view), "cursor-changed",
+			  G_CALLBACK( edit_person_email_cursor_changed ), NULL );
 	g_signal_connect( G_OBJECT(buttonUp), "clicked",
 			  G_CALLBACK( edit_person_email_move_up ), NULL );
 	g_signal_connect( G_OBJECT(buttonDown), "clicked",
@@ -1188,7 +1350,7 @@ static void addressbook_edit_person_page_email( gint pageNum, gchar *pageLbl ) {
 	g_signal_connect(G_OBJECT(entry_remarks), "key_press_event",
 			 G_CALLBACK(edit_person_entry_email_pressed), NULL);
 
-	personeditdlg.clist_email   = clist;
+	personeditdlg.view_email   = view;
 	personeditdlg.entry_email   = entry_email;
 	personeditdlg.entry_alias   = entry_alias;
 	personeditdlg.entry_remarks = entry_remarks;
@@ -1203,7 +1365,9 @@ static gboolean attrib_adding = FALSE, attrib_saving = FALSE;
 
 static void edit_person_entry_att_changed (GtkWidget *entry, gpointer data)
 {
-	gboolean non_empty = gtk_cmclist_get_row_data(GTK_CMCLIST(personeditdlg.clist_attrib), 0) != NULL;
+	GtkTreeModel *model = gtk_tree_view_get_model(
+			GTK_TREE_VIEW(personeditdlg.view_attrib));
+	gboolean non_empty = (gtk_tree_model_iter_n_children(model, NULL) > 0);
 	const gchar *atname;
 
 	if (personeditdlg.read_only || personeditdlg.ldap)
@@ -1252,17 +1416,15 @@ static void addressbook_edit_person_page_attrib( gint pageNum, gchar *pageLbl )
 
 	GtkWidget *table;
 	GtkWidget *label;
-	GtkWidget *clist_swin;
-	GtkWidget *clist;
+	GtkWidget *scrollwin;
+	GtkWidget *view;
 	GtkWidget *entry_name;
 	GtkWidget *entry_value;
 	gint top;
-
-	gchar *titles[ ATTRIB_N_COLS ];
-	gint i;
-
-	titles[ ATTRIB_COL_NAME  ] = _("Name");
-	titles[ ATTRIB_COL_VALUE ] = _("Value");
+	GtkListStore *store;
+	GtkTreeViewColumn *col;
+	GtkCellRenderer *rdr;
+	GtkTreeSelection *sel;
 
 	vbox = gtk_vbox_new( FALSE, 8 );
 	gtk_widget_show( vbox );
@@ -1284,32 +1446,43 @@ static void addressbook_edit_person_page_attrib( gint pageNum, gchar *pageLbl )
 	gtk_container_add( GTK_CONTAINER( hbox ), vboxl );
 	gtk_container_set_border_width( GTK_CONTAINER(vboxl), 4 );
 
-	clist_swin = gtk_scrolled_window_new( NULL, NULL );
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
+	scrollwin = gtk_scrolled_window_new( NULL, NULL );
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
 				       GTK_POLICY_AUTOMATIC,
 				       GTK_POLICY_AUTOMATIC);
 
-	clist = gtk_cmclist_new_with_titles( ATTRIB_N_COLS, titles );
-	gtk_container_add( GTK_CONTAINER(clist_swin), clist );
-	gtk_cmclist_set_selection_mode( GTK_CMCLIST(clist), GTK_SELECTION_BROWSE );
-	gtk_cmclist_set_compare_func( GTK_CMCLIST(clist), edit_person_attrib_compare_func );
-	gtk_cmclist_set_auto_sort( GTK_CMCLIST(clist), TRUE );
-	gtk_cmclist_set_column_width( GTK_CMCLIST(clist), ATTRIB_COL_NAME, ATTRIB_COL_WIDTH_NAME );
-	gtk_cmclist_set_column_width( GTK_CMCLIST(clist), ATTRIB_COL_VALUE, ATTRIB_COL_WIDTH_VALUE );
+	store = gtk_list_store_new(ATTRIB_N_COLS,
+			G_TYPE_STRING, G_TYPE_STRING,
+			G_TYPE_POINTER, -1);
+
+	view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+	g_object_unref(store);
+	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), TRUE);
+	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
+	gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
+
+	rdr = gtk_cell_renderer_text_new();
+	col = gtk_tree_view_column_new_with_attributes(_("Name"), rdr,
+			"markup", ATTRIB_COL_NAME, NULL);
+	gtk_tree_view_column_set_min_width(col, ATTRIB_COL_WIDTH_NAME);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
+
+	col = gtk_tree_view_column_new_with_attributes(_("Value"), rdr,
+			"markup", ATTRIB_COL_VALUE, NULL);
+	gtk_tree_view_column_set_min_width(col, ATTRIB_COL_WIDTH_VALUE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
 
-	for( i = 0; i < ATTRIB_N_COLS; i++ )
-		gtk_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button, FALSE);
+	gtk_container_add( GTK_CONTAINER(scrollwin), view );
 
 	/* Data entry area */
 #ifndef GENERIC_UMPC
 	table = gtk_table_new( 4, 2, FALSE);
-	gtk_container_add( GTK_CONTAINER(vboxl), clist_swin );
+	gtk_container_add( GTK_CONTAINER(vboxl), scrollwin );
 	gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0);
 #else
 	table = gtk_table_new( 2, 4, FALSE);
 	gtk_box_pack_start(GTK_BOX(vboxl), table, FALSE, FALSE, 0);
-	gtk_container_add( GTK_CONTAINER(vboxl), clist_swin );
-	gtk_cmclist_column_titles_hide(GTK_CMCLIST(clist));
+	gtk_container_add( GTK_CONTAINER(vboxl), scrollwin );
 #endif
 	gtk_container_set_border_width( GTK_CONTAINER(table), 4 );
 	gtk_table_set_row_spacings(GTK_TABLE(table), 4);
@@ -1381,8 +1554,8 @@ static void addressbook_edit_person_page_attrib( gint pageNum, gchar *pageLbl )
 	gtk_widget_show_all(vbox);
 
 	/* Event handlers */
-	g_signal_connect( G_OBJECT(clist), "select_row",
-			  G_CALLBACK( edit_person_attrib_list_selected), NULL );
+	g_signal_connect( G_OBJECT(view), "cursor-changed",
+			  G_CALLBACK( edit_person_attrib_cursor_changed ), NULL );
 	g_signal_connect( G_OBJECT(buttonDel), "clicked",
 			  G_CALLBACK( edit_person_attrib_delete ), NULL );
 	g_signal_connect( G_OBJECT(buttonMod), "clicked",
@@ -1396,7 +1569,7 @@ static void addressbook_edit_person_page_attrib( gint pageNum, gchar *pageLbl )
 	g_signal_connect(G_OBJECT(entry_value), "key_press_event",
 			 G_CALLBACK(edit_person_entry_att_pressed), NULL);
 
-	personeditdlg.clist_attrib  = clist;
+	personeditdlg.view_attrib  = view;
 	personeditdlg.entry_atname  = entry_name;
 	personeditdlg.entry_atvalue = entry_value;
 	personeditdlg.attrib_add = buttonAdd;
@@ -1424,14 +1597,20 @@ static void addressbook_edit_person_create( GtkWidget *parent, gboolean *cancell
 * Return list of email items.
 */
 static GList *edit_person_build_email_list() {
-	GtkCMCList *clist = GTK_CMCLIST(personeditdlg.clist_email);
+	GtkWidget *view = personeditdlg.view_email;
+	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
+	GtkTreeIter iter;
 	GList *listEMail = NULL;
 	ItemEMail *email;
-	gint row = 0;
-	while( (email = gtk_cmclist_get_row_data( clist, row )) ) {
+
+	if (!gtk_tree_model_get_iter_first(model, &iter))
+		return NULL;
+
+	do {
+		gtk_tree_model_get(model, &iter, EMAIL_COL_PTR, &email, -1);
 		listEMail = g_list_append( listEMail, email );
-		row++;
-	}
+	} while (gtk_tree_model_iter_next(model, &iter));
+
 	return listEMail;
 }
 
@@ -1439,14 +1618,22 @@ static GList *edit_person_build_email_list() {
 * Return list of attributes.
 */
 static GList *edit_person_build_attrib_list() {
-	GtkCMCList *clist = GTK_CMCLIST(personeditdlg.clist_attrib);
+	GtkTreeModel *model = gtk_tree_view_get_model(
+			GTK_TREE_VIEW(personeditdlg.view_attrib));
+	GtkTreeIter iter;
 	GList *listAttrib = NULL;
 	UserAttribute *attrib;
-	gint row = 0;
-	while( (attrib = gtk_cmclist_get_row_data( clist, row )) ) {
+
+	/* Iterate through all the rows, selecting the one that
+	 * matches. */
+	if (!gtk_tree_model_get_iter_first(model, &iter))
+		return FALSE;
+
+	do {
+		gtk_tree_model_get(model, &iter, ATTRIB_COL_PTR, &attrib, -1);
 		listAttrib = g_list_append( listAttrib, attrib );
-		row++;
-	}
+	} while (gtk_tree_model_iter_next(model, &iter));
+
 	return listAttrib;
 }
 
@@ -1509,14 +1696,17 @@ static gboolean addressbook_edit_person_close( gboolean cancelled )
 	GList *listEMail = NULL;
 	GList *listAttrib = NULL;
 	GError *error = NULL;
+	GtkTreeModel *model;
 
 	listEMail = edit_person_build_email_list();
 	listAttrib = edit_person_build_attrib_list();
 	if( cancelled ) {
 		addritem_free_list_email( listEMail );
 		addritem_free_list_attribute( listAttrib );
-		gtk_cmclist_clear( GTK_CMCLIST(personeditdlg.clist_email) );
-		gtk_cmclist_clear( GTK_CMCLIST(personeditdlg.clist_attrib) );
+		model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_email));
+		gtk_list_store_clear(GTK_LIST_STORE(model));
+		model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_attrib));
+		gtk_list_store_clear(GTK_LIST_STORE(model));
 
 		if (!prefs_common.addressbook_use_editaddress_dialog)
 			gtk_widget_hide( personeditdlg.container );
@@ -1597,8 +1787,10 @@ static gboolean addressbook_edit_person_close( gboolean cancelled )
 		g_free( name );
 	}
 
-	gtk_cmclist_clear( GTK_CMCLIST(personeditdlg.clist_email) );
-	gtk_cmclist_clear( GTK_CMCLIST(personeditdlg.clist_attrib) );
+	model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_email));
+	gtk_list_store_clear(GTK_LIST_STORE(model));
+	model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_attrib));
+	gtk_list_store_clear(GTK_LIST_STORE(model));
 
 	if (!prefs_common.addressbook_use_editaddress_dialog)
 		gtk_widget_hide( personeditdlg.container );
@@ -1623,6 +1815,10 @@ ItemPerson *addressbook_edit_person( AddressBookFile *abf, ItemFolder *parent_fo
 	static gboolean cancelled;
 	GError *error = NULL;
 	GdkPixbuf *pixbuf = NULL;
+	GtkTreeModel *model;
+	GtkTreeSelection *sel;
+	GtkTreeIter iter;
+
 	/* set transient data */
 	current_abf = abf;
 	current_person = person;
@@ -1653,11 +1849,13 @@ ItemPerson *addressbook_edit_person( AddressBookFile *abf, ItemFolder *parent_fo
 			addressbook_address_list_disable_some_actions();
 
 	/* Clear all fields */
-	personeditdlg.rowIndEMail = -1;
-	personeditdlg.rowIndAttrib = -1;
 	edit_person_status_show( "" );
-	gtk_cmclist_clear( GTK_CMCLIST(personeditdlg.clist_email) );
-	gtk_cmclist_clear( GTK_CMCLIST(personeditdlg.clist_attrib) );
+
+	model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_email));
+	gtk_list_store_clear(GTK_LIST_STORE(model));
+	model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_attrib));
+	gtk_list_store_clear(GTK_LIST_STORE(model));
+
 	gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_name), "" );
 	gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_first), "" );
 	gtk_entry_set_text(GTK_ENTRY(personeditdlg.entry_last), "" );
@@ -1722,12 +1920,22 @@ no_img:
 		gtk_notebook_set_current_page( GTK_NOTEBOOK(personeditdlg.notebook), PAGE_BASIC );
 	}
 
-	gtk_cmclist_select_row( GTK_CMCLIST(personeditdlg.clist_email), 0, 0 );
-	gtk_cmclist_select_row( GTK_CMCLIST(personeditdlg.clist_attrib), 0, 0 );
-	edit_person_email_clear( NULL );
-	if (current_person)
-		edit_person_email_list_selected(GTK_CMCLIST(personeditdlg.clist_email), 0, 0, NULL, NULL);
+	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(personeditdlg.view_email));
+	model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_email));
+	if (gtk_tree_model_get_iter_first(model, &iter)) {
+		gtk_tree_selection_select_iter(sel, &iter);
+		edit_person_email_cursor_changed(
+				GTK_TREE_VIEW(personeditdlg.view_email), NULL);
+	}
 
+	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(personeditdlg.view_attrib));
+	model = gtk_tree_view_get_model(GTK_TREE_VIEW(personeditdlg.view_attrib));
+	if (gtk_tree_model_get_iter_first(model, &iter))
+		gtk_tree_selection_select_iter(sel, &iter);
+		edit_person_attrib_cursor_changed(
+				GTK_TREE_VIEW(personeditdlg.view_attrib), NULL);
+
+	edit_person_email_clear( NULL );
 	edit_person_attrib_clear( NULL );
 
 	if (prefs_common.addressbook_use_editaddress_dialog) {
diff --git a/src/editaddress_other_attributes_ldap.c b/src/editaddress_other_attributes_ldap.c
index 9075b05..f360d9a 100644
--- a/src/editaddress_other_attributes_ldap.c
+++ b/src/editaddress_other_attributes_ldap.c
@@ -37,10 +37,6 @@
 #include "editaddress_other_attributes_ldap.h"
 #include "prefs_common.h"
 
-#define	ATTRIB_COL_NAME			0
-#define	ATTRIB_COL_VALUE		1
-#define ATTRIB_N_COLS			2
-#define EMAIL_N_COLS			3
 #define ATTRIB_COL_WIDTH_NAME	120
 #define ATTRIB_COL_WIDTH_VALUE	180
 
@@ -78,16 +74,23 @@ static void edit_person_attrib_clear(gpointer data) {
 
 static gboolean list_find_attribute(const gchar *attr)
 {
-	GtkCMCList *clist = GTK_CMCLIST(personEditDlg->clist_attrib);
+	GtkWidget *view = personEditDlg->view_attrib;
+	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
+	GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
+	GtkTreeIter iter;
 	UserAttribute *attrib;
-	gint row = 0;
-	while((attrib = gtk_cmclist_get_row_data(clist, row))) {
+
+	if (!gtk_tree_model_get_iter_first(model, &iter))
+		return FALSE;
+
+	do {
+		gtk_tree_model_get(model, &iter, ATTRIB_COL_PTR, &attrib, -1);
 		if (!g_ascii_strcasecmp(attrib->name, attr)) {
-			gtk_cmclist_select_row(clist, row, 0);
+			gtk_tree_selection_select_iter(sel, &iter);
 			return TRUE;
 		}
-		row++;
-	}
+	} while (gtk_tree_model_iter_next(model, &iter));
+
 	return FALSE;
 }
 
@@ -109,9 +112,9 @@ static gint edit_person_attrib_compare_func(GtkCMCList *clist, gconstpointer ptr
 
 static void edit_person_combo_box_changed(GtkComboBox *opt_menu, gpointer data)
 {
-	GtkCMCList *clist = GTK_CMCLIST(data);
-	gint row = personEditDlg->rowIndAttrib;
-	UserAttribute *attrib = gtk_cmclist_get_row_data(clist, row);
+	GtkWidget *view = GTK_WIDGET(data);
+	UserAttribute *attrib = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(view), ATTRIB_COL_PTR, NULL, NULL, NULL);
 	gint option = gtk_combo_box_get_active(opt_menu);
 	const gchar *str = attrib ? attrib->name:"";
 
@@ -127,48 +130,67 @@ static void edit_person_combo_box_changed(GtkComboBox *opt_menu, gpointer data)
 	}
 }
 
-static void edit_person_attrib_list_selected(GtkCMCList *clist, gint row, gint column, GdkEvent *event, gpointer data) {
-	UserAttribute *attrib = gtk_cmclist_get_row_data(clist, row);
-	if (attrib && !personEditDlg->read_only) {
-		int index = get_attribute_index(attrib->name);
+static void edit_person_attrib_cursor_changed(GtkTreeView *view,
+		gpointer user_data)
+{
+	UserAttribute *attrib = gtkut_tree_view_get_selected_pointer(
+			view, ATTRIB_COL_PTR, NULL, NULL, NULL);
+
+	if( attrib && !personEditDlg->read_only ) {
+		gint index = get_attribute_index(attrib->name);
+
 		if (index == -1)
 			index = 0;
 
 		gtk_combo_box_set_active(GTK_COMBO_BOX(personEditDlg->entry_atname), index);
-		gtk_entry_set_text( GTK_ENTRY(personEditDlg->entry_atvalue), attrib->value );
+		gtk_entry_set_text(GTK_ENTRY(personEditDlg->entry_atvalue), attrib->value);
+
 		gtk_widget_set_sensitive(personEditDlg->attrib_del, TRUE);
-	}
-	else {
-		/*g_printerr("Row: %d -> empty attribute\n", row);*/
-		gtk_entry_set_text( GTK_ENTRY(personEditDlg->entry_atvalue), "");	
+	} else {
 		gtk_widget_set_sensitive(personEditDlg->attrib_del, FALSE);
 	}
-	personEditDlg->rowIndAttrib = row;
-	edit_person_status_show(NULL);
+	edit_person_status_show( NULL );
 }
 
 static void edit_person_attrib_delete(gpointer data) {
-	GtkCMCList *clist = GTK_CMCLIST(personEditDlg->clist_attrib);
-	gint row = personEditDlg->rowIndAttrib;
-	UserAttribute *attrib = gtk_cmclist_get_row_data(clist, row);
+	UserAttribute *attrib;
+	GtkTreeModel *model;
+	GtkTreeSelection *sel;
+	GtkTreeIter iter;
+	gboolean has_row = FALSE;
+	gint n;
+
 	edit_person_attrib_clear(NULL);
+	edit_person_status_show(NULL);
+
+	attrib = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(personEditDlg->view_attrib), ATTRIB_COL_PTR,
+			&model, &sel, &iter);
+
 	if (attrib) {
-		/* Remove list entry */
-		gtk_cmclist_remove(clist, row);
+		/* Remove list entry, and set iter to next row, if any */
+		has_row = gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
 		addritem_free_attribute(attrib);
 		attrib = NULL;
 	}
 
 	/* Position hilite bar */
-	attrib = gtk_cmclist_get_row_data(clist, row);
-	if (!attrib) {
-		personEditDlg->rowIndAttrib = -1 + row;
-	} 
-	
-	if (!personEditDlg->read_only)
-		gtk_widget_set_sensitive(personEditDlg->attrib_del, gtk_cmclist_get_row_data(clist, 0) != NULL);
-	
-	edit_person_status_show(NULL);
+	if (!has_row) {
+		/* The removed row was the last in the list, so iter is not
+		 * valid. Find out if there is at least one row remaining
+		 * in the list, and select the last one if so. */
+		n = gtk_tree_model_iter_n_children(model, NULL);
+		if (n > 0 && gtk_tree_model_iter_nth_child(model, &iter, NULL, n-1)) {
+			/* It exists. */
+			has_row = TRUE;
+		}
+	}
+
+	if (!has_row)
+		gtk_tree_selection_select_iter(sel, &iter);
+
+	edit_person_attrib_cursor_changed(
+			GTK_TREE_VIEW(personEditDlg->view_attrib), NULL);
 }
 
 static UserAttribute *edit_person_attrib_edit(gboolean *error, UserAttribute *attrib) {
@@ -185,6 +207,7 @@ static UserAttribute *edit_person_attrib_edit(gboolean *error, UserAttribute *at
 	g_free(sValue_);
 
 	if (sName && sValue) {
+		debug_print("sname && svalue\n");
 		if (attrib == NULL) {
 			attrib = addritem_create_attribute();
 		}
@@ -206,42 +229,64 @@ static UserAttribute *edit_person_attrib_edit(gboolean *error, UserAttribute *at
 
 static void edit_person_attrib_modify(gpointer data) {
 	gboolean errFlg = FALSE;
-	GtkCMCList *clist = GTK_CMCLIST(personEditDlg->clist_attrib);
-	gint row = personEditDlg->rowIndAttrib;
-	UserAttribute *attrib = gtk_cmclist_get_row_data(clist, row);
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	UserAttribute *attrib;
+
+	attrib = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(personEditDlg->view_attrib), ATTRIB_COL_PTR,
+			&model, NULL, &iter);
 	if (attrib) {
 		edit_person_attrib_edit(&errFlg, attrib);
 		if (!errFlg) {
-			gtk_cmclist_set_text(clist, row, ATTRIB_COL_NAME, attrib->name);
-			gtk_cmclist_set_text(clist, row, ATTRIB_COL_VALUE, attrib->value);
+			gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+					ATTRIB_COL_NAME, attrib->name,
+					ATTRIB_COL_VALUE, attrib->value,
+					-1);
 			edit_person_attrib_clear(NULL);
 		}
 	}
 }
 
 static void edit_person_attrib_add(gpointer data) {
-	GtkCMCList *clist = GTK_CMCLIST(personEditDlg->clist_attrib);
 	gboolean errFlg = FALSE;
-	UserAttribute *attrib = NULL;
-	gint row = personEditDlg->rowIndAttrib;
-	if (gtk_cmclist_get_row_data(clist, row) == NULL) row = 0;
+	GtkTreeModel *model = gtk_tree_view_get_model(
+			GTK_TREE_VIEW(personEditDlg->view_attrib));
+	GtkTreeSelection *sel = gtk_tree_view_get_selection(
+			GTK_TREE_VIEW(personEditDlg->view_attrib));
+	GtkTreeIter iter, iter2;
+	UserAttribute *attrib;
 
+	if (model != NULL) {
+		/* No row selected, or list empty, add it as first row. */
+		gtk_list_store_insert(GTK_LIST_STORE(model), &iter, 0);
+	} else {
+		/* Add it after the currently selected row. */
+		gtk_list_store_insert_after(GTK_LIST_STORE(model), &iter2,
+				&iter);
+		iter = iter2;
+	}
+
+	/* Grab the values from text entries, and fill out the new row. */
 	attrib = edit_person_attrib_edit(&errFlg, NULL);
+	debug_print("after edit\n");
 	if (!errFlg) {
-		gchar *text[EMAIL_N_COLS];
-		text[ATTRIB_COL_NAME] = attrib->name;
-		text[ATTRIB_COL_VALUE] = attrib->value;
-
-		row = gtk_cmclist_insert(clist, 1 + row, text);
-		gtk_cmclist_set_row_data(clist, row, attrib);
-		gtk_cmclist_select_row(clist, row, 0);
+		debug_print("!errflg\n");
+		gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+				ATTRIB_COL_NAME, attrib->name,
+				ATTRIB_COL_VALUE, attrib->value,
+				ATTRIB_COL_PTR, attrib,
+				-1);
+		gtk_tree_selection_select_iter(sel, &iter);
 		edit_person_attrib_clear(NULL);
 	}
 }
 
 static void edit_person_entry_att_changed (GtkWidget *entry, gpointer data)
 {
-	gboolean non_empty = gtk_cmclist_get_row_data(GTK_CMCLIST(personEditDlg->clist_attrib), 0) != NULL;
+	GtkTreeModel *model = gtk_tree_view_get_model(
+			GTK_TREE_VIEW(personEditDlg->view_attrib));
+	gboolean non_empty = (gtk_tree_model_iter_n_children(model, NULL) > 0);
 	const gchar *sName;
 	int index;
 
@@ -288,19 +333,17 @@ void addressbook_edit_person_page_attrib_ldap(PersonEditDlg *dialog, gint pageNu
 
 	GtkWidget *table;
 	GtkWidget *label;
-	GtkWidget *clist_swin;
-	GtkWidget *clist;
+	GtkWidget *scrollwin;
+	GtkWidget *view;
 	GtkWidget *entry_value;
 	gint top;
+	GtkListStore *store;
+	GtkTreeViewColumn *col;
+	GtkCellRenderer *rdr;
+	GtkTreeSelection *sel;
 
 	personEditDlg = dialog;
 
-	gchar *titles[ATTRIB_N_COLS];
-	gint i;
-
-	titles[ATTRIB_COL_NAME] = N_("Name");
-	titles[ATTRIB_COL_VALUE] = N_("Value");
-
 	vbox = gtk_vbox_new(FALSE, 8);
 	gtk_widget_show(vbox);
 	gtk_container_add(GTK_CONTAINER(personEditDlg->notebook), vbox);
@@ -321,21 +364,33 @@ void addressbook_edit_person_page_attrib_ldap(PersonEditDlg *dialog, gint pageNu
 	gtk_container_add(GTK_CONTAINER(hbox), vboxl);
 	gtk_container_set_border_width(GTK_CONTAINER(vboxl), 4);
 
-	clist_swin = gtk_scrolled_window_new(NULL, NULL);
-	gtk_container_add(GTK_CONTAINER(vboxl), clist_swin);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(clist_swin),
+	scrollwin = gtk_scrolled_window_new(NULL, NULL);
+	gtk_container_add(GTK_CONTAINER(vboxl), scrollwin);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
 				       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 
-	clist = gtk_cmclist_new_with_titles(ATTRIB_N_COLS, titles);
-	gtk_container_add(GTK_CONTAINER(clist_swin), clist);
-	gtk_cmclist_set_selection_mode(GTK_CMCLIST(clist), GTK_SELECTION_BROWSE);
-	gtk_cmclist_set_column_width(GTK_CMCLIST(clist), ATTRIB_COL_NAME, ATTRIB_COL_WIDTH_NAME);
-	gtk_cmclist_set_column_width(GTK_CMCLIST(clist), ATTRIB_COL_VALUE, ATTRIB_COL_WIDTH_VALUE);
-	gtk_cmclist_set_compare_func(GTK_CMCLIST(clist), edit_person_attrib_compare_func);
-	gtk_cmclist_set_auto_sort(GTK_CMCLIST(clist), TRUE);
+	store = gtk_list_store_new(ATTRIB_N_COLS,
+			G_TYPE_STRING, G_TYPE_STRING,
+			G_TYPE_POINTER, -1);
+
+	view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+	g_object_unref(store);
+	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), TRUE);
+	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
+	gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
+
+	rdr = gtk_cell_renderer_text_new();
+	col = gtk_tree_view_column_new_with_attributes(_("Name"), rdr,
+			"markup", ATTRIB_COL_NAME, NULL);
+	gtk_tree_view_column_set_min_width(col, ATTRIB_COL_WIDTH_NAME);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
+
+	col = gtk_tree_view_column_new_with_attributes(_("Value"), rdr,
+			"markup", ATTRIB_COL_VALUE, NULL);
+	gtk_tree_view_column_set_min_width(col, ATTRIB_COL_WIDTH_VALUE);
+	gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
 
-	for (i = 0; i < ATTRIB_N_COLS; i++)
-		gtk_widget_set_can_focus(GTK_CMCLIST(clist)->column[i].button, FALSE);
+	gtk_container_add(GTK_CONTAINER(scrollwin), view);
 
 	/* Data entry area */
 	table = gtk_table_new(4, 2, FALSE);
@@ -401,8 +456,8 @@ void addressbook_edit_person_page_attrib_ldap(PersonEditDlg *dialog, gint pageNu
 	gtk_widget_show_all(vbox);
 	
 	/* Event handlers */
-	g_signal_connect(G_OBJECT(clist), "select_row",
-			  G_CALLBACK( edit_person_attrib_list_selected), NULL);
+	g_signal_connect(G_OBJECT(view), "cursor-changed",
+			G_CALLBACK(edit_person_attrib_cursor_changed), NULL);
 	g_signal_connect(G_OBJECT(buttonDel), "clicked",
 			  G_CALLBACK(edit_person_attrib_delete), NULL);
 	g_signal_connect(G_OBJECT(buttonMod), "clicked",
@@ -414,9 +469,9 @@ void addressbook_edit_person_page_attrib_ldap(PersonEditDlg *dialog, gint pageNu
 	g_signal_connect(G_OBJECT(entry_value), "key_press_event",
 			 G_CALLBACK(edit_person_entry_att_pressed), NULL);
 	g_signal_connect(G_OBJECT(combo_box), "changed",
-			 G_CALLBACK(edit_person_combo_box_changed), clist);
+			 G_CALLBACK(edit_person_combo_box_changed), view);
 
-	personEditDlg->clist_attrib  = clist;
+	personEditDlg->view_attrib  = view;
 	personEditDlg->entry_atname  = combo_box;
 	personEditDlg->entry_atvalue = entry_value;
 	personEditDlg->attrib_add = buttonAdd;
diff --git a/src/editaddress_other_attributes_ldap.h b/src/editaddress_other_attributes_ldap.h
index c63f932..86a4d06 100644
--- a/src/editaddress_other_attributes_ldap.h
+++ b/src/editaddress_other_attributes_ldap.h
@@ -29,6 +29,13 @@
 #include <gdk/gdkkeysyms.h>
 #include <gtk/gtk.h>
 
+enum {
+	ATTRIB_COL_NAME,
+	ATTRIB_COL_VALUE,
+	ATTRIB_COL_PTR,
+	ATTRIB_N_COLS
+};
+
 typedef struct _PersonEdit_dlg PersonEditDlg;
 struct _PersonEdit_dlg {
 	GtkWidget *container;
@@ -51,7 +58,7 @@ struct _PersonEdit_dlg {
 	GtkWidget *entry_email;
 	GtkWidget *entry_alias;
 	GtkWidget *entry_remarks;
-	GtkWidget *clist_email;
+	GtkWidget *view_email;
 	GtkWidget *email_up;
 	GtkWidget *email_down;
 	GtkWidget *email_del;
@@ -61,13 +68,11 @@ struct _PersonEdit_dlg {
 	/* Attribute data tab */
 	GtkWidget *entry_atname;
 	GtkWidget *entry_atvalue;
-	GtkWidget *clist_attrib;
+	GtkWidget *view_attrib;
 	GtkWidget *attrib_add;
 	GtkWidget *attrib_del;
 	GtkWidget *attrib_mod;
 
-	gint rowIndEMail;
-	gint rowIndAttrib;
 	gboolean editNew;
 	gboolean read_only;
 	gboolean ldap;

commit caa451cc1ce483333091f7ffab6be901e7a9f2b8
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sat Mar 3 10:27:56 2018 +0100

    Fix potential crashes in gtkut_tree_view_get_selected_pointer().

diff --git a/src/gtk/gtkutils.c b/src/gtk/gtkutils.c
index dc21886..b077b62 100644
--- a/src/gtk/gtkutils.c
+++ b/src/gtk/gtkutils.c
@@ -2016,15 +2016,23 @@ gpointer gtkut_tree_view_get_selected_pointer(GtkTreeView *view,
 	cm_return_val_if_fail(view != NULL, NULL);
 	cm_return_val_if_fail(column >= 0, NULL);
 
-	sel = gtk_tree_view_get_selection(view);
+	model = gtk_tree_view_get_model(view);
+	if (_model != NULL)
+		*_model = model;
 
-	cm_return_val_if_fail(
-			gtk_tree_selection_count_selected_rows(sel) == 1,
-			NULL);
+	sel = gtk_tree_view_get_selection(view);
+	if (_selection != NULL)
+		*_selection = sel;
 
-	if (!gtk_tree_selection_get_selected(sel, &model, &iter))
+	if (!gtk_tree_selection_get_selected(sel, NULL, &iter))
 		return NULL; /* No row selected */
 
+	if (_iter != NULL)
+		*_iter = iter;
+
+	if (gtk_tree_selection_count_selected_rows(sel) > 1)
+		return NULL; /* Can't work with multiselect */
+
 	cm_return_val_if_fail(
 			gtk_tree_model_get_n_columns(model) > column,
 			NULL);
@@ -2036,12 +2044,5 @@ gpointer gtkut_tree_view_get_selected_pointer(GtkTreeView *view,
 
 	gtk_tree_model_get(model, &iter, column, &ptr, -1);
 
-	if (_model != NULL)
-		*_model = model;
-	if (_selection != NULL)
-		*_selection = sel;
-	if (_iter != NULL)
-		*_iter = iter;
-
 	return ptr;
 }

commit 50fe0ebcf6e8f3de1f2e8c8a2eaef90d63cf79b0
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Feb 27 20:24:06 2018 +0100

    Update uses of gtkut_tree_view_get_selected_pointer().

diff --git a/src/account.c b/src/account.c
index 52e88f5..be5967f 100644
--- a/src/account.c
+++ b/src/account.c
@@ -1633,7 +1633,8 @@ static gint account_list_view_get_selected_account_id(GtkWidget *list_view)
 	PrefsAccount *res = NULL;
 
 	res = (PrefsAccount *)gtkut_tree_view_get_selected_pointer(
-			GTK_TREE_VIEW(list_view), ACCOUNT_DATA);
+			GTK_TREE_VIEW(list_view), ACCOUNT_DATA,
+			NULL, NULL, NULL);
 
 	return (res != NULL ? res->account_id : -1);
 }
@@ -1663,7 +1664,8 @@ static PrefsAccount *account_list_view_get_selected_account(GtkWidget *list_view
 {
 	PrefsAccount *res =
 		(PrefsAccount *)gtkut_tree_view_get_selected_pointer(
-			GTK_TREE_VIEW(list_view), ACCOUNT_DATA);
+			GTK_TREE_VIEW(list_view), ACCOUNT_DATA,
+			NULL, NULL, NULL);
 
 	return res;
 }
diff --git a/src/addressadd.c b/src/addressadd.c
index 25a39e8..1b5c574 100644
--- a/src/addressadd.c
+++ b/src/addressadd.c
@@ -131,7 +131,8 @@ static gboolean addressadd_key_pressed( GtkWidget *widget, GdkEventKey *event, g
 static void set_selected_ptr()
 {
 	addressadd_dlg.fiSelected = gtkut_tree_view_get_selected_pointer(
-			GTK_TREE_VIEW(addressadd_dlg.tree_folder), ADDRADD_COL_PTR);
+			GTK_TREE_VIEW(addressadd_dlg.tree_folder), ADDRADD_COL_PTR,
+			NULL, NULL, NULL);
 }
 
 static void addressadd_ok( GtkWidget *widget, gboolean *cancelled ) {
diff --git a/src/editldap_basedn.c b/src/editldap_basedn.c
index 8d7932c..3a01737 100644
--- a/src/editldap_basedn.c
+++ b/src/editldap_basedn.c
@@ -95,19 +95,13 @@ static void set_selected()
 {
 	GtkWidget *entry = ldapedit_basedn.basedn_entry;
 	GtkWidget *view = ldapedit_basedn.basedn_list;
-	GtkTreeModel *model;
-	GtkTreeSelection *sel;
-	GtkTreeIter iter;
 	gchar *text;
 
 	if (entry == NULL || view == NULL)
 		return;
 
-	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
-	if (!gtk_tree_selection_get_selected(sel, &model, &iter))
-		return;
-
-	gtk_tree_model_get(model, &iter, 0, &text, -1);
+	text = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(view), 0, NULL, NULL, NULL);
 
 	if (text == NULL)
 		return;
diff --git a/src/importldif.c b/src/importldif.c
index 77ff6aa..255a32a 100644
--- a/src/importldif.c
+++ b/src/importldif.c
@@ -277,18 +277,16 @@ static gboolean imp_ldif_field_move() {
 
 static void _update_selected_row()
 {
-	GtkWidget *view = impldif_dlg.view_fields;
 	GtkTreeModel *model;
-	GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
 	GtkTreeIter iter;
 	Ldif_FieldRec *rec;
 
-	if (!gtk_tree_selection_get_selected(sel, &model, &iter))
+	rec = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(impldif_dlg.view_fields), FIELD_COL_PTR,
+			&model, NULL, &iter);
+	if (rec == NULL)
 		return;
 
-	gtk_tree_model_get(model, &iter, FIELD_COL_PTR, &rec, -1);
-	cm_return_if_fail(rec != NULL);
-
 	ldif_field_set_name(rec, gtk_entry_get_text(
 				GTK_ENTRY(impldif_dlg.entryAttrib)));
 	ldif_field_set_selected(rec, gtk_toggle_button_get_active(
@@ -592,7 +590,8 @@ static void imp_ldif_field_list_cursor_changed(GtkTreeView *view,
 
 	gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryAttrib), "" );
 
-	rec = gtkut_tree_view_get_selected_pointer(view, FIELD_COL_PTR);
+	rec = gtkut_tree_view_get_selected_pointer(view, FIELD_COL_PTR,
+			NULL, NULL, NULL);
 
 	if( rec != NULL) {
 		/* Update widget contents */
diff --git a/src/mimeview.c b/src/mimeview.c
index 70a2278..eeb7a8a 100644
--- a/src/mimeview.c
+++ b/src/mimeview.c
@@ -570,7 +570,8 @@ void mimeview_destroy(MimeView *mimeview)
 MimeInfo *mimeview_get_selected_part(MimeView *mimeview)
 {
 	return gtkut_tree_view_get_selected_pointer(
-			GTK_TREE_VIEW(mimeview->ctree), COL_DATA);
+			GTK_TREE_VIEW(mimeview->ctree), COL_DATA,
+			NULL, NULL, NULL);
 }
 
 MimeInfo *mimeview_get_node_part(MimeView *mimeview, GtkTreePath *path)
diff --git a/src/plugins/pgpcore/select-keys.c b/src/plugins/pgpcore/select-keys.c
index 0598851..4bfae56 100644
--- a/src/plugins/pgpcore/select-keys.c
+++ b/src/plugins/pgpcore/select-keys.c
@@ -614,7 +614,8 @@ select_btn_cb (GtkWidget *widget, gpointer data)
     cm_return_if_fail (sk);
 
     key = gtkut_tree_view_get_selected_pointer(
-        GTK_TREE_VIEW(sk->view), COL_PTR);
+        GTK_TREE_VIEW(sk->view), COL_PTR,
+				NULL, NULL, NULL);
     if (key) {
         gpgme_user_id_t uid;
 	for (uid = key->uids; uid; uid = uid->next) {
diff --git a/src/ssl_manager.c b/src/ssl_manager.c
index 1792b35..38d8457 100644
--- a/src/ssl_manager.c
+++ b/src/ssl_manager.c
@@ -393,17 +393,13 @@ static void ssl_manager_delete_cb(GtkWidget *widget,
 {
 	SSLCertificate *cert;
 	int val;
-	GtkTreeIter sel;
+	GtkTreeIter iter;
 	GtkTreeModel *model;
 
-	if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection
-				(GTK_TREE_VIEW(manager.certlist)),
-				&model, &sel))
-		return;
-	
-	gtk_tree_model_get(model, &sel,
-			   SSL_MANAGER_CERT, &cert,
-			   -1);
+	cert = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(manager.certlist), SSL_MANAGER_CERT,
+			&model, NULL, &iter);
+
 	if (!cert)
 		return;
 
@@ -418,7 +414,7 @@ static void ssl_manager_delete_cb(GtkWidget *widget,
 	
 	ssl_certificate_delete_from_disk(cert);
 	ssl_certificate_destroy(cert);
-	gtk_list_store_remove(GTK_LIST_STORE(model), &sel);
+	gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
 }
 
 static void ssl_manager_view_cb(GtkWidget *widget, 
@@ -427,7 +423,8 @@ static void ssl_manager_view_cb(GtkWidget *widget,
 	SSLCertificate *cert;
 
 	cert = gtkut_tree_view_get_selected_pointer(
-			GTK_TREE_VIEW(manager.certlist), SSL_MANAGER_CERT);
+			GTK_TREE_VIEW(manager.certlist), SSL_MANAGER_CERT,
+			NULL, NULL, NULL);
 
 	if (!cert)
 		return;

commit b7e39594374d6d5fc08430a8cc83e83fd655eee4
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Tue Feb 27 20:19:37 2018 +0100

    Make the gtkut_tree_view_get_selected_pointer() more versatile.
    
    It can now be used also for non-trivial use cases, where
    the caller needs to further work with the model and/or
    selection, or if a string value needs to be read from the
    model.

diff --git a/src/gtk/gtkutils.c b/src/gtk/gtkutils.c
index 453e846..dc21886 100644
--- a/src/gtk/gtkutils.c
+++ b/src/gtk/gtkutils.c
@@ -2004,12 +2004,14 @@ gboolean gtkut_pointer_is_grabbed(GtkWidget *widget)
 }
 
 gpointer gtkut_tree_view_get_selected_pointer(GtkTreeView *view,
-		gint column)
+		gint column, GtkTreeModel **_model, GtkTreeSelection **_selection,
+		GtkTreeIter *_iter)
 {
 	GtkTreeIter iter;
 	GtkTreeModel *model;
 	GtkTreeSelection *sel;
 	gpointer ptr;
+	GType type;
 
 	cm_return_val_if_fail(view != NULL, NULL);
 	cm_return_val_if_fail(column >= 0, NULL);
@@ -2026,11 +2028,20 @@ gpointer gtkut_tree_view_get_selected_pointer(GtkTreeView *view,
 	cm_return_val_if_fail(
 			gtk_tree_model_get_n_columns(model) > column,
 			NULL);
+
+	type = gtk_tree_model_get_column_type(model, column);
 	cm_return_val_if_fail(
-			gtk_tree_model_get_column_type(model, column) == G_TYPE_POINTER,
+			type == G_TYPE_POINTER || type == G_TYPE_STRING,
 			NULL);
 
 	gtk_tree_model_get(model, &iter, column, &ptr, -1);
 
+	if (_model != NULL)
+		*_model = model;
+	if (_selection != NULL)
+		*_selection = sel;
+	if (_iter != NULL)
+		*_iter = iter;
+
 	return ptr;
 }
diff --git a/src/gtk/gtkutils.h b/src/gtk/gtkutils.h
index 853eba4..15b95f4 100644
--- a/src/gtk/gtkutils.h
+++ b/src/gtk/gtkutils.h
@@ -235,8 +235,14 @@ gboolean auto_configure_service_sync(const gchar *service, const gchar *domain,
 gboolean gtkut_pointer_is_grabbed(GtkWidget *widget);
 
 /* Returns pointer stored in selected row of a tree view's model
- * in a given column. The column has to be of type G_TYPE_POINTER. */
+ * in a given column. The column has to be of type G_TYPE_POINTER
+ * or G_TYPE_STRING (in this case, the returned value has to be
+ * freed by the caller.
+ * _model, _selection and _iter parameters are optional, and if
+ * not NULL, they will be set to point to corresponding GtkTreeModel,
+ * GtkTreeSelection, and GtkTreeIter of the selected row. */
 gpointer gtkut_tree_view_get_selected_pointer(GtkTreeView *view,
-		gint column);
+		gint column, GtkTreeModel **_model, GtkTreeSelection **_selection,
+		GtkTreeIter *_iter);
 
 #endif /* __GTKUTILS_H__ */

commit 01f71039837bafaeaa491754e2ca94bdb6225c2f
Author: Andrej Kacian <ticho at claws-mail.org>
Date:   Sun Feb 25 20:40:38 2018 +0100

    Add gtkut_tree_view_get_selected_pointer() helper function.
    
    It's meant for the simple cases when you just want to get
    a pointer out of a treeview's selected row and you're not
    going to do anything with the view, nor the model.

diff --git a/src/account.c b/src/account.c
index 87f8953..52e88f5 100644
--- a/src/account.c
+++ b/src/account.c
@@ -1630,19 +1630,12 @@ static void account_create_list_view_columns(GtkWidget *list_view)
  */
 static gint account_list_view_get_selected_account_id(GtkWidget *list_view)
 {
-	GtkTreeSelection *selector;
-	GtkTreeModel *model;
-	GtkTreeIter iter;
 	PrefsAccount *res = NULL;
 
-	selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
-	
-	if (!gtk_tree_selection_get_selected(selector, &model, &iter))
-		return -1;
-
-	gtk_tree_model_get(model, &iter, ACCOUNT_DATA, &res, -1);
+	res = (PrefsAccount *)gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(list_view), ACCOUNT_DATA);
 
-	return res->account_id;			   
+	return (res != NULL ? res->account_id : -1);
 }
 
 /*!
@@ -1668,19 +1661,11 @@ static GtkTreePath *account_list_view_get_selected_account_path(GtkWidget *list_
  */
 static PrefsAccount *account_list_view_get_selected_account(GtkWidget *list_view)
 {
-	GtkTreeSelection *selector;
-	GtkTreeModel *model;
-	GtkTreeIter iter;
-	PrefsAccount *res = NULL;
-
-	selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
-	
-	if (!gtk_tree_selection_get_selected(selector, &model, &iter))
-		return NULL;
-
-	gtk_tree_model_get(model, &iter, ACCOUNT_DATA, &res, -1);
+	PrefsAccount *res =
+		(PrefsAccount *)gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(list_view), ACCOUNT_DATA);
 
-	return res;			   
+	return res;
 }
 
 /*!
diff --git a/src/addressadd.c b/src/addressadd.c
index 78aea88..25a39e8 100644
--- a/src/addressadd.c
+++ b/src/addressadd.c
@@ -130,16 +130,8 @@ static gboolean addressadd_key_pressed( GtkWidget *widget, GdkEventKey *event, g
 /* Points addressadd_dlg.fiSelected to the selected item */
 static void set_selected_ptr()
 {
-	GtkWidget *view = addressadd_dlg.tree_folder;
-	GtkTreeModel *model;
-	GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
-	GtkTreeIter iter;
-
-	if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
-		gtk_tree_model_get(model, &iter,
-				ADDRADD_COL_PTR, &addressadd_dlg.fiSelected,
-				-1);
-	}
+	addressadd_dlg.fiSelected = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(addressadd_dlg.tree_folder), ADDRADD_COL_PTR);
 }
 
 static void addressadd_ok( GtkWidget *widget, gboolean *cancelled ) {
diff --git a/src/gtk/gtkutils.c b/src/gtk/gtkutils.c
index f390f2f..453e846 100644
--- a/src/gtk/gtkutils.c
+++ b/src/gtk/gtkutils.c
@@ -2002,3 +2002,35 @@ gboolean gtkut_pointer_is_grabbed(GtkWidget *widget)
 
 	return gdk_display_device_is_grabbed(display, pointerdev);
 }
+
+gpointer gtkut_tree_view_get_selected_pointer(GtkTreeView *view,
+		gint column)
+{
+	GtkTreeIter iter;
+	GtkTreeModel *model;
+	GtkTreeSelection *sel;
+	gpointer ptr;
+
+	cm_return_val_if_fail(view != NULL, NULL);
+	cm_return_val_if_fail(column >= 0, NULL);
+
+	sel = gtk_tree_view_get_selection(view);
+
+	cm_return_val_if_fail(
+			gtk_tree_selection_count_selected_rows(sel) == 1,
+			NULL);
+
+	if (!gtk_tree_selection_get_selected(sel, &model, &iter))
+		return NULL; /* No row selected */
+
+	cm_return_val_if_fail(
+			gtk_tree_model_get_n_columns(model) > column,
+			NULL);
+	cm_return_val_if_fail(
+			gtk_tree_model_get_column_type(model, column) == G_TYPE_POINTER,
+			NULL);
+
+	gtk_tree_model_get(model, &iter, column, &ptr, -1);
+
+	return ptr;
+}
diff --git a/src/gtk/gtkutils.h b/src/gtk/gtkutils.h
index 47f040a..853eba4 100644
--- a/src/gtk/gtkutils.h
+++ b/src/gtk/gtkutils.h
@@ -234,4 +234,9 @@ gboolean auto_configure_service_sync(const gchar *service, const gchar *domain,
 
 gboolean gtkut_pointer_is_grabbed(GtkWidget *widget);
 
+/* Returns pointer stored in selected row of a tree view's model
+ * in a given column. The column has to be of type G_TYPE_POINTER. */
+gpointer gtkut_tree_view_get_selected_pointer(GtkTreeView *view,
+		gint column);
+
 #endif /* __GTKUTILS_H__ */
diff --git a/src/importldif.c b/src/importldif.c
index 86ea2dd..77ff6aa 100644
--- a/src/importldif.c
+++ b/src/importldif.c
@@ -588,16 +588,12 @@ static void imp_ldif_page_file( gint pageNum, gchar *pageLbl ) {
 static void imp_ldif_field_list_cursor_changed(GtkTreeView *view,
 		gpointer user_data)
 {
-	GtkTreeModel *model;
-	GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
-	GtkTreeIter iter;
 	Ldif_FieldRec *rec;
 
-	if (!gtk_tree_selection_get_selected(sel, &model, &iter))
-		return; /* No row selected */
-	gtk_tree_model_get(model, &iter, FIELD_COL_PTR, &rec, -1);
-
 	gtk_entry_set_text( GTK_ENTRY(impldif_dlg.entryAttrib), "" );
+
+	rec = gtkut_tree_view_get_selected_pointer(view, FIELD_COL_PTR);
+
 	if( rec != NULL) {
 		/* Update widget contents */
 		gtk_label_set_text(
diff --git a/src/mimeview.c b/src/mimeview.c
index 8fa8cd3..70a2278 100644
--- a/src/mimeview.c
+++ b/src/mimeview.c
@@ -569,16 +569,8 @@ void mimeview_destroy(MimeView *mimeview)
 
 MimeInfo *mimeview_get_selected_part(MimeView *mimeview)
 {
-	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(mimeview->ctree));
-	GtkTreeIter iter;
-	GtkTreeSelection *selection;
-	MimeInfo *partinfo = NULL;
-	
-	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(mimeview->ctree));
-	if (gtk_tree_selection_get_selected(selection, NULL, &iter))
-		gtk_tree_model_get(model, &iter, COL_DATA, &partinfo, -1);
-
-	return partinfo;
+	return gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(mimeview->ctree), COL_DATA);
 }
 
 MimeInfo *mimeview_get_node_part(MimeView *mimeview, GtkTreePath *path)
diff --git a/src/plugins/pgpcore/select-keys.c b/src/plugins/pgpcore/select-keys.c
index f558f6b..0598851 100644
--- a/src/plugins/pgpcore/select-keys.c
+++ b/src/plugins/pgpcore/select-keys.c
@@ -610,18 +610,11 @@ select_btn_cb (GtkWidget *widget, gpointer data)
     struct select_keys_s *sk = data;
     gboolean use_key;
     gpgme_key_t key;
-    GtkTreeModel *model;
-    GtkTreeSelection *sel;
-    GtkTreeIter iter;
 
     cm_return_if_fail (sk);
-		sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(sk->view));
-    if (!gtk_tree_selection_get_selected(sel, &model, &iter)) {
-        debug_print ("** nothing selected\n");
-        return;
-    }
 
-    gtk_tree_model_get(model, &iter, COL_PTR, &key, -1);
+    key = gtkut_tree_view_get_selected_pointer(
+        GTK_TREE_VIEW(sk->view), COL_PTR);
     if (key) {
         gpgme_user_id_t uid;
 	for (uid = key->uids; uid; uid = uid->next) {
diff --git a/src/ssl_manager.c b/src/ssl_manager.c
index 9c75cf0..1792b35 100644
--- a/src/ssl_manager.c
+++ b/src/ssl_manager.c
@@ -425,17 +425,10 @@ static void ssl_manager_view_cb(GtkWidget *widget,
 			        gpointer data) 
 {
 	SSLCertificate *cert;
-	GtkTreeIter sel;
-	GtkTreeModel *model;
 
-	if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection
-				(GTK_TREE_VIEW(manager.certlist)),
-				&model, &sel))
-		return;
-	
-	gtk_tree_model_get(model, &sel,
-			   SSL_MANAGER_CERT, &cert,
-			   -1);
+	cert = gtkut_tree_view_get_selected_pointer(
+			GTK_TREE_VIEW(manager.certlist), SSL_MANAGER_CERT);
+
 	if (!cert)
 		return;
 

-----------------------------------------------------------------------


hooks/post-receive
-- 
Claws Mail


More information about the Commits mailing list