Ethereal-dev: [Ethereal-dev] Redesign of expert comp statistics

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: "Greg Morris" <gmorris@xxxxxxxxxx>
Date: Wed, 15 Mar 2006 18:17:14 +0100
Change from using Clist to Tree Views. This change does the following
 
1. Removes need for menu option "Go to first Packet". With the tree view when the composite expert item expanded a complete list of packets are displayed. When the user clicks on one of the expanded packet number items, the Ethereal main summary window will be positioned to the selected packet in the tree list. (similar to expert statistics)
2. Simplifies the code
3. Adds search capabilities to the summary column
4. Adds ability to drag and drop within table
5. Removed copy to CSV option because it uses Clists. Will modify and add back later.
 
Additional things to do...
1. Add another note window with the detailed view, mimic expert statitistics function
2. Add back the copy to CSV using tree view instead of Clists
3. Perform some logic checks to enable/disable menu items depending on whether an expert item is passed in the expert tap
4. Everything else I get comments on...
 
Greg
 
Index: expert_comp_table.h
===================================================================
--- expert_comp_table.h	(revision 17611)
+++ expert_comp_table.h	(working copy)
@@ -36,7 +36,7 @@
 typedef struct _error_procedure_t {
 	char    *entries[4];       /**< column entries */
     char    *fvalue_value;     /**< filter value */
-	guint32 packet_num;        /**< first packet number */
+    GtkTreeIter      iter;
     guint16 count;             /**< number of expert items encountered
                                     for this entry */
 } error_procedure_t;
@@ -44,10 +44,11 @@
 /** Statistics table */
 typedef struct _error_equiv_table {
 	GtkWidget *scrolled_window;         /**< window widget */
-	GtkCList *table;                    /**< table widget */
+    GtkTreeSelection *select;           /**< item selected */
 	GtkWidget *menu;                    /**< context menu */
 	guint16 num_procs;                  /**< number of elements on procedures array */
 	error_procedure_t *procedures;      /**< the procedures array */
+    GtkTreeView       *tree_view;       /**< Tree view */
 }error_equiv_table;
 
 /** Init an err table data structure.
Index: expert_comp_dlg.c
===================================================================
--- expert_comp_dlg.c	(revision 17611)
+++ expert_comp_dlg.c	(working copy)
@@ -122,19 +122,6 @@
     return 1; /* Draw */
 }
 
-
-
-static void
-error_draw(void *pss)
-{
-    expert_comp_dlg_t *ss=(expert_comp_dlg_t *)pss;
-
-    draw_error_table_data(&ss->error_table);
-    draw_error_table_data(&ss->warn_table);
-    draw_error_table_data(&ss->note_table);
-    draw_error_table_data(&ss->chat_table);
-}
-
 void protect_thread_critical_region(void);
 void unprotect_thread_critical_region(void);
 static void
@@ -203,7 +190,7 @@
     init_error_table(&ss->chat_table, 0, temp_page);
 
     /* Register the tap listener */
-    error_string=register_tap_listener("expert", ss, filter, error_reset, error_packet, error_draw);
+    error_string=register_tap_listener("expert", ss, filter, error_reset, error_packet, NULL);
     if(error_string){
         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str);
         g_string_free(error_string, TRUE);
Index: expert_comp_table.c
===================================================================
--- expert_comp_table.c	(revision 17611)
+++ expert_comp_table.c	(working copy)
@@ -37,8 +37,6 @@
 #include "compat_macros.h"
 #include "epan/packet_info.h"
 #include "expert_comp_table.h"
-#include "image/clist_ascend.xpm"
-#include "image/clist_descend.xpm"
 #include "simple_dialog.h"
 #include "globals.h"
 #include "gtk/find_dlg.h"
@@ -53,11 +51,49 @@
 
 #define GTK_MENU_FUNC(a) ((GtkItemFactoryCallback)(a))
 
