sort #includes by directories
[obnox/wireshark/wip.git] / gtk / expert_comp_table.c
1 /* expert_comp_table.c
2  * expert_comp_table   2005 Greg Morris
3  * Portions copied from service_response_time_table.c by Ronnie Sahlberg
4  * Helper routines common to all composite expert statistics
5  * tap.
6  *
7  * $Id$
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <string.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <math.h>
36
37 #include <gtk/gtk.h>
38
39 #include "epan/packet_info.h"
40 #include <epan/expert.h>
41 #include <epan/emem.h>
42
43 #include "../simple_dialog.h"
44 #include "../globals.h"
45 #include "../color.h"
46
47 #include "gtk/expert_comp_table.h"
48 #include "gtk/find_dlg.h"
49 #include "gtk/color_dlg.h"
50 #include "gtk/main.h"
51 #include "gtk/gui_utils.h"
52 #include "gtk/gtkglobals.h"
53 #include "gtk/webbrowser.h"
54
55
56 #define GTK_MENU_FUNC(a) ((GtkItemFactoryCallback)(a))
57
58 #define SORT_ALPHABETICAL 0
59
60 static gint
61 sort_iter_compare_func (GtkTreeModel *model,
62 GtkTreeIter *a,
63 GtkTreeIter *b,
64 gpointer userdata)
65 {
66     gint sortcol = GPOINTER_TO_INT(userdata);
67     gint ret = 0;
68     switch (sortcol)
69     {
70         case SORT_ALPHABETICAL:
71         {
72             gchar *name1, *name2;
73             gtk_tree_model_get(model, a, 0, &name1, -1);
74             gtk_tree_model_get(model, b, 0, &name2, -1);
75             if (name1 == NULL || name2 == NULL)
76             {
77                 if (name1 == NULL && name2 == NULL)
78                     break; /* both equal => ret = 0 */
79                 ret = (name1 == NULL) ? -1 : 1;
80             }
81             else
82             {
83                 ret = g_ascii_strcasecmp(name1,name2);
84             }
85             g_free(name1);
86             g_free(name2);
87             }
88             break;
89         default:
90             g_return_val_if_reached(0);
91     }
92     return ret;
93 }
94
95 enum
96 {
97    GROUP_COLUMN,
98    PROTOCOL_COLUMN,
99    SUMMARY_COLUMN,
100    COUNT_COLUMN,
101    N_COLUMNS
102 };
103
104 static gint find_summary_data(error_equiv_table *err, const expert_info_t *expert_data)
105 {
106     gint i;
107     
108     /* First time thru values will be 0 */
109     if (err->num_procs==0) {
110         return -1;
111     }
112     for (i=0;i<err->num_procs;i++) {
113         if (strcmp(err->procedures[i].entries[1], expert_data->protocol) == 0 &&
114             strcmp(err->procedures[i].entries[2], expert_data->summary) == 0) {
115             return i;
116         }
117     }
118     return -1;
119 }
120
121 /* Filter actions */
122 #define ACTION_MATCH            0
123 #define ACTION_PREPARE          1
124 #define ACTION_FIND_FRAME       2
125 #define ACTION_FIND_NEXT        3
126 #define ACTION_FIND_PREVIOUS    4
127 #define ACTION_COLORIZE         5
128 #define ACTION_WEB_LOOKUP       6
129
130 /* Action type - says what to do with the filter */
131 #define ACTYPE_SELECTED         0
132 #define ACTYPE_NOT_SELECTED     1
133 #define ACTYPE_AND_SELECTED     2
134 #define ACTYPE_OR_SELECTED      3
135 #define ACTYPE_AND_NOT_SELECTED 4
136 #define ACTYPE_OR_NOT_SELECTED  5
137
138 /* Encoded callback arguments */
139 #define CALLBACK_MATCH(type)            ((ACTION_MATCH<<8) | (type))
140 #define CALLBACK_PREPARE(type)          ((ACTION_PREPARE<<8) | (type))
141 #define CALLBACK_FIND_FRAME(type)       ((ACTION_FIND_FRAME<<8) | (type))
142 #define CALLBACK_FIND_NEXT(type)        ((ACTION_FIND_NEXT<<8) | (type))
143 #define CALLBACK_FIND_PREVIOUS(type)    ((ACTION_FIND_PREVIOUS<<8) | (type))
144 #define CALLBACK_COLORIZE(type)         ((ACTION_COLORIZE<<8) | (type))
145 #define CALLBACK_WEB_LOOKUP             (ACTION_WEB_LOOKUP<<8)
146
147 /* Extract components of callback argument */
148 #define FILTER_ACTION(cb_arg)           (((cb_arg)>>8) & 0xff)
149 #define FILTER_ACTYPE(cb_arg)           ((cb_arg) & 0xff)
150
151 static void
152 error_select_filter_cb(GtkWidget *widget _U_, gpointer callback_data, guint callback_action)
153 {
154     int action, type, selection;
155     error_equiv_table *err = (error_equiv_table *)callback_data;
156     char str[256];
157     const char *current_filter;
158
159     GtkTreeIter iter;
160     GtkTreeModel *model;
161     const expert_info_t expert_data;
162
163     action=FILTER_ACTION(callback_action);
164     type=FILTER_ACTYPE(callback_action);
165
166
167     gtk_tree_selection_get_selected(err->select, &model, &iter);
168
169     gtk_tree_model_get (model, &iter, GROUP_COLUMN, &expert_data.group, -1);
170     gtk_tree_model_get (model, &iter, PROTOCOL_COLUMN, &expert_data.protocol, -1);
171     gtk_tree_model_get (model, &iter, SUMMARY_COLUMN, &expert_data.summary, -1);
172     
173     if (strcmp((char *)(unsigned long)expert_data.group, "Packet:")==0) {
174         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "You cannot filter or search for packet number. Click on a valid item header.");
175         return;
176     }
177
178     selection = find_summary_data(err, &expert_data);
179
180     if(selection>=(int)err->num_procs){
181         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "No items are selected");
182         return;
183     }
184     current_filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
185
186     /* Some expert data doesn't pass an expert item. Without this we cannot create a filter */
187     /* But allow for searching of internet for error string */
188     if (action != 6 && action != 7) {
189         if (err->procedures[selection].fvalue_value==NULL) {
190             if (action != 2 && action != 3 && action != 4) {
191                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Wireshark cannot create a filter on this item - %s, try using find instead.", err->procedures[selection].entries[2]);
192                 return;
193             }
194         }
195         switch(type){
196         case ACTYPE_SELECTED:
197             /* if no expert item was passed */
198             if (err->procedures[selection].fvalue_value==NULL) {
199                 g_snprintf(str, 255, "%s", err->procedures[selection].entries[2]);
200             }
201             else
202             {
203                 /* expert item exists. Use it. */
204                 g_snprintf(str, 255, "%s", err->procedures[selection].fvalue_value);
205             }
206             break;
207         case ACTYPE_NOT_SELECTED:
208             /* if no expert item was passed */
209             if (err->procedures[selection].fvalue_value==NULL) {
210                 g_snprintf(str, 255, "!%s", err->procedures[selection].entries[2]);
211             }
212             else
213             {
214                 /* expert item exists. Use it. */
215                 g_snprintf(str, 255, "!(%s)", err->procedures[selection].fvalue_value);
216             }
217             break;
218             /* the remaining cases will only exist if the expert item exists so no need to check */
219         case ACTYPE_AND_SELECTED:
220             g_snprintf(str, 255, "(%s) && (%s)", current_filter, err->procedures[selection].fvalue_value);
221             break;
222         case ACTYPE_OR_SELECTED:
223             g_snprintf(str, 255, "(%s) || (%s)", current_filter, err->procedures[selection].fvalue_value);
224             break;
225         case ACTYPE_AND_NOT_SELECTED:
226             g_snprintf(str, 255, "(%s) && !(%s)", current_filter, err->procedures[selection].fvalue_value);
227             break;
228         case ACTYPE_OR_NOT_SELECTED:
229             g_snprintf(str, 255, "(%s) || !(%s)", current_filter, err->procedures[selection].fvalue_value);
230             break;
231         default:
232             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Can't find menu type - %u", type);
233         }
234     }
235
236     switch(action){
237     case ACTION_MATCH:
238         main_filter_packets(&cfile, str, FALSE);
239         break;
240     case ACTION_PREPARE:
241         gtk_entry_set_text(GTK_ENTRY(main_display_filter_widget), str);
242         break;
243     case ACTION_FIND_FRAME:
244         /* When trying to perform a find without expert item, we must pass
245          * the expert string to the find window. The user might need to modify
246          * the string and click on the text search to locate the packet in question.
247          * So regardless of the type we will just bring up the find window and allow
248          * the user to modify the search criteria and options.
249          */
250         find_frame_with_filter(str);
251         break;
252     case ACTION_FIND_NEXT:
253         /* In the case of find next, if there was no expert item, then most likely the expert
254          * string was modified to locate the text inside the message. So we can't just perform
255          * a find with the expert string or we will not really be performing a find next.
256          * In an effort to allow the user to modify the string and/or continue searching, we
257          * will just present the user with the find window again with the default expert string.
258          * A better aproach would be to attempt in capturing the last find string and utilize this 
259          * with a find next/previous. Also a better approach might be to just send a <Ctl-N> keystroke.
260          */
261         if (err->procedures[selection].fvalue_value==NULL) {
262             find_frame_with_filter(str);
263         }
264         else
265         { 
266             /* We have an expert item so just continue search without find dialog. */
267             find_previous_next_frame_with_filter(str, FALSE);
268         }
269         break;
270     case ACTION_FIND_PREVIOUS:
271         /* In the case of find previous, if there was no expert item, then most likely the expert
272          * string was modified to locate the text inside the message. So we can't just perform
273          * a find with the expert string or we will not really be performing a find previous.
274          * In an effort to allow the user to modify the string and/or continue searching, we
275          * will just present the user with the find window again with the default expert string.
276          * A better aproach would be to attempt in capturing the last find string and utilize this 
277          * with a find next/previous. Also a better approach might be to just send a <Ctl-B> keystroke.
278          */
279         if (err->procedures[selection].fvalue_value==NULL) {
280             find_frame_with_filter(str);
281         }
282         else
283         { 
284             /* We have an expert item so just continue search without find dialog. */
285             find_previous_next_frame_with_filter(str, TRUE);
286         }
287         break;
288     case ACTION_COLORIZE:
289         color_display_with_filter(str);
290         break;
291     case ACTION_WEB_LOOKUP:
292         /* Lookup expert string on internet. Default search via www.google.com */
293         g_snprintf(str, 255, "http://www.google.com/search?hl=en&q=%s+'%s'", err->procedures[selection].entries[1], err->procedures[selection].entries[2]);
294         browser_open_url(str);
295         break;
296     default:
297         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Can't find menu action - %u", action);
298     }
299 }
300
301 static gint
302 error_show_popup_menu_cb(void *widg _U_, GdkEvent *event, error_equiv_table *err)
303 {
304         GdkEventButton *bevent = (GdkEventButton *)event;
305
306         if(event->type==GDK_BUTTON_PRESS && bevent->button==3){
307                 gtk_menu_popup(GTK_MENU(err->menu), NULL, NULL, NULL, NULL, 
308                         bevent->button, bevent->time);
309         }
310
311         return FALSE;
312 }
313
314 static GtkItemFactoryEntry error_list_menu_items[] =
315 {
316         /* Match */
317         {"/Apply as Filter", NULL, NULL, 0, "<Branch>", NULL,},
318         {"/Apply as Filter/Selected", NULL,
319                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_MATCH(ACTYPE_SELECTED),
320                 NULL, NULL,},
321         {"/Apply as Filter/... not Selected", NULL,
322                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_MATCH(ACTYPE_NOT_SELECTED),
323                 NULL, NULL,},
324         {"/Apply as Filter/.. and Selected", NULL,
325                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_MATCH(ACTYPE_AND_SELECTED),
326                 NULL, NULL,},
327         {"/Apply as Filter/... or Selected", NULL,
328                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_MATCH(ACTYPE_OR_SELECTED),
329                 NULL, NULL,},
330         {"/Apply as Filter/... and not Selected", NULL,
331                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_MATCH(ACTYPE_AND_NOT_SELECTED),
332                 NULL, NULL,},
333         {"/Apply as Filter/... or not Selected", NULL,
334                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_MATCH(ACTYPE_OR_NOT_SELECTED),
335                 NULL, NULL,},
336
337         /* Prepare */
338         {"/Prepare a Filter", NULL, NULL, 0, "<Branch>", NULL,},
339         {"/Prepare a Filter/Selected", NULL,
340                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_PREPARE(ACTYPE_SELECTED),
341                 NULL, NULL,},
342         {"/Prepare a Filter/Not Selected", NULL,
343                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_PREPARE(ACTYPE_NOT_SELECTED),
344                 NULL, NULL,},
345         {"/Prepare a Filter/... and Selected", NULL,
346                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_PREPARE(ACTYPE_AND_SELECTED),
347                 NULL, NULL,},
348         {"/Prepare a Filter/... or Selected", NULL,
349                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_PREPARE(ACTYPE_OR_SELECTED),
350                 NULL, NULL,},
351         {"/Prepare a Filter/... and not Selected", NULL,
352                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_PREPARE(ACTYPE_AND_NOT_SELECTED),
353                 NULL, NULL,},
354         {"/Prepare a Filter/... or not Selected", NULL,
355                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_PREPARE(ACTYPE_OR_NOT_SELECTED),
356                 NULL, NULL,},
357
358         /* Find Frame */
359         {"/Find Frame", NULL, NULL, 0, "<Branch>", NULL,},
360         {"/Find Frame/Find Frame", NULL, NULL, 0, "<Branch>", NULL,},
361         {"/Find Frame/Find Frame/Selected", NULL,
362                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_FIND_FRAME(ACTYPE_SELECTED),
363                 NULL, NULL,},
364         {"/Find Frame/Find Frame/Not Selected", NULL,
365                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_FIND_FRAME(ACTYPE_NOT_SELECTED),
366                 NULL, NULL,},
367         /* Find Next */
368         {"/Find Frame/Find Next", NULL, NULL, 0, "<Branch>", NULL,},
369         {"/Find Frame/Find Next/Selected", NULL,
370                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_FIND_NEXT(ACTYPE_SELECTED),
371                 NULL, NULL,},
372         {"/Find Frame/Find Next/Not Selected", NULL,
373                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_FIND_NEXT(ACTYPE_NOT_SELECTED),
374                 NULL, NULL,},
375
376         /* Find Previous */
377         {"/Find Frame/Find Previous", NULL, NULL, 0, "<Branch>", NULL,},
378         {"/Find Frame/Find Previous/Selected", NULL,
379                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_FIND_PREVIOUS(ACTYPE_SELECTED),
380                 NULL, NULL,},
381         {"/Find Frame/Find Previous/Not Selected", NULL,
382                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_FIND_PREVIOUS(ACTYPE_NOT_SELECTED),
383                 NULL, NULL,},
384
385         /* Colorize Procedure */
386         {"/Colorize Procedure", NULL, NULL, 0, "<Branch>", NULL,},
387         {"/Colorize Procedure/Selected", NULL,
388                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_COLORIZE(ACTYPE_SELECTED),
389                 NULL, NULL,},
390         {"/Colorize Procedure/Not Selected", NULL,
391                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_COLORIZE(ACTYPE_NOT_SELECTED),
392                 NULL, NULL,},
393
394         /* Search Internet */
395         {"/Internet Search for Info Text", NULL,
396                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_WEB_LOOKUP, NULL, NULL,}
397 };
398
399 static void
400 expert_goto_pkt_cb (GtkTreeSelection *selection, gpointer data _U_)
401 {
402         GtkTreeIter iter;
403         GtkTreeModel *model;
404         gchar *pkt;
405         gchar *grp;
406
407         if (gtk_tree_selection_get_selected (selection, &model, &iter))
408         {
409                 gtk_tree_model_get (model, &iter, PROTOCOL_COLUMN, &pkt, -1);
410                 gtk_tree_model_get (model, &iter, GROUP_COLUMN, &grp, -1);
411
412                 if (strcmp(grp, "Packet:")==0) {
413                     cf_goto_frame(&cfile, atoi(pkt));
414                 }
415                 g_free (pkt);
416                 g_free (grp);
417         }
418 }
419
420 static void
421 error_create_popup_menu(error_equiv_table *err)
422 {
423     GtkItemFactory *item_factory;
424
425
426     err->select = gtk_tree_view_get_selection (GTK_TREE_VIEW (err->tree_view));
427     gtk_tree_selection_set_mode (err->select, GTK_SELECTION_SINGLE);
428     g_signal_connect (G_OBJECT (err->select), "changed",
429                   G_CALLBACK (expert_goto_pkt_cb),
430                   err);
431     item_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
432
433     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);
434
435     err->menu = gtk_item_factory_get_widget(item_factory, "<main>");
436     g_signal_connect(err->tree_view, "button_press_event", G_CALLBACK(error_show_popup_menu_cb), err);
437 }
438
439 void
440 init_error_table(error_equiv_table *err, guint16 num_procs, GtkWidget *vbox)
441 {
442     guint16 i, j;
443     GtkTreeStore *store;
444     GtkWidget *tree;
445     GtkTreeViewColumn *column;
446     GtkCellRenderer *renderer;
447     GtkTreeSortable *sortable;
448
449     /* Create the store */
450     store = gtk_tree_store_new (4,       /* Total number of columns */
451                                G_TYPE_STRING,   /* Group              */
452                                G_TYPE_STRING,   /* Protocol           */
453                                G_TYPE_STRING,   /* Summary            */
454                                G_TYPE_INT);     /* Count              */
455
456     /* Create a view */
457     tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
458     err->tree_view = GTK_TREE_VIEW(tree);
459     sortable = GTK_TREE_SORTABLE(store);
460
461     /* Setup the sortable columns */
462     gtk_tree_sortable_set_sort_func(sortable, SORT_ALPHABETICAL, sort_iter_compare_func, GINT_TO_POINTER(SORT_ALPHABETICAL), NULL);
463     gtk_tree_sortable_set_sort_column_id(sortable, SORT_ALPHABETICAL, GTK_SORT_ASCENDING);
464     gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW (tree), FALSE);
465
466     /* The view now holds a reference.  We can get rid of our own reference */
467     g_object_unref (G_OBJECT (store));
468
469     /* Create a cell render */
470     renderer = gtk_cell_renderer_text_new ();
471
472     /* Create the first column, associating the "text" attribute of the
473      * cell_renderer to the first column of the model */
474     column = gtk_tree_view_column_new_with_attributes ("Group", renderer, "text", GROUP_COLUMN, NULL);
475     gtk_tree_view_column_set_sort_column_id(column, 0);
476     gtk_tree_view_column_set_resizable(column, TRUE);
477     /* Add the column to the view. */
478     gtk_tree_view_append_column (GTK_TREE_VIEW (err->tree_view), column);
479  
480     /* Second column.. Protocol. */
481     renderer = gtk_cell_renderer_text_new ();
482     column = gtk_tree_view_column_new_with_attributes ("Protocol", renderer, "text", PROTOCOL_COLUMN, NULL);
483     gtk_tree_view_column_set_sort_column_id(column, 1);
484     gtk_tree_view_column_set_resizable(column, TRUE);
485     gtk_tree_view_append_column (GTK_TREE_VIEW (err->tree_view), column);
486  
487     /* Third column.. Summary. */
488     renderer = gtk_cell_renderer_text_new ();
489     column = gtk_tree_view_column_new_with_attributes ("Summary", renderer, "text", SUMMARY_COLUMN, NULL);
490     gtk_tree_view_column_set_sort_column_id(column, 2);
491     gtk_tree_view_column_set_resizable(column, TRUE);
492     gtk_tree_view_append_column (GTK_TREE_VIEW (err->tree_view), column);
493  
494     /* Last column.. Count. */
495     column = gtk_tree_view_column_new_with_attributes ("Count", renderer, "text", COUNT_COLUMN, NULL);
496     gtk_tree_view_column_set_sort_column_id(column, 3);
497     gtk_tree_view_column_set_resizable(column, TRUE);
498     gtk_tree_view_append_column (GTK_TREE_VIEW (err->tree_view), column);
499  
500     err->scrolled_window=scrolled_window_new(NULL, NULL);
501
502     gtk_container_add(GTK_CONTAINER(err->scrolled_window), GTK_WIDGET (err->tree_view));
503
504     gtk_box_pack_start(GTK_BOX(vbox), err->scrolled_window, TRUE, TRUE, 0);
505
506     gtk_tree_view_set_search_column (err->tree_view, SUMMARY_COLUMN); /* Allow searching the summary */
507     gtk_tree_view_set_reorderable (err->tree_view, TRUE);   /* Allow user to reorder data with drag n drop */
508     
509     /* Now enable the sorting of each column */
510     gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(err->tree_view), TRUE);
511     gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(err->tree_view), TRUE);
512
513     gtk_widget_show(err->scrolled_window);
514
515     err->num_procs=num_procs;
516     err->procedures=g_malloc(sizeof(error_procedure_t)*(num_procs+1));
517     for(i=0;i<num_procs;i++){
518         for(j=0;j<3;j++){
519             err->procedures[i].entries[j]=NULL; /* reset all values */
520         }
521     }
522
523     /* create popup menu for this table */
524     error_create_popup_menu(err);
525 }
526
527 void
528 init_error_table_row(error_equiv_table *err, const expert_info_t *expert_data)
529 {
530     guint16 old_num_procs=err->num_procs;
531     guint16 j;
532     gint row=0;
533
534     GtkTreeStore *store;
535
536     /* we have discovered a new procedure. Extend the table accordingly */
537     row = find_summary_data(err, expert_data);
538     if(row==-1){
539         /* First time we have seen this event so initialize memory table */
540         row = old_num_procs; /* Number of expert events since this is a new event */
541         err->procedures=g_realloc(err->procedures, (sizeof(error_procedure_t)*(old_num_procs+1)));
542         err->procedures[row].count=0; /* count of events for this item */
543         err->procedures[row].fvalue_value = NULL; /* Filter string value */
544         for(j=0;j<4;j++){
545             err->procedures[row].entries[j]=NULL;
546         }
547         
548         /* Create the item in our memory table */
549         err->procedures[row].entries[0]=(char *)g_strdup(val_to_str(expert_data->group, expert_group_vals,"Unknown group (%u)"));  /* Group */
550         err->procedures[row].entries[1]=(char *)g_strdup(expert_data->protocol);    /* Protocol */
551         err->procedures[row].entries[2]=(char *)g_strdup(expert_data->summary);     /* Summary */
552
553         /* Create a new item in our tree view */
554         store = GTK_TREE_STORE(gtk_tree_view_get_model(err->tree_view)); /* Get store */
555         gtk_tree_store_append (store, &err->procedures[row].iter, NULL);  /* Acquire an iterator */
556         
557         gtk_tree_store_set (store, &err->procedures[row].iter,
558                     GROUP_COLUMN, (char *)g_strdup(val_to_str(expert_data->group, expert_group_vals,"Unknown group (%u)")),
559                     PROTOCOL_COLUMN, (char *)g_strdup(expert_data->protocol),
560                     SUMMARY_COLUMN, (char *)g_strdup(expert_data->summary), -1);
561
562         /* If an expert item was passed then build the filter string */
563         if (expert_data->pitem) {
564             char *filter;
565
566             filter = proto_construct_match_selected_string(expert_data->pitem->finfo, NULL);
567             if (filter != NULL)
568                 err->procedures[row].fvalue_value = g_strdup(filter);
569         }
570         /* Store the updated count of events */
571         err->num_procs = ++old_num_procs;
572     }
573
574     /* Update our memory table with event data */
575     err->procedures[row].count++; /* increment the count of events for this item */
576
577     /* Store the updated count for this event item */
578     err->procedures[row].entries[3]=(char *)g_strdup_printf("%d", err->procedures[row].count);     /* Count */
579
580     /* Update the tree with new count for this event */
581     store = GTK_TREE_STORE(gtk_tree_view_get_model(err->tree_view));
582     gtk_tree_store_set(store, &err->procedures[row].iter, COUNT_COLUMN, err->procedures[row].count, -1);
583 }
584
585 void
586 add_error_table_data(error_equiv_table *err, const expert_info_t *expert_data)
587 {
588     error_procedure_t *errp;
589     gint index;
590     GtkTreeStore    *store;
591     GtkTreeIter      new_iter;
592
593     index = find_summary_data(err,expert_data);
594
595     /* We should never encounter a condition where we cannot find the expert data. If
596      * we do then we will just abort.
597      */
598     if (index == -1) {
599         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not find expert data. Aborting");
600         return;
601     }
602     errp=&err->procedures[index];
603
604     store = GTK_TREE_STORE(gtk_tree_view_get_model(err->tree_view));
605
606     gtk_tree_store_append(store, &new_iter, &errp->iter);
607
608     gtk_tree_store_set(store, &new_iter,
609                            GROUP_COLUMN, "Packet:",
610                            PROTOCOL_COLUMN, (char *)g_strdup_printf("%d", expert_data->packet_num),
611                            -1);
612 }
613
614 void
615 reset_error_table_data(error_equiv_table *err)
616 {
617     guint16 i;
618     GtkTreeStore    *store;
619
620     for(i=0;i<err->num_procs;i++){
621         err->procedures[i].entries[0] = NULL;
622         err->procedures[i].entries[1] = NULL;
623         err->procedures[i].entries[2] = NULL;
624         err->procedures[i].entries[3] = NULL;
625         err->procedures[i].count=0;
626     }
627
628     store = GTK_TREE_STORE(gtk_tree_view_get_model(err->tree_view));
629     gtk_tree_store_clear(store);
630     err->num_procs = 0;
631 }
632
633 void
634 free_error_table_data(error_equiv_table *err)
635 {
636     guint16 i,j;
637
638     for(i=0;i<err->num_procs;i++){
639         for(j=0;j<4;j++){
640             if(err->procedures[i].entries[j]){
641                 err->procedures[i].entries[j]=NULL;
642             }
643             err->procedures[i].fvalue_value=NULL;
644             err->procedures[i].count=0;
645         }
646     }
647     err->procedures=NULL;
648     err->num_procs=0;
649 }