[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] chanlist treeview



Hi all,

Here's the (hopefully final) channel list treeview patch.  Sorry for the
delay, real-world stuff intervened.

I went ahead and just finished/cleaned up the version which uses glib's
binary trees.  I think the simpler code is probably worth any
performance loss.  No real functionality changes; I toyed with the idea
of trying to improve the GUI, but couldn't really come up with anything
satisfactory.  I leave that as an academic exercise for the reader :)

Patch is attached.

Cheers,

   Vince


-- 
    Vincent Ho
loki@internode.on.net

If all the world's economists were laid end to end, we wouldn't reach a
conclusion.
        -- William Baumol
Index: src/fe-gtk/fe-gtk.h
===================================================================
RCS file: /cvsroot/xchat/xchat2/src/fe-gtk/fe-gtk.h,v
retrieving revision 1.7
diff -u -r1.7 fe-gtk.h
--- src/fe-gtk/fe-gtk.h	17 Mar 2003 03:54:23 -0000	1.7
+++ src/fe-gtk/fe-gtk.h	7 Apr 2003 13:52:44 -0000
@@ -23,6 +23,7 @@
 #include <gtk/gtkwidget.h>
 #include <gtk/gtkcontainer.h>
 #include <gtk/gtksignal.h>
+#include <gtk/gtktreemodel.h>
 
 #undef gtk_signal_connect
 #define gtk_signal_connect g_signal_connect
@@ -47,6 +48,7 @@
 	GtkWidget *chanlist_wild;
 	GtkWidget *chanlist_window;
 	GtkWidget *chanlist_list;
+	GtkWidget *chanlist_view;	/* treeview */
 	GtkWidget *chanlist_refresh;
 	GtkWidget *chanlist_label;
 
@@ -56,6 +58,10 @@
 
 	gboolean chanlist_match_wants_channel;	/* match in channel name */
 	gboolean chanlist_match_wants_topic;	/* match in topic */
+
+	GTree *chanlist_itertree;	/* tree of channel iters */
+	char *chanlist_searchchan;	/* channel we're currently searching for */
+	char *chanlist_prevchan;	/* previous channel in sorted order */
 
 #ifndef WIN32
 	regex_t chanlist_match_regex;	/* compiled regular expression here */
Index: src/fe-gtk/fe-gtk.c
===================================================================
RCS file: /cvsroot/xchat/xchat2/src/fe-gtk/fe-gtk.c,v
retrieving revision 1.14
diff -u -r1.14 fe-gtk.c
--- src/fe-gtk/fe-gtk.c	23 Feb 2003 14:27:26 -0000	1.14
+++ src/fe-gtk/fe-gtk.c	7 Apr 2003 13:52:46 -0000
@@ -458,12 +458,6 @@
 }
 
 void
