2 * Routines to implement a new GTK2 packet list using our custom model
3 * Copyright 2008-2009, Stephen Fisher (see AUTHORS file)
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
31 #ifdef NEW_PACKET_LIST
40 #include "gui_utils.h"
41 #include "packet_list_store.h"
42 #include "epan/column_info.h"
43 #include "epan/prefs.h"
44 #include <epan/packet.h>
45 #include "../ui_util.h"
46 #include "../simple_dialog.h"
47 #include "epan/emem.h"
49 #include "gtk/gtkglobals.h"
50 #include "gtk/font_utils.h"
51 #include "gtk/packet_history.h"
52 #include "epan/column.h"
53 #include "gtk/recent.h"
55 #include "gtk/menus.h"
57 #include "color_filters.h"
58 #include "gtk/color_utils.h"
59 #include "gtk/capture_file_dlg.h"
60 #include "gtk/main_statusbar.h"
62 static PacketList *packetlist;
64 static gboolean enable_color;
66 static GtkWidget *create_view_and_model(void);
67 static guint row_from_iter(GtkTreeIter *iter);
68 static gboolean iter_from_row(GtkTreeIter *iter, guint row);
69 static void scroll_to_and_select_iter(GtkTreeIter *iter);
70 static void new_packet_list_select_cb(GtkTreeView *tree_view, gpointer data _U_);
71 static void show_cell_data_func(GtkTreeViewColumn *col,
72 GtkCellRenderer *renderer,
78 new_packet_list_create(void)
80 GtkWidget *view, *scrollwin;
82 scrollwin = scrolled_window_new(NULL, NULL);
84 view = create_view_and_model();
86 gtk_container_add(GTK_CONTAINER(scrollwin), view);
89 g_signal_connect(view, "row-activated",
90 G_CALLBACK(popup_menu_handler),
91 g_object_get_data(G_OBJECT(popup_menu_object),
93 g_signal_connect(view, "button_press_event",
94 G_CALLBACK(new_packet_list_button_pressed_cb), NULL);
97 g_object_set_data(G_OBJECT(popup_menu_object), E_MPACKET_LIST_KEY, view);
103 new_packet_list_append(column_info *cinfo, frame_data *fdata, packet_info *pinfo _U_)
109 /* Allocate the array holding column data, the size is the current number of columns */
110 row_data.col_text = se_alloc(sizeof(row_data.col_text)*packetlist->n_columns);
111 g_assert(packetlist->n_columns == cinfo->num_cols);
112 for(i = 0; i < cinfo->num_cols; i++) {
113 if (col_based_on_frame_data(cinfo, i) ||
114 /* We handle custom columns lazily */
115 cinfo->col_fmt[i] == COL_CUSTOM)
116 /* We already store the value in frame_data, so don't duplicate this. */
117 row_data.col_text[i] = NULL;
119 row_data.col_text[i] = se_strdup(cinfo->col_data[i]);
123 row_data.col_text = NULL;
125 row_data.fdata = fdata;
127 packet_list_append_record(packetlist, &row_data);
129 return packetlist->num_rows; /* XXX - Check that this is the right # */
133 create_view_and_model(void)
135 GtkTreeViewColumn *col;
136 GtkCellRenderer *renderer;
140 packetlist = new_packet_list_new();
142 packetlist->view = tree_view_new(GTK_TREE_MODEL(packetlist));
144 #if GTK_CHECK_VERSION(2,6,0)
145 gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(packetlist->view),
148 g_signal_connect(packetlist->view, "cursor-changed",
149 G_CALLBACK(new_packet_list_select_cb), NULL);
150 g_signal_connect(packetlist->view, "button_press_event", G_CALLBACK(popup_menu_handler),
151 g_object_get_data(G_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
152 g_object_set_data(G_OBJECT(popup_menu_object), E_MPACKET_LIST_KEY, packetlist);
154 /* g_object_unref(packetlist); */ /* Destroy automatically with view for now */ /* XXX - Messes up freezing & thawing */
156 renderer = gtk_cell_renderer_text_new();
157 g_object_set(renderer,
160 gtk_widget_modify_font(packetlist->view, user_font_get_regular());
162 for(i = 0; i < cfile.cinfo.num_cols; i++) {
163 col = gtk_tree_view_column_new();
164 gtk_tree_view_column_pack_start(col, renderer, TRUE);
165 gtk_tree_view_column_set_cell_data_func(col, renderer,
169 gtk_tree_view_column_set_title(col, cfile.cinfo.col_title[i]);
170 gtk_tree_view_column_set_sort_column_id(col, i);
171 gtk_tree_view_column_set_resizable(col, TRUE);
172 gtk_tree_view_column_set_sizing(col,GTK_TREE_VIEW_COLUMN_FIXED);
173 gtk_tree_view_column_set_reorderable(col, TRUE); /* XXX - Should this be saved in the prefs? */
175 col_width = recent_get_column_width(i);
176 if(col_width == -1) {
177 layout = gtk_widget_create_pango_layout(packetlist->view, get_column_width_string(get_column_format(i), i));
178 pango_layout_get_pixel_size(layout, &col_width, NULL);
179 gtk_tree_view_column_set_min_width(col, col_width);
180 g_object_unref(G_OBJECT(layout));
183 gtk_tree_view_append_column(GTK_TREE_VIEW(packetlist->view), col);
186 return packetlist->view;
190 new_packet_list_clear(void)
192 packet_history_clear();
194 new_packet_list_store_clear(packetlist);
195 gtk_widget_queue_draw(packetlist->view);
199 new_packet_list_freeze(void)
201 /* So we don't lose the model by the time we want to thaw it */
202 g_object_ref(packetlist);
204 /* Detach view from model */
205 gtk_tree_view_set_model(GTK_TREE_VIEW(packetlist->view), NULL);
209 new_packet_list_thaw(void)
211 /* Remove extra reference added by new_packet_list_freeze() */
212 g_object_unref(packetlist);
214 /* Re-attach view to the model */
215 gtk_tree_view_set_model(GTK_TREE_VIEW(packetlist->view),
216 GTK_TREE_MODEL(packetlist));
220 new_packet_list_resize_columns_cb(GtkWidget *widget _U_, gpointer data _U_)
222 g_warning("*** new_packet_list_resize_columns_cb() not yet implemented.");
226 new_packet_list_next(void)
228 GtkTreeSelection *selection;
232 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(packetlist->view));
233 if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
236 row = row_from_iter(&iter);
237 if (!iter_from_row(&iter, row+1))
240 scroll_to_and_select_iter(&iter);
244 new_packet_list_prev(void)
246 GtkTreeSelection *selection;
250 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(packetlist->view));
251 if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
254 row = row_from_iter(&iter);
255 if (!iter_from_row(&iter, row-1))
258 scroll_to_and_select_iter(&iter);
262 scroll_to_and_select_iter(GtkTreeIter *iter)
264 GtkTreeModel *model = GTK_TREE_MODEL(packetlist);
265 GtkTreeSelection *selection;
269 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(packetlist->view));
270 gtk_tree_selection_select_iter (selection, iter);
271 path = gtk_tree_model_get_path(model, iter);
272 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(packetlist->view),
275 TRUE, /* use_align */
276 0.5, /* row_align determines where the row is placed, 0.5 means center */
277 0); /* The horizontal alignment of the column */
278 gtk_tree_view_set_cursor(GTK_TREE_VIEW(packetlist->view),
281 FALSE); /* start_editing */
283 /* Needed to get the middle and bottom panes updated */
284 new_packet_list_select_cb(GTK_TREE_VIEW(packetlist->view), NULL);
288 new_packet_list_select_first_row(void)
290 GtkTreeModel *model = GTK_TREE_MODEL(packetlist);
293 if(!gtk_tree_model_get_iter_first(model, &iter))
296 scroll_to_and_select_iter(&iter);
300 new_packet_list_select_last_row(void)
302 GtkTreeModel *model = GTK_TREE_MODEL(packetlist);
306 if((children = gtk_tree_model_iter_n_children(model, NULL)) == 0)
309 if(!iter_from_row(&iter, children-1))
312 scroll_to_and_select_iter(&iter);
316 new_packet_list_find_row_from_data(gpointer data, gboolean select)
318 GtkTreeModel *model = GTK_TREE_MODEL(packetlist);
323 /* Initializes iter with the first iterator in the tree (the one at the path "0")
324 * and returns TRUE. Returns FALSE if the tree is empty
326 if(!gtk_tree_model_get_iter_first(model, &iter))
330 row = row_from_iter(&iter);
331 fdata = new_packet_list_get_row_data(row);
333 if(fdata == (frame_data*)data){
335 scroll_to_and_select_iter(&iter);
339 } while (gtk_tree_model_iter_next (model,&iter));
345 new_packet_list_set_selected_row(gint row)
348 GtkTreeModel *model = GTK_TREE_MODEL(packetlist);
349 GtkTreeSelection *selection;
352 if (!iter_from_row(&iter, row))
356 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(packetlist->view));
357 gtk_tree_selection_select_iter (selection, &iter);
358 path = gtk_tree_model_get_path(model, &iter);
359 gtk_tree_view_set_cursor(GTK_TREE_VIEW(packetlist->view),
362 FALSE); /* start_editing */
364 /* Needed to get the middle and bottom panes updated */
365 new_packet_list_select_cb(GTK_TREE_VIEW(packetlist->view), NULL);
369 new_packet_list_select_cb(GtkTreeView *tree_view, gpointer data _U_)
371 GtkTreeSelection *selection;
376 selection = gtk_tree_view_get_selection(tree_view);
377 gtk_tree_selection_get_selected(selection, NULL, &iter);
379 /* Remove the hex display tab pages */
380 while(gtk_notebook_get_nth_page(GTK_NOTEBOOK(byte_nb_ptr), 0))
381 gtk_notebook_remove_page(GTK_NOTEBOOK(byte_nb_ptr), 0);
383 row = row_from_iter(&iter);
385 cf_select_packet(&cfile, row);
387 /* Add newly selected frame to packet history (breadcrumbs) */
388 fdata = new_packet_list_get_row_data(row);
390 packet_history_add(fdata->num);
394 new_packet_list_get_event_row_column(GtkWidget *w _U_, GdkEventButton *event_button,
395 gint *row, gint *column)
398 GtkTreeViewColumn *view_column;
400 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(packetlist->view),
401 (gint) event_button->x,
402 (gint) event_button->y,
403 &path, &view_column, NULL, NULL)) {
408 gtk_tree_model_get_iter (GTK_TREE_MODEL(packetlist), &iter, path);
409 *row = row_from_iter(&iter);
410 gtk_tree_path_free(path);
413 cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(packetlist->view));
414 *column = g_list_index(cols, (gpointer) view_column);
424 new_packet_list_get_row_data(gint row)
426 PacketListRecord *record;
428 record = packetlist->rows[row];
430 return record->fdata;
434 row_from_iter(GtkTreeIter *iter)
436 PacketListRecord *record;
438 record = iter->user_data;
444 get_dissected_flag_from_iter(GtkTreeIter *iter)
446 PacketListRecord *record;
448 record = iter->user_data;
450 return record->dissected;
454 col_text_present_from_iter(GtkTreeIter *iter)
456 PacketListRecord *record;
458 record = iter->user_data;
460 return record->col_text != NULL;
464 set_dissected_flag_from_iter(GtkTreeIter *iter, gboolean dissected)
466 PacketListRecord *record;
468 record = iter->user_data;
470 record->dissected = dissected;
473 /* XXX: will this work with display filters? */
475 iter_from_row(GtkTreeIter *iter, guint row)
477 GtkTreeModel *model = GTK_TREE_MODEL(packetlist);
479 return gtk_tree_model_iter_nth_child(model, iter, NULL, row);
483 new_packet_list_dissect(frame_data *fdata, gboolean col_text_present)
490 /* We need to construct the columns if we skipped the columns entirely
491 * when reading the file or if we have custom columns enabled */
492 if (have_custom_cols(&cfile.cinfo) || !col_text_present)
493 cinfo = &cfile.cinfo;
497 if (!wtap_seek_read(cfile.wth, fdata->file_off, &cfile.pseudo_header,
498 cfile.pd, fdata->cap_len, &err, &err_info)) {
499 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
500 cf_read_error_message(err, err_info), cfile.filename);
504 edt = epan_dissect_new(TRUE /* create_proto_tree */, FALSE /* proto_tree_visible */);
505 color_filters_prime_edt(edt);
506 col_custom_prime_edt(edt, &cfile.cinfo);
507 epan_dissect_run(edt, &cfile.pseudo_header, cfile.pd, fdata, cinfo);
508 fdata->color_filter = color_filters_colorize_packet(0 /* row - unused */, edt);
510 /* "Stringify" non frame_data vals */
511 if (!col_text_present)
512 epan_dissect_fill_in_columns(edt, FALSE /* fill_fd_colums */);
514 epan_dissect_free(edt);
518 cache_columns(frame_data *fdata, guint row, gboolean col_text_present)
522 /* None of the columns are present. Fill them out in the record */
523 if (!col_text_present) {
524 for(col = 0; col < cfile.cinfo.num_cols; ++col) {
525 /* Skip columns based om frame_data because we already store those. */
526 if (!col_based_on_frame_data(&cfile.cinfo, col))
527 packet_list_change_record(packetlist, row, col, &cfile.cinfo);
532 /* Custom columns are present. Fill them out in the record */
533 if (have_custom_cols(&cfile.cinfo))
534 for (col = cfile.cinfo.col_first[COL_CUSTOM];
535 col <= cfile.cinfo.col_last[COL_CUSTOM];
537 if (cfile.cinfo.col_fmt[col] == COL_CUSTOM)
538 packet_list_change_record(packetlist, row, col, &cfile.cinfo);
542 show_cell_data_func(GtkTreeViewColumn *col _U_, GtkCellRenderer *renderer,
543 GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
545 guint row = row_from_iter(iter);
546 guint col_num = GPOINTER_TO_INT(data);
547 frame_data *fdata = new_packet_list_get_row_data(row);
548 color_filter_t *color_filter;
555 if (get_dissected_flag_from_iter(iter))
556 color_filter = fdata->color_filter;
558 gboolean col_text_present = col_text_present_from_iter(iter);
559 new_packet_list_dissect(fdata, col_text_present);
560 set_dissected_flag_from_iter(iter, TRUE);
561 cache_columns(fdata, row, col_text_present);
562 color_filter = fdata->color_filter;
565 if (col_based_on_frame_data(&cfile.cinfo, col_num)) {
566 col_fill_in_frame_data(fdata, &cfile.cinfo, col_num);
567 cell_text = g_strdup(cfile.cinfo.col_data[col_num]);
569 gtk_tree_model_get(model, iter,
574 if((fdata->color_filter)||(fdata->flags.marked)){
575 gboolean color_on = enable_color;
576 if(fdata->flags.marked){
577 color_t_to_gdkcolor(&fg_gdk, &prefs.gui_marked_fg);
578 color_t_to_gdkcolor(&bg_gdk, &prefs.gui_marked_bg);
581 color_filter = fdata->color_filter;
582 fg_color_t = color_filter->fg_color;
583 bg_color_t = color_filter->bg_color;
584 color_t_to_gdkcolor(&fg_gdk, &fg_color_t);
585 color_t_to_gdkcolor(&bg_gdk, &bg_color_t);
587 g_object_set(renderer,
589 "foreground-gdk", &fg_gdk,
590 "foreground-set", color_on,
591 "background-gdk", &bg_gdk,
592 "background-set", color_on,
595 g_object_set(renderer,
604 new_packet_list_enable_color(gboolean enable)
606 enable_color = enable;
607 gtk_widget_queue_draw (packetlist->view);
611 new_packet_list_queue_draw(void)
613 gtk_widget_queue_draw (packetlist->view);
616 /* call this after last set_frame_mark is done */
617 static void mark_frames_ready(void)
619 file_save_update_dynamics();
620 packets_bar_update();
624 set_frame_mark(gboolean set, frame_data *frame)
627 cf_mark_frame(&cfile, frame);
629 cf_unmark_frame(&cfile, frame);
634 new_packet_list_set_font(PangoFontDescription *font)
636 gtk_widget_modify_font(packetlist->view, font);
639 void new_packet_list_mark_frame_cb(GtkWidget *w _U_, gpointer data _U_)
641 GtkTreeSelection *selection;
646 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(packetlist->view));
647 gtk_tree_selection_get_selected(selection, NULL, &iter);
648 row = row_from_iter(&iter);
650 fdata = new_packet_list_get_row_data(row);
652 set_frame_mark(!fdata->flags.marked, fdata);
657 #endif /* NEW_PACKET_LIST */