+#define SORT_ALPHABETICAL 0
+
+static gint
+sort_iter_compare_func (GtkTreeModel *model,
+GtkTreeIter *a,
+GtkTreeIter *b,
+gpointer userdata)
+{
+    gint sortcol = GPOINTER_TO_INT(userdata);
+    gint ret = 0;
+    switch (sortcol)
+    {
+        case SORT_ALPHABETICAL:
+        {
+        gchar *name1, *name2;
+        gtk_tree_model_get(model, a, 0, &name1, -1);
+        gtk_tree_model_get(model, b, 0, &name2, -1);
+        if (name1 == NULL || name2 == NULL)
+        {
+            if (name1 == NULL && name2 == NULL)
+                break; /* both equal => ret = 0 */
+            ret = (name1 == NULL) ? -1 : 1;
+        }
+        else
+        {
+            ret = g_ascii_strcasecmp(name1,name2);
+        }
+        g_free(name1);
+        g_free(name2);
+        }
+        break;
+        default:
+        g_return_val_if_reached(0);
+    }
+    return ret;
+}
+
 /* XXX - move this to a common header file */
 static const value_string expert_group_vals[] = {
 	{ PI_CHECKSUM,		"Checksum" },
 	{ PI_SEQUENCE,		"Sequence" },
 	{ PI_RESPONSE_CODE, "Response" },
+    { PI_REQUEST_CODE,  "Request" },
 	{ PI_UNDECODED,		"Undecoded" },
 	{ PI_MALFORMED,		"Malformed" },
 	{ PI_REASSEMBLE,	"Reassemble" },
@@ -65,114 +101,31 @@
 	{ 0, NULL }
 };
 
-typedef struct column_arrows {
-	GtkWidget *table;
-	GtkWidget *ascend_pm;
-	GtkWidget *descend_pm;
-} column_arrows;
-
-static void
-error_click_column_cb(GtkCList *clist, gint column, gpointer data)
+enum
 {
-	column_arrows *col_arrows = (column_arrows *) data;
-	int i;
+   GROUP_COLUMN,
+   PROTOCOL_COLUMN,
+   SUMMARY_COLUMN,
+   COUNT_COLUMN,
+   N_COLUMNS
+};
 
-	gtk_clist_freeze(clist);
 