-fe_chan_list_end (struct server *serv)
-{
-	gtk_widget_set_sensitive (serv->gui->chanlist_refresh, TRUE);
-}
-
-void
 fe_notify_update (char *name)
 {
 	if (name)
Index: src/fe-gtk/chanlist.c
===================================================================
RCS file: /cvsroot/xchat/xchat2/src/fe-gtk/chanlist.c,v
retrieving revision 1.5
diff -u -r1.5 chanlist.c
--- src/fe-gtk/chanlist.c	4 Jan 2003 08:55:34 -0000	1.5
+++ src/fe-gtk/chanlist.c	7 Apr 2003 13:52:50 -0000
@@ -29,6 +29,8 @@
 
 #include "fe-gtk.h"
 
+#include <glib/gtree.h>
+
 #include <gtk/gtkcheckbutton.h>
 #include <gtk/gtktable.h>
 #include <gtk/gtkalignment.h>
@@ -41,6 +43,9 @@
 #include <gtk/gtkstock.h>
 #include <gdk/gdkkeysyms.h>
 #include <gtk/gtkhbbox.h>
+#include <gtk/gtkliststore.h>
+#include <gtk/gtktreeview.h>
+#include <gtk/gtktreeselection.h>
 
 #include "../common/xchat.h"
 #include "../common/xchatc.h"
@@ -49,6 +54,199 @@
 #include "gtkutil.h"
 #include "maingui.h"
 
+/* model for the chanlist treeview */
+enum
+{
+	CHAN_COLUMN,
+	USERS_COLUMN,
+	TOPIC_COLUMN,
+	N_COLUMNS
+};
+
+
+/* just to shorten code  -Vince */
+static GtkListStore *
+get_store (struct server *serv)
+{
+	return GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (serv->gui->chanlist_view)));
+}
+
+static int
+chanlist_cmp (const char *chan1, const char *chan2)
+{
+	return strcasecmp (chan1, chan2);
+}
+
+/* Callback function for g_tree_search(), which we use to find the previous
+ * existing channel node.
+ */
+static int
+chanlist_cmp_serv (const char *nodechan, struct server *serv)
+{
+	int result = chanlist_cmp (serv->gui->chanlist_searchchan, nodechan);
+	
+	/* If the channel we're searching for is greater than the one we're
+	 * currently comparing against, then it's possibly the previous
+	 * channel.
+	 */
+	if (result > 0)
+		serv->gui->chanlist_prevchan = (char *)nodechan;
+
+	return result;
+}
+
+/* Gets an iterator pointing to the location where a channel should be
+ * inserted in ascending order.
+ */
+static void
+chanlist_itertree_get (struct server *serv, char *chan, GtkTreeIter *iter_ret)
+{
+	GtkListStore *store = get_store (serv);
+	GtkTreeIter *piter = NULL;
+	GtkTreeIter iter;
+	char *chancopy;
+	GtkTreeIter *itercopy;
+
+	/* so the search func knows what channel we want to insert */
+	serv->gui->chanlist_searchchan = chan;
+	serv->gui->chanlist_prevchan = NULL;
+	g_tree_search (serv->gui->chanlist_itertree,
+	               (GCompareFunc)chanlist_cmp_serv, serv);
+	/* chanlist_prevchan can be set by the chanlist_cmp_serv() callback */
+	if (serv->gui->chanlist_prevchan)
+	{
+		piter = g_tree_lookup (serv->gui->chanlist_itertree, serv->gui->chanlist_prevchan);
+		if (!piter)
+			g_print (__FILE__ "piter for %s is null\n", serv->gui->chanlist_prevchan);
+	}
+	/* piter is now the previous channel in sorted order, or null, meaning
+	 * there is no such channel.
+	 */
+	gtk_list_store_insert_after (store, &iter, piter);
+	
+	/* insert the new channel into the tree */
+	chancopy = g_strdup (chan);
+	itercopy = gtk_tree_iter_copy (&iter);
+	g_tree_insert (serv->gui->chanlist_itertree, chancopy, itercopy);
+	
+	*iter_ret = iter;
+}
+
+/* Clears the list, and destroys/re-initialises the cache tree */
+static void clear_chanlist_view (struct server *serv)
+{
+	gtk_list_store_clear (get_store (serv));
+	g_tree_destroy (serv->gui->chanlist_itertree);
+	serv->gui->chanlist_itertree = g_tree_new_full ((GCompareDataFunc)chanlist_cmp,
+		NULL, g_free, (GDestroyNotify)gtk_tree_iter_free);
+
+}
+
+
+static void
+chanlist_join (GtkWidget * wid, struct server *serv)
+{
+	GtkTreeView *view = GTK_TREE_VIEW (serv->gui->chanlist_view);
+	GtkTreeIter iter;
+	char *chan = NULL;
+	char tbuf[CHANLEN + 6];
+
+	if (gtkutil_treeview_get_selected (view, &iter,
+	                                   CHAN_COLUMN, &chan, -1))
+	{
+		if (serv->connected && (strcmp (chan, "*") != 0))
+		{
+			snprintf (tbuf, sizeof (tbuf), "join %s", chan);
+			handle_command (serv->server_session, tbuf, FALSE);
+		} else
+			gtkutil_simpledialog ("Not connected.");
+
+	  g_free (chan);
+	}
+}
+
+static gboolean
+chanlist_treeview_clicked_cb (GtkWidget *view, GdkEventButton *event,
+                              gpointer data)
+{
+	if (!event)
+	  return FALSE;
+	
+	switch (event->button)
+	{
+		case 1:
+			if (event->type == GDK_2BUTTON_PRESS)
+	  			chanlist_join (NULL, (struct server *)data);
+			break;
+		default:
+			break;
+	}
+	return FALSE;
+}
+
+/* this is the column id that represents unsorted columns
+ * We don't know this ahead of time... */
+static int unsorted_col_id;
+
+static GtkWidget *
+chanlist_treeview_new (GtkWidget *box, struct server *serv)
+{
+	GtkListStore *store;
+	GtkWidget *view;
+	GtkTreeViewColumn *col;
+
+	store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_INT,
+	                            G_TYPE_STRING);
+	g_return_val_if_fail (store != NULL, NULL);
+	view = gtkutil_treeview_new (box, GTK_TREE_MODEL (store), NULL,
+	                             CHAN_COLUMN, _("Channel"),
+	                             USERS_COLUMN, _("Users"),
+	                             TOPIC_COLUMN, _("Topic"),
+	                             -1);
+
+	g_signal_connect (G_OBJECT (view), "button-press-event",
+	                  G_CALLBACK (chanlist_treeview_clicked_cb), serv);
+
+	col = gtk_tree_view_get_column (GTK_TREE_VIEW (view), CHAN_COLUMN);
+	gtk_tree_view_column_set_alignment (col, 0.5);
+	unsorted_col_id = gtk_tree_view_column_get_sort_column_id (col);
+	gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
+	gtk_tree_view_column_set_max_width (col, 300);
+	gtk_tree_view_column_set_resizable (col, TRUE);
+
+	col = gtk_tree_view_get_column (GTK_TREE_VIEW (view), USERS_COLUMN);
+	gtk_tree_view_column_set_alignment (col, 0.5);
+	gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
+	gtk_tree_view_column_set_resizable (col, TRUE);
+
+	col = gtk_tree_view_get_column (GTK_TREE_VIEW (view), TOPIC_COLUMN);
+	gtk_tree_view_column_set_alignment (col, 0.5);
+	gtk_tree_view_column_set_resizable (col, TRUE);
+
+	gtk_widget_show (view);
+	return view;
+}
+
+/* Turn column sorting on/off */
+void toggle_sorting_enabled (struct server *serv, gboolean enabled)
+{
+	GtkTreeViewColumn *col, *col2;
+
+	col = gtk_tree_view_get_column (GTK_TREE_VIEW (serv->gui->chanlist_view),
+	                                CHAN_COLUMN);
+	col2 = gtk_tree_view_get_column (GTK_TREE_VIEW (serv->gui->chanlist_view),
+	                                 USERS_COLUMN);
+	if (enabled)
+	{
+		gtk_tree_view_column_set_sort_column_id (col, CHAN_COLUMN);
+		gtk_tree_view_column_set_sort_column_id (col2, USERS_COLUMN);
+	}
+	else
+	{
+		gtk_tree_view_column_set_sort_column_id (col, unsorted_col_id);
+		gtk_tree_view_column_set_sort_column_id (col2, unsorted_col_id);
+	}
+}
 
 /**
  * Accepts a regex_t pointer and string to test it with 
@@ -81,40 +279,6 @@
 #endif
 
 /**
- * Sorts the channel list based upon the user field.
- */
-static gint
-chanlist_compare_user (GtkCList * clist,
-							  gconstpointer ptr1, gconstpointer ptr2)
-{
-	int int1;
-	int int2;
-
-	GtkCListRow *row1 = (GtkCListRow *) ptr1;
-	GtkCListRow *row2 = (GtkCListRow *) ptr2;
-
-	int1 = atoi (GTK_CELL_TEXT (row1->cell[clist->sort_column])->text);
-	int2 = atoi (GTK_CELL_TEXT (row2->cell[clist->sort_column])->text);
-
-	return int1 > int2 ? 1 : -1;
-}
-
-/**
- * Provides the default case-insensitive sorting for the channel 
- * list.
- */
-static gint
-chanlist_compare_text_ignore_case (GtkCList * clist,
-											  gconstpointer ptr1, gconstpointer ptr2)
-{
-	GtkCListRow *row1 = (GtkCListRow *) ptr1;
-	GtkCListRow *row2 = (GtkCListRow *) ptr2;
-
-	return rfc_casecmp (GTK_CELL_TEXT (row1->cell[clist->sort_column])->text,
-							 GTK_CELL_TEXT (row2->cell[clist->sort_column])->text);
-}
-
-/**
  * Updates the caption to reflect the number of users and channels
  */
 static void