-	for (i = 0; i < 4; i++) {
-		gtk_widget_hide(col_arrows[i].ascend_pm);
-		gtk_widget_hide(col_arrows[i].descend_pm);
-	}
-
-	if (column == clist->sort_column) {
-		if (clist->sort_type == GTK_SORT_ASCENDING) {
-			clist->sort_type = GTK_SORT_DESCENDING;
-			gtk_widget_show(col_arrows[column].descend_pm);
-		} else {
-			clist->sort_type = GTK_SORT_ASCENDING;
-			gtk_widget_show(col_arrows[column].ascend_pm);
-		}
-	} else {
-		if(column>=2){
-			clist->sort_type = GTK_SORT_DESCENDING;
-			gtk_widget_show(col_arrows[column].descend_pm);
-		} else {
-			clist->sort_type = GTK_SORT_ASCENDING;
-			gtk_widget_show(col_arrows[column].ascend_pm);
-		}
-		gtk_clist_set_sort_column(clist, column);
-	}
-	gtk_clist_thaw(clist);
-
-	gtk_clist_sort(clist);
-}
-
-static gint
-error_sort_column(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
+static gint find_summary_data(error_equiv_table *err, const expert_info_t *expert_data)
 {
-	char *text1 = NULL;
-	char *text2 = NULL;
-	float f1,f2;
-
-	const GtkCListRow *row1 = ptr1;
-	const GtkCListRow *row2 = ptr2;
-
-	text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text;
-	text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text;
-
-	switch(clist->sort_column){
-	case 0:
-	case 2:
-	case 1:
-		return strcmp (text1, text2);
-	case 3:
-	case 4:
-	case 5:
-		sscanf(text1,"%f",&f1);
-		sscanf(text2,"%f",&f2);
-		if(fabs(f1-f2)<0.000005)
-			return 0;
-		if(f1>f2)
-			return 1;
-		return -1;
-	}
-	g_assert_not_reached();
-	return 0;
-}
-
-
-#if (GTK_MAJOR_VERSION >= 2)
-static void
-copy_as_csv_cb(GtkWindow *win _U_, gpointer data)
-{
-   guint32         i,j;
-   gchar           *table_entry;
-   GtkClipboard    *cb;
-   GString         *CSV_str = g_string_new("");
-
-   error_equiv_table *expert=(error_equiv_table *)data;
-
-   /* Add the column headers to the CSV data */
-   g_string_append(CSV_str,"Summary,Group,Protocol,Count"); /* add the column headings to the CSV string */
-   g_string_append(CSV_str,"\n");                        /* new row */
-
-   /* Add the column values to the CSV data */
-   for(i=0;i<expert->num_procs;i++){                     /* all rows            */
-    for(j=0;j<4;j++){                                    /* all columns         */
-     gtk_clist_get_text(expert->table,i,j,&table_entry); /* copy table item into string */
-     g_string_append(CSV_str,table_entry);               /* add the table entry to the CSV string */
-    if(j!=(4-1))
-     g_string_append(CSV_str,",");
+    gint i;
+    
+    /* First time thru values will be 0 */
+    if (err->num_procs==0) {
+        return -1;
     }
-    g_string_append(CSV_str,"\n");                       /* new row */
-   }
-
-   /* Now that we have the CSV data, copy it into the default clipboard */
-   cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);      /* Get the default clipboard */
-   gtk_clipboard_set_text(cb, CSV_str->str, -1);         /* Copy the CSV data into the clipboard */
-   g_string_free(CSV_str, TRUE);                         /* Free the memory */
+    for (i=0;i<err->num_procs;i++) {
+        if (strcmp(err->procedures[i].entries[2], expert_data->summary) == 0) {
+            return i;
+        }
+    }
+    return -1;
 }
-#endif
 
 /* action is encoded as 
    filter_action*256+filter_type
@@ -200,17 +153,30 @@
 	error_equiv_table *err = (error_equiv_table *)callback_data;
 	char str[256];
 	const char *current_filter;
+    GtkTreeIter iter;
+    GtkTreeModel *model;
+    const expert_info_t expert_data;
 
     action=(callback_action>>8)&0xff;
 	type=callback_action&0xff;
 
-	selection=GPOINTER_TO_INT(g_list_nth_data(GTK_CLIST(err->table)->selection, 0));
+    gtk_tree_selection_get_selected(err->select, &model, &iter);
+
+    gtk_tree_model_get (model, &iter, GROUP_COLUMN, &expert_data.group, -1);
+    gtk_tree_model_get (model, &iter, PROTOCOL_COLUMN, &expert_data.protocol, -1);
+    gtk_tree_model_get (model, &iter, SUMMARY_COLUMN, &expert_data.summary, -1);
+    
+    if (strcmp((char *)expert_data.group, "Packet:")==0) {
+		simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "You cannot filter or search for packet number. Click on a valid item header.");
+        return;
+    }
+
+    selection = find_summary_data(err, &expert_data);
+
 	if(selection>=(int)err->num_procs){
 		simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "No items are selected");
 		return;
 	}
-	/* translate it back from row index to index in procedures array */
-	selection=GPOINTER_TO_INT(gtk_clist_get_row_data(err->table, selection));
 
 	current_filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
 
@@ -336,10 +302,6 @@
 		g_snprintf(str, 255, "http://www.google.com/search?hl=en&q=%s+'%s'", err->procedures[selection].entries[1], err->procedures[selection].entries[2]);
         browser_open_url(str);
 		break;
-    case 7:
-        /* Goto the first occurance (packet) in the trace */
-        cf_goto_frame(&cfile, err->procedures[selection].packet_num);
-        break;
     default:
         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Can't find menu action - %u", action);
 	}
@@ -423,100 +385,132 @@
 	ITEM_FACTORY_ENTRY("/Internet Search for Info Text", NULL,
 		error_select_filter_cb, 6*256+0, NULL, NULL),
 
-	/* Go to first packet matching this entry */
-	ITEM_FACTORY_ENTRY("/Goto First Occurance", NULL,
-		error_select_filter_cb, 7*256+0, NULL, NULL),
 };
 
 static void
+expert_goto_pkt_cb (GtkTreeSelection *selection, gpointer data)
+{
+        GtkTreeIter iter;
+        GtkTreeModel *model;
+        gchar *pkt;
+        gchar *grp;
+        error_equiv_table *err=data;
+
+        if (gtk_tree_selection_get_selected (selection, &model, &iter))
+        {
+                gtk_tree_model_get (model, &iter, PROTOCOL_COLUMN, &pkt, -1);
+                gtk_tree_model_get (model, &iter, GROUP_COLUMN, &grp, -1);
+
+                if (strcmp(grp, "Packet:")==0) {
+                    cf_goto_frame(&cfile, atoi(pkt));
+                }
+                g_free (pkt);
+                g_free (grp);
+        }
+}
+
+
+static void
 error_create_popup_menu(error_equiv_table *err)
 {
 	GtkItemFactory *item_factory;
 
+
+    err->select = gtk_tree_view_get_selection (GTK_TREE_VIEW (err->tree_view));
+    gtk_tree_selection_set_mode (err->select, GTK_SELECTION_SINGLE);
+    g_signal_connect (G_OBJECT (err->select), "changed",
+                  G_CALLBACK (expert_goto_pkt_cb),
+                  err);
+
 	item_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
 
 	gtk_item_factory_create_items_ac(item_factory, sizeof(error_list_menu_items)/sizeof(error_list_menu_items[0]), error_list_menu_items, err, 2);
 
 	err->menu = gtk_item_factory_get_widget(item_factory, "<main>");
-	SIGNAL_CONNECT(err->table, "button_press_event", error_show_popup_menu_cb, err);
+	SIGNAL_CONNECT(err->tree_view, "button_press_event", error_show_popup_menu_cb, err);
 }
 
 void
 init_error_table(error_equiv_table *err, guint16 num_procs, GtkWidget *vbox)
 {
 	guint16 i, j;
-	column_arrows *col_arrows;
-	GdkBitmap *ascend_bm, *descend_bm;
-	GdkPixmap *ascend_pm, *descend_pm;
-	GtkStyle *win_style;
-	GtkWidget *column_lb;
-#if (GTK_MAJOR_VERSION >= 2)
-    GtkWidget *copy_bt;
-#endif
-    GtkTooltips *tooltips = gtk_tooltips_new();
-	const char *default_titles[] = { "Group", "Protocol", "Summary", "Count"};
+    GtkTreeStore *store;
+    GtkWidget *tree;
+    GtkTreeViewColumn *column;
+    GtkCellRenderer *renderer;
+    GtkTreeSortable *sortable;
 
-	err->scrolled_window=scrolled_window_new(NULL, NULL);
-	gtk_box_pack_start(GTK_BOX(vbox), err->scrolled_window, TRUE, TRUE, 0);
+     /* Create the store */
+     store = gtk_tree_store_new (4,       /* Total number of columns */
+                                G_TYPE_STRING,   /* Group              */
+                                G_TYPE_STRING,   /* Protocol           */
+                                G_TYPE_STRING,   /* Summary            */
+                                G_TYPE_STRING); /* Count               */
 
-	err->table=(GtkCList *)gtk_clist_new(4);
 
-	gtk_widget_show(GTK_WIDGET(err->table));
-	gtk_widget_show(err->scrolled_window);
+    /* Create a view */
+    tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+    err->tree_view = GTK_TREE_VIEW(tree);
+    sortable = GTK_TREE_SORTABLE(store);
 
-	col_arrows = (column_arrows *) g_malloc(sizeof(column_arrows) * 4);
-	win_style = gtk_widget_get_style(err->scrolled_window);
-	ascend_pm = gdk_pixmap_create_from_xpm_d(err->scrolled_window->window,
-			&ascend_bm,
-			&win_style->bg[GTK_STATE_NORMAL],
-			(gchar **)clist_ascend_xpm);
-	descend_pm = gdk_pixmap_create_from_xpm_d(err->scrolled_window->window,
-			&descend_bm,
-			&win_style->bg[GTK_STATE_NORMAL],
-			(gchar **)clist_descend_xpm);
-	for (i = 0; i < 4; i++) {
-		col_arrows[i].table = gtk_table_new(2, 2, FALSE);
-		gtk_table_set_col_spacings(GTK_TABLE(col_arrows[i].table), 5);
-		column_lb = gtk_label_new(default_titles[i]);
-		gtk_table_attach(GTK_TABLE(col_arrows[i].table), column_lb, 0, 1, 0, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
-		gtk_widget_show(column_lb);
+    /* Setup the sortable columns */
+    gtk_tree_sortable_set_sort_func(sortable, SORT_ALPHABETICAL, sort_iter_compare_func, GINT_TO_POINTER(SORT_ALPHABETICAL), NULL);
+    gtk_tree_sortable_set_sort_column_id(sortable, SORT_ALPHABETICAL, GTK_SORT_ASCENDING);
+    gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW (tree), FALSE);
 
-		col_arrows[i].ascend_pm = gtk_pixmap_new(ascend_pm, ascend_bm);
-		gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].ascend_pm, 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
-		col_arrows[i].descend_pm = gtk_pixmap_new(descend_pm, descend_bm);
-		gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].descend_pm, 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
-		if (i == 3) {
-			gtk_widget_show(col_arrows[i].descend_pm);
-		}
-		gtk_clist_set_column_widget(GTK_CLIST(err->table), i, col_arrows[i].table);
-		gtk_widget_show(col_arrows[i].table);
-	}
-	gtk_clist_column_titles_show(GTK_CLIST(err->table));
+    /* The view now holds a reference.  We can get rid of our own reference */
+    g_object_unref (G_OBJECT (store));
 