@@ -203,9 +367,11 @@
 static void
 chanlist_place_row_in_gui (struct server *serv, gchar ** next_row)
 {
-	int num_users = atoi (next_row[1]);
-	gfloat val, end;
-	GtkAdjustment *adj;
+	GtkListStore *store;
+	GtkTreeIter iter;
+	char *chan = next_row[0];
+	int num_users = strtol (next_row[1], NULL, 10);
+	char *topic = next_row[2];
 
 	/* First, update the 'found' counter values */
 	serv->gui->chanlist_users_found_count += num_users;
@@ -262,24 +428,15 @@
 		}
 	}
 
-	adj = gtk_clist_get_vadjustment (GTK_CLIST (serv->gui->chanlist_list));
-	val = adj->value;
-	/*
-	 * If all the above above tests passed or if no text was in the 
-	 * chanlist_wild_text, add this entry to the GUI
-	 */
-	gtk_clist_prepend (GTK_CLIST (serv->gui->chanlist_list), next_row);
+	/* it matches.. insert it now */
+	store = get_store (serv);
+	chanlist_itertree_get (serv, chan, &iter);
+	gtk_list_store_set (store, &iter, 0, chan, 1, num_users, 2, topic, -1);
 
 	/* Update the 'shown' counter values */
 	serv->gui->chanlist_users_shown_count += num_users;
 	serv->gui->chanlist_channels_shown_count++;
 