-	gtk_clist_set_compare_func(err->table, error_sort_column);
-	gtk_clist_set_sort_column(err->table, 3);
-	gtk_clist_set_sort_type(err->table, GTK_SORT_DESCENDING);
+    /* Create a cell render */
+    renderer = gtk_cell_renderer_text_new ();
 
+    /* Create the first column, associating the "text" attribute of the
+     * cell_renderer to the first column of the model */
+    column = gtk_tree_view_column_new_with_attributes ("Group", renderer, "text", GROUP_COLUMN, NULL);
+    gtk_tree_view_column_set_sort_column_id(column, 0);
+    gtk_tree_view_column_set_resizable(column, TRUE);
+    /* Add the column to the view. */
+    gtk_tree_view_append_column (GTK_TREE_VIEW (err->tree_view), column);
+ 
+    /* Second column.. Protocol. */
+    renderer = gtk_cell_renderer_text_new ();
+    column = gtk_tree_view_column_new_with_attributes ("Protocol", renderer, "text", PROTOCOL_COLUMN, NULL);
+    gtk_tree_view_column_set_sort_column_id(column, 1);
+    gtk_tree_view_column_set_resizable(column, TRUE);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (err->tree_view), column);
+ 
+    /* Third column.. Summary. */
+    renderer = gtk_cell_renderer_text_new ();
+    column = gtk_tree_view_column_new_with_attributes ("Summary", renderer, "text", SUMMARY_COLUMN, NULL);
+    gtk_tree_view_column_set_sort_column_id(column, 2);
+    gtk_tree_view_column_set_resizable(column, TRUE);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (err->tree_view), column);
+ 
+    /* Last column.. Count. */
+    renderer = gtk_cell_renderer_text_new ();
+    column = gtk_tree_view_column_new_with_attributes ("Count", renderer, "text", COUNT_COLUMN, NULL);
+    gtk_tree_view_column_set_sort_column_id(column, 3);
+    gtk_tree_view_column_set_resizable(column, TRUE);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (err->tree_view), column);
+ 
+ 	err->scrolled_window=scrolled_window_new(NULL, NULL);
 
-	/*XXX instead of this we should probably have some code to
-		dynamically adjust the width of the columns */
-	gtk_clist_set_column_width(err->table, 0, 75);
-	gtk_clist_set_column_width(err->table, 1, 75);
-	gtk_clist_set_column_width(err->table, 2, 400);
-	gtk_clist_set_column_width(err->table, 3, 50);
+    gtk_container_add(GTK_CONTAINER(err->scrolled_window), GTK_WIDGET (err->tree_view));
 
+	gtk_box_pack_start(GTK_BOX(vbox), err->scrolled_window, TRUE, TRUE, 0);
 
-	gtk_clist_set_shadow_type(err->table, GTK_SHADOW_IN);
-	gtk_clist_column_titles_show(err->table);
-	gtk_container_add(GTK_CONTAINER(err->scrolled_window), (GtkWidget *)err->table);
+    gtk_tree_view_set_search_column (err->tree_view, SUMMARY_COLUMN); /* Allow searching the summary */
+    gtk_tree_view_set_reorderable (err->tree_view, TRUE);   /* Allow user to reorder data with drag n drop */
+    
+    /* Now enable the sorting of each column */
+    gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(err->tree_view), TRUE);
+    gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(err->tree_view), TRUE);
 
-	SIGNAL_CONNECT(err->table, "click-column", error_click_column_cb, col_arrows);
+	gtk_container_add(GTK_CONTAINER(err->scrolled_window), GTK_WIDGET (err->tree_view));
 
-	gtk_widget_show(GTK_WIDGET(err->table));
 	gtk_widget_show(err->scrolled_window);
 
-
-	err->num_procs=num_procs;
+    err->num_procs=num_procs;
 	err->procedures=g_malloc(sizeof(error_procedure_t)*(num_procs+1));
 	for(i=0;i<num_procs;i++){
 		for(j=0;j<3;j++){
@@ -524,73 +518,72 @@
 		}
 	}
 
-#if (GTK_MAJOR_VERSION >= 2)
-    /* XXX - maybe we want to have a "Copy as CSV" stock button here? */
-    /*copy_bt = gtk_button_new_with_label ("Copy content to clipboard as CSV");*/
-    copy_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_COPY);
-    gtk_tooltips_set_tip(tooltips, copy_bt,
-        "Copy all expert information to the clipboard in CSV (Comma Seperated Values) format.", NULL);
-    SIGNAL_CONNECT(copy_bt, "clicked", copy_as_csv_cb,(gpointer *) err);
-    gtk_box_pack_start(GTK_BOX(vbox), copy_bt, FALSE, FALSE, 0);
-#endif
-
 	/* create popup menu for this table */
   	error_create_popup_menu(err);
 }
 