-	/* restore original scrollbar position */
-	end = adj->upper - adj->lower - adj->page_size;
-	if (val > end)
-		val = end;
-	gtk_adjustment_set_value (adj, val);
-
 	chanlist_update_caption (serv);
 }
 
@@ -291,12 +448,15 @@
 {
 	if (serv->connected)
 	{
+
 		chanlist_data_free (serv);
 		chanlist_reset_counters (serv);
 		chanlist_update_caption (serv);
 
-		gtk_clist_clear (GTK_CLIST (serv->gui->chanlist_list));
-		gtk_widget_set_sensitive (serv->gui->chanlist_refresh, FALSE);
+		/* empty and re-initialise the list */
+		clear_chanlist_view (serv);
+		/* turn off column sorting, it slows insertion to a crawl */
+		toggle_sorting_enabled (serv, FALSE);
 
 		handle_command (serv->server_session, "list", FALSE);
 	} else
@@ -322,7 +482,6 @@
 chanlist_build_gui_list (struct server *serv)
 {
 	GSList *rows;
-	GtkCList *clist;
 
 	/* first check if the list is present */
 	if (serv->gui->chanlist_data_stored_rows == NULL)
@@ -331,13 +490,9 @@
 		return;
 	}
 
-	clist = GTK_CLIST (serv->gui->chanlist_list);
-
-	/* turn off sorting because this _greatly_ quickens the reinsertion */
-	gtk_clist_set_auto_sort (clist, FALSE);
-	/* freeze that GtkCList to make it go fasssster as well */
-	gtk_clist_freeze (clist);
-	gtk_clist_clear (clist);
+	/* Clear the existing list, and disable sorting */
+	clear_chanlist_view (serv);
+	toggle_sorting_enabled (serv, FALSE);
 
 	/* Reset the counters */
 	chanlist_reset_counters (serv);
@@ -349,9 +504,7 @@
 		chanlist_place_row_in_gui (serv, (gchar **) rows->data);
 	}
 
-	gtk_clist_thaw (clist);
-	gtk_clist_set_auto_sort (clist, TRUE);
-	gtk_clist_sort (clist);
+	toggle_sorting_enabled (serv, TRUE);
 }
 
 /**
@@ -365,6 +518,8 @@
 	gchar **next_row;
 
 	next_row = (gchar **) malloc (sizeof (gchar *) * 3);
+	if (!next_row)
+	  return;
 	next_row[0] = strdup (chan);
 	next_row[1] = strdup (users);
 	next_row[2] = strip_color (topic);
@@ -376,6 +531,17 @@
 	chanlist_place_row_in_gui (serv, next_row);
 }
 
+
+void
+fe_chan_list_end (struct server *serv)
+{
+	gtk_widget_set_sensitive (serv->gui->chanlist_refresh, TRUE);
+	/* re-enable sorting on the channel column of the tree */
+	toggle_sorting_enabled (serv, TRUE);
+}
+
+
+
 /**
  * The next several functions simply handle signals from widgets to update 
  * the list and state variables. 
@@ -431,77 +597,24 @@
 	serv->gui->chanlist_match_wants_topic = GTK_TOGGLE_BUTTON (wid)->active;
 }
 
-static void
-chanlist_click_column (GtkWidget * clist, gint column, struct server *serv)
-{
-	/* If the user clicks the same column twice in a row,
-	 * swap the sort type. Otherwise, assume he wishes
-	 * to sort by another column, but using the same
-	 * direction. 
-	 */
-
-	if (serv->gui->chanlist_last_column == column)
-	{
-		if (serv->gui->chanlist_sort_type == GTK_SORT_ASCENDING)
-			serv->gui->chanlist_sort_type = GTK_SORT_DESCENDING;
-		else
-			serv->gui->chanlist_sort_type = GTK_SORT_ASCENDING;
-	}
-
-	serv->gui->chanlist_last_column = column;
-
-	gtk_clist_set_sort_type (GTK_CLIST (clist), serv->gui->chanlist_sort_type);
-	gtk_clist_set_sort_column (GTK_CLIST (clist), column);
-
-	/* Since ascii sorting the numbers is a no go, use a custom
-	 * sorter function for the 'users' column.
-	 */
-	if (column == 1)
-		gtk_clist_set_compare_func (GTK_CLIST (clist), (GtkCListCompareFunc)
-											 chanlist_compare_user);
-	else
-		/* In the 0 or 2 case, use the case-insensitive string 
-		 * compare function. 
-		 */
-		gtk_clist_set_compare_func (GTK_CLIST (clist), (GtkCListCompareFunc)
-											 chanlist_compare_text_ignore_case);
-
-	gtk_clist_sort (GTK_CLIST (clist));
-}
-
-static void
-chanlist_join (GtkWidget * wid, struct server *serv)
-{
-	int row;
-	char *chan;
-	char tbuf[CHANLEN + 6];
-
-	row = gtkutil_clist_selection (serv->gui->chanlist_list);
-	if (row != -1)
-	{
-		gtk_clist_get_text (GTK_CLIST (serv->gui->chanlist_list), row, 0,
-								  &chan);
-		if (serv->connected && (strcmp (chan, "*") != 0))
-		{
-			snprintf (tbuf, sizeof (tbuf), "join %s", chan);
-			handle_command (serv->server_session, tbuf, FALSE);
-		} else
-			gdk_beep ();
-	}
-}
 
 static void
 chanlist_filereq_done (struct server *serv, void *data2, char *file)
 {
+	GtkTreeModel *model = GTK_TREE_MODEL (get_store (serv));
+	GtkTreeIter iter;
 	time_t t = time (0);
-	int i = 0;
 	int fh;
-	char *chan, *users, *topic;
+	char *chan, *topic;
+	int numusers;
 	char buf[1024];
 
 	if (!file)
 		return;
 
+	if (!gtk_tree_model_get_iter_from_string (model, &iter, "0"))
+		return;
+
 	fh = open (file, O_TRUNC | O_WRONLY | O_CREAT, 0600);
 	if (fh == -1)
 		return;
@@ -510,17 +623,14 @@
 				 serv->servername, ctime (&t));
 	write (fh, buf, strlen (buf));
 
-	while (1)
+	do
 	{
-		if (!gtk_clist_get_text
-			 (GTK_CLIST (serv->gui->chanlist_list), i, 0, &chan))
-			break;
-		gtk_clist_get_text (GTK_CLIST (serv->gui->chanlist_list), i, 1, &users);
-		gtk_clist_get_text (GTK_CLIST (serv->gui->chanlist_list), i, 2, &topic);
-		i++;
-		snprintf (buf, sizeof buf, "%-16s %-5s%s\n", chan, users, topic);
+		gtk_tree_model_get (model, &iter, 0, &chan, 1, &numusers, 2, &topic, -1);
+		snprintf (buf, sizeof buf, "%-16s %-5d%s\n", chan, numusers, topic);
 		write (fh, buf, strlen (buf));
-	}
+		g_free (chan);
+		g_free (topic);
+	} while (gtk_tree_model_iter_next (model, &iter));
 
 	close (fh);
 }
@@ -528,16 +638,14 @@
 static void
 chanlist_save (GtkWidget * wid, struct server *serv)
 {
-	char *temp;
+	GtkTreeModel *model = GTK_TREE_MODEL (get_store (serv));
 
-	if (!gtk_clist_get_text
-		 (GTK_CLIST (serv->gui->chanlist_list), 0, 0, &temp))
+	if (gtk_tree_model_iter_n_children (model, NULL) > 0)
 	{
+		gtkutil_file_req (_("Select an output filename"), chanlist_filereq_done,
+		                  serv, 0, TRUE);
+	} else
 		gtkutil_simpledialog (_("I can't save an empty list!"));
-		return;
-	}
-	gtkutil_file_req (_("Select an output filename"), chanlist_filereq_done,
-							serv, 0, TRUE);
 }
 
 static void
@@ -552,16 +660,6 @@
 	serv->gui->chanlist_maxusers = gtk_spin_button_get_value_as_int (wid);
 }
 
-static void
-chanlist_row_selected (GtkWidget * clist, gint row, gint column,
-							  GdkEventButton * even, struct server *serv)
-{
-	if (even && even->type == GDK_2BUTTON_PRESS)
-	{
-		chanlist_join (0, (struct server *) serv);
-	}
-}
-
 /**
  * Handles the window's destroy event to free allocated memory.
  */
@@ -584,15 +682,19 @@
 chanlist_closegui (GtkWidget *wid, server *serv)
 {
 	if (is_server (serv))
+	{
 		serv->gui->chanlist_window = 0;
+		if (serv->gui->chanlist_itertree)
+			g_tree_destroy (serv->gui->chanlist_itertree);
+	}
 }
 
 void
 chanlist_opengui (struct server *serv)
 {
-	gchar *titles[] = { _("Channel"), _("Users"), _("Topic") };
 	GtkWidget *frame, *vbox, *hbox, *table, *wid;
 	char tbuf[256];
+	GtkWidget *vbox1;
 
 	if (serv->gui->chanlist_window)
 	{
@@ -615,6 +717,13 @@
 		mg_create_generic_tab ("chanlist", tbuf, FALSE, TRUE, chanlist_closegui,
 								serv, 450, 300, &vbox, serv);
 
+	/* inner box, for padding */
+	vbox1 = gtk_vbox_new (0, 0);
+	gtk_container_add (GTK_CONTAINER (vbox), vbox1);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox1), 6);
+	gtk_widget_show (vbox1);
+	vbox = vbox1;
+
 	frame = gtk_frame_new (_("List display options:"));
 	gtk_container_set_border_width (GTK_CONTAINER (frame), 2);
 	gtk_widget_show (frame);
@@ -710,25 +819,11 @@
 							  (gpointer) serv);
 	gtk_widget_show (wid);
 
-	serv->gui->chanlist_list =
-		gtkutil_clist_new (3, titles, vbox, GTK_POLICY_ALWAYS,
-								 chanlist_row_selected, (gpointer) serv, 0, 0,
-								 GTK_SELECTION_BROWSE);
-	gtk_clist_set_column_width (GTK_CLIST (serv->gui->chanlist_list), 0, 90);
-	gtk_clist_set_column_width (GTK_CLIST (serv->gui->chanlist_list), 1, 45);
-	gtk_clist_set_column_width (GTK_CLIST (serv->gui->chanlist_list), 2, 165);
-	gtk_clist_column_titles_active (GTK_CLIST (serv->gui->chanlist_list));
-	gtk_signal_connect (GTK_OBJECT (serv->gui->chanlist_list), "click_column",
-							  GTK_SIGNAL_FUNC (chanlist_click_column),
-							  (gpointer) serv);
-	gtk_clist_set_compare_func (GTK_CLIST (serv->gui->chanlist_list),
-										 (GtkCListCompareFunc)
-										 chanlist_compare_text_ignore_case);
-	gtk_clist_set_sort_column (GTK_CLIST (serv->gui->chanlist_list), 0);
-	gtk_clist_set_auto_sort (GTK_CLIST (serv->gui->chanlist_list), 1);
-	/* makes the horiz. scrollbar appear when needed */
-	gtk_clist_set_column_auto_resize (GTK_CLIST (serv->gui->chanlist_list),
-											2, TRUE);
+	serv->gui->chanlist_view = chanlist_treeview_new (vbox, serv);
+	serv->gui->chanlist_itertree = NULL;
+	/* keep a balanced tree: keyed by channel name, data is tree iters */
+	serv->gui->chanlist_itertree = g_tree_new_full ((GCompareDataFunc)chanlist_cmp,
+		NULL, g_free, (GDestroyNotify)gtk_tree_iter_free);
 
 	/* make a label to store the user/channel info */
 	wid = gtk_label_new ("");
@@ -762,3 +857,4 @@
 
 	gtk_widget_show (serv->gui->chanlist_window);
 }
+