-static gint find_summary_data(error_equiv_table *err, const expert_info_t *expert_data)
-{
-    gint i;
-    
-    /* First time thru values will be 0 */
-    if (err->num_procs==0 || err->procedures[0].entries[2]==0) {
-        return -1;
-    }
-    for (i=0;i<err->num_procs;i++) {
-        if (strcmp(err->procedures[i].entries[2], expert_data->summary) == 0) {
-            return i;
-        }
-    }
-    return -1;
-}
-
 void
 init_error_table_row(error_equiv_table *err, const expert_info_t *expert_data)
 {
     guint16 old_num_procs=err->num_procs;
     guint16 j;
     gint row=0;
+    GtkTreeStore *store;
 
 	/* we have discovered a new procedure. Extend the table accordingly */
     row = find_summary_data(err, expert_data);
 	if(row==-1){
-        row = 0;
-        old_num_procs++;
+        /* First time we have seen this event so initialize memory table */
+        row = old_num_procs; /* Number of expert events since this is a new event */
 		err->procedures=g_realloc(err->procedures, (sizeof(error_procedure_t)*(old_num_procs+1)));
-        err->procedures[err->num_procs].count=0;
-		for(j=0;j<4;j++){
-			err->procedures[err->num_procs].entries[j]=NULL;
+        err->procedures[row].count=0; /* count of events for this item */
+        err->procedures[row].fvalue_value = NULL; /* Filter string value */
+        for(j=0;j<4;j++){
+			err->procedures[row].entries[j]=NULL;
 		}
-        err->procedures[err->num_procs].packet_num = (guint32)expert_data->packet_num;                        /* First packet num */
+
+        /* Create the item in our memory table */
+        err->procedures[row].entries[0]=(char *)g_strdup_printf("%s", val_to_str(expert_data->group, expert_group_vals,"Unknown group (%u)"), NULL);  /* Group */
+        err->procedures[row].entries[1]=(char *)g_strdup_printf("%s", expert_data->protocol, NULL);    /* Protocol */
+        err->procedures[row].entries[2]=(char *)g_strdup_printf("%s", expert_data->summary, NULL);     /* Summary */
+
+        /* Create a new item in our tree view */
+        store = GTK_TREE_STORE(gtk_tree_view_get_model(err->tree_view)); /* Get store */
+        gtk_tree_store_append (store, &err->procedures[row].iter, NULL);  /* Acquire an iterator */
+
+        gtk_tree_store_set (store, &err->procedures[row].iter,
+                GROUP_COLUMN, (char *)g_strdup_printf("%s", val_to_str(expert_data->group, expert_group_vals,"Unknown group (%u)"), NULL),
+                PROTOCOL_COLUMN, (char *)g_strdup_printf("%s", expert_data->protocol, NULL),
+                SUMMARY_COLUMN, (char *)g_strdup_printf("%s", expert_data->summary, NULL), -1);
+
+        /* If an expert item was passed then build the filter string */
+        if (expert_data->pitem && strcmp(expert_data->pitem->finfo->value.ftype->name,"FT_NONE")!=0) {
+            err->procedures[row].fvalue_value = g_strdup_printf("%s", proto_construct_dfilter_string(expert_data->pitem->finfo, NULL));
+        }
+        /* Store the updated count of events */
+        err->num_procs = ++old_num_procs;
 	}
-	err->procedures[err->num_procs].entries[0]=(char *)g_strdup_printf("%s", val_to_str(expert_data->group, expert_group_vals,"Unknown group (%u)"), NULL);   /* Group */
-    err->procedures[err->num_procs].entries[1]=(char *)g_strdup_printf("%s", expert_data->protocol, NULL);    /* Protocol */
-    err->procedures[err->num_procs].entries[2]=(char *)g_strdup_printf("%s", expert_data->summary, NULL);     /* Summary */
-	err->procedures[err->num_procs].entries[3]=(char *)g_strdup_printf("%d", err->procedures[row].count);     /* Count */
-    err->procedures[err->num_procs].fvalue_value = NULL;
-    if (expert_data->pitem && strcmp(expert_data->pitem->finfo->value.ftype->name,"FT_NONE")!=0) {
-        err->procedures[err->num_procs].fvalue_value = g_strdup_printf("%s", proto_construct_dfilter_string(expert_data->pitem->finfo, NULL));
-    }
-    err->num_procs = old_num_procs;                                                           
+
+    /* Update our memory table with event data */
+    err->procedures[row].count++; /* increment the count of events for this item */
+
+    /* Store the updated count for this event item */
+	err->procedures[row].entries[3]=(char *)g_strdup_printf("%d", err->procedures[row].count);     /* Count */
+
+    /* Update the tree with new count for this event */
+    store = GTK_TREE_STORE(gtk_tree_view_get_model(err->tree_view));
+    gtk_tree_store_set(store, &err->procedures[row].iter, COUNT_COLUMN, (char *)g_strdup_printf("%d", err->procedures[row].count), -1);
 }
 
 void
 add_error_table_data(error_equiv_table *err, const expert_info_t *expert_data)
 {
 	error_procedure_t *errp;
-	gint row;
     gint index;
 
+    GtkTreeStore    *store;
+    GtkTreeIter      new_iter;
+
     index = find_summary_data(err,expert_data);
 
     /* We should never encounter a condition where we cannot find the expert data. If
@@ -602,60 +595,31 @@
     }
 	errp=&err->procedures[index];
 
-	/*
-	 * If the count of calls for this procedure is currently zero, it's
-	 * going to become non-zero, so add a row for it (we don't want
-	 * rows for procedures that have no calls - especially if the
-	 * procedure has no calls because the index doesn't correspond
-	 * to a procedure, but is an unused/reserved value).
-	 *
-	 * (Yes, this means that the rows aren't in order by anything
-	 * interesting.  That's why we have the table sorted by a column.)
-	 */
-	if (errp->count==0){
-		row=gtk_clist_append(err->table, err->procedures[index].entries);
-		gtk_clist_set_row_data(err->table, row, (gpointer) index);
-	}
-    errp->count++;
-    err->procedures[index].entries[3] = (char *)g_strdup_printf("%d", errp->count);
-}
+    store = GTK_TREE_STORE(gtk_tree_view_get_model(err->tree_view));
 
-void
-draw_error_table_data(error_equiv_table *err)
-{
-	int i,j;
-	char *strp;
+    gtk_tree_store_append(store, &new_iter, &errp->iter);
 
-	for(i=0;i<err->num_procs;i++){
-		/* ignore procedures with no calls (they don't have CList rows) */
-		if(err->procedures[i].count==0){
-			continue;
-		}
-
-		j=gtk_clist_find_row_from_data(err->table, (gpointer)i);
-		strp=g_strdup_printf("%d", err->procedures[i].count);
-		gtk_clist_set_text(err->table, j, 3, strp);
-		err->procedures[i].entries[3]=(char *)strp;
-
-
-	}
-	gtk_clist_sort(err->table);
+    gtk_tree_store_set(store, &new_iter,
+                           GROUP_COLUMN, "Packet:",
+                           PROTOCOL_COLUMN, (char *)g_strdup_printf("%d", expert_data->packet_num),
+                           -1);
 }
 
-
 void
 reset_error_table_data(error_equiv_table *err)
 {
 	guint16 i;
+    GtkTreeStore    *store;
 
 	for(i=0;i<err->num_procs;i++){
 		err->procedures[i].entries[0] = NULL;
 		err->procedures[i].entries[1] = NULL;
 		err->procedures[i].entries[2] = NULL;
 		err->procedures[i].entries[3] = NULL;
-        err->procedures[i].packet_num=0;
+        err->procedures[i].count=0;
 	}
-	gtk_clist_clear(err->table);
+    store = GTK_TREE_STORE(gtk_tree_view_get_model(err->tree_view));
+    gtk_tree_store_clear(store);
     err->num_procs = 0;
 }
 
@@ -670,7 +634,7 @@
 				err->procedures[i].entries[j]=NULL;
 			}
             err->procedures[i].fvalue_value=NULL;
-            err->procedures[i].packet_num=0;
+            err->procedures[i].count=0;
 		}
 	}
 	err->procedures=NULL;