2 * Routines for handling column preferences
4 * $Id: column.c,v 1.3 1998/11/18 03:01:26 gerald Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
47 static GtkWidget *column_l, *chg_bt, *del_bt, *title_te, *fmt_m, *up_bt,
51 #define E_COL_NAME_KEY "column_name"
52 #define E_COL_LBL_KEY "column_label"
53 #define E_COL_CM_KEY "in_col_cancel_mode"
55 static gchar *col_format_to_string(gint);
56 static gchar *col_format_desc(gint);
57 static gint get_column_format_from_str(gchar *str);
58 static void column_sel_list_cb(GtkWidget *, gpointer);
59 static void column_sel_new_cb(GtkWidget *, gpointer);
60 static void column_sel_chg_cb(GtkWidget *, gpointer);
61 static void column_sel_del_cb(GtkWidget *, gpointer);
62 static void column_sel_arrow_cb(GtkWidget *, gpointer);
63 static void column_set_fmt_cb(GtkWidget *, gpointer);
65 /* Given a format number (as defined in ethereal.h), returns its equivalent
68 col_format_to_string(gint fmt) {
69 gchar *slist[] = { "%m", "%t", "%t", "%t", "%s", "%rs", "%us", "%hs",
70 "%rhs", "%uhs", "%ns", "%rns", "%uns", "%d", "%rd",
71 "%ud", "%hd", "%rhd", "%uhd", "%nd", "%rnd", "%und",
72 "%S", "%rS", "%uS", "%D", "%rD", "%uD", "%p", "%i" };
74 if (fmt < 0 || fmt > NUM_COL_FMTS)
80 /* Given a format number (as defined in ethereal.h), returns its
83 col_format_desc(gint fmt) {
84 gchar *dlist[] = { "Number", "Relative time", "Absolute time",
85 "Delta time", "Source address", "Src addr (resolved)",
86 "Src addr (unresolved)", "Hardware src addr",
87 "Hw src addr (resolved)", "Hw src addr (unresolved)",
88 "Network src addr", "Net scr addr (resolved)",
89 "Net src addr (unresolved)", "Destination address",
90 "Dest addr (resolved)", "Dest addr (unresolved)",
91 "Hardware dest addr", "Hw dest addr (resolved)",
92 "Hw dest addr (unresolved)", "Network dest addr",
93 "Net dest addr (resolved)", "Net dest addr (unresolved)",
94 "Source port", "Src port (resolved)",
95 "Src port (unresolved)", "Destination port",
96 "Dest port (resolved)", "Dest port (unresolved)",
97 "Protocol", "Information" };
99 if (fmt < 0 || fmt > NUM_COL_FMTS)
105 /* Marks each array element true if it can be substituted for the given
108 get_column_format_matches(gboolean *fmt_list, gint format) {
111 for (i = 0; i < NUM_COL_FMTS; i++) {
112 /* Get the obvious: the format itself */
115 /* Get any formats lower down on the chain */
118 fmt_list[COL_RES_DL_SRC] = TRUE;
119 fmt_list[COL_RES_NET_SRC] = TRUE;
122 fmt_list[COL_RES_DL_SRC] = TRUE;
123 fmt_list[COL_RES_NET_SRC] = TRUE;
126 fmt_list[COL_UNRES_DL_SRC] = TRUE;
127 fmt_list[COL_UNRES_NET_SRC] = TRUE;
130 fmt_list[COL_RES_DL_DST] = TRUE;
131 fmt_list[COL_RES_NET_DST] = TRUE;
134 fmt_list[COL_RES_DL_DST] = TRUE;
135 fmt_list[COL_RES_NET_DST] = TRUE;
138 fmt_list[COL_UNRES_DL_DST] = TRUE;
139 fmt_list[COL_UNRES_NET_DST] = TRUE;
142 fmt_list[COL_RES_DL_SRC] = TRUE;
145 fmt_list[COL_RES_DL_DST] = TRUE;
147 case COL_DEF_NET_SRC:
148 fmt_list[COL_RES_NET_SRC] = TRUE;
150 case COL_DEF_NET_DST:
151 fmt_list[COL_RES_NET_DST] = TRUE;
153 case COL_DEF_SRC_PORT:
154 fmt_list[COL_RES_SRC_PORT] = TRUE;
156 case COL_DEF_DST_PORT:
157 fmt_list[COL_RES_DST_PORT] = TRUE;
165 /* Returns the longest possible width for a particular column type */
167 get_column_width(gint format, GdkFont *font) {
170 return (gdk_string_width(font, "0") * 7);
173 return (gdk_string_width(font, "00:00:00.000000"));
177 return (gdk_string_width(font, "0000.000000"));
184 case COL_UNRES_DL_SRC:
185 case COL_DEF_NET_SRC:
186 case COL_RES_NET_SRC:
187 case COL_UNRES_NET_SRC:
193 case COL_UNRES_DL_DST:
194 case COL_DEF_NET_DST:
195 case COL_RES_NET_DST:
196 case COL_UNRES_NET_DST:
197 return (gdk_string_width(font, "00:00:00:00:00:00"));
199 case COL_DEF_SRC_PORT:
200 case COL_RES_SRC_PORT:
201 case COL_UNRES_SRC_PORT:
202 case COL_DEF_DST_PORT:
203 case COL_RES_DST_PORT:
204 case COL_UNRES_DST_PORT:
205 return (gdk_string_width(font, "0") * 6);
208 return (gdk_string_width(font, "NBNS (UDP)"));
210 default: /* COL_INFO */
211 return (gdk_string_width(font, "Source port: kerberos-master "
212 "Destination port: kerberos-master"));
226 get_column_format(gint col) {
227 GList *clp = g_list_nth(prefs.col_list, col);
230 cfmt = (fmt_data *) clp->data;
232 return(get_column_format_from_str(cfmt->fmt));
236 get_column_format_from_str(gchar *str) {
238 gint res_off = RES_DEF, addr_off = ADDR_DEF;
240 /* To do: Make this parse %-formatted strings "for real" */
241 while (*cptr != '\0') {
243 case 't': /* To do: fix for absolute and delta */
250 return COL_DEF_SRC + res_off + addr_off;
253 return COL_DEF_DST + res_off + addr_off;
256 return COL_DEF_SRC_PORT + res_off;
259 return COL_DEF_DST_PORT + res_off;
286 get_column_title(gint col) {
287 GList *clp = g_list_nth(prefs.col_list, col);
290 cfmt = (fmt_data *) clp->data;
295 #define MAX_FMT_PREF_LEN 1024
296 #define MAX_FMT_PREF_LINE_LEN 60
298 col_format_to_pref_str() {
299 static gchar pref_str[MAX_FMT_PREF_LEN] = "";
300 GList *clp = g_list_first(prefs.col_list);
302 int cur_pos = 0, cur_len = 0, fmt_len;
305 cfmt = (fmt_data *) clp->data;
307 fmt_len = strlen(cfmt->title) + 4;
308 if ((fmt_len + cur_len) < (MAX_FMT_PREF_LEN - 1)) {
309 if ((fmt_len + cur_pos) > MAX_FMT_PREF_LINE_LEN) {
312 pref_str[cur_len] = '\n'; cur_len++;
313 pref_str[cur_len] = '\t'; cur_len++;
315 sprintf(&pref_str[cur_len], "\"%s\", ", cfmt->title);
320 fmt_len = strlen(cfmt->fmt) + 4;
321 if ((fmt_len + cur_len) < (MAX_FMT_PREF_LEN - 1)) {
322 if ((fmt_len + cur_pos) > MAX_FMT_PREF_LINE_LEN) {
325 pref_str[cur_len] = '\n'; cur_len++;
326 pref_str[cur_len] = '\t'; cur_len++;
328 sprintf(&pref_str[cur_len], "\"%s\", ", cfmt->fmt);
337 pref_str[cur_len - 2] = '\0';
342 /* Create and display the column selection widgets. */
343 /* Called when the 'Columns' preference notebook page is selected. */
345 column_prefs_show() {
346 GtkWidget *main_vb, *top_hb, *list_bb, *new_bt, *column_sc, *nl_item,
347 *nl_lb, *tb, *lb, *menu, *mitem, *arrow_hb;
352 /* Container for each row of widgets */
353 main_vb = gtk_vbox_new(FALSE, 5);
354 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
355 gtk_widget_show(main_vb);
356 gtk_object_set_data(GTK_OBJECT(main_vb), E_COL_CM_KEY, (gpointer)FALSE);
358 /* Top row: Column list and buttons */
359 top_hb = gtk_hbox_new(FALSE, 5);
360 gtk_container_add(GTK_CONTAINER(main_vb), top_hb);
361 gtk_widget_show(top_hb);
363 list_bb = gtk_vbutton_box_new();
364 gtk_button_box_set_layout (GTK_BUTTON_BOX (list_bb), GTK_BUTTONBOX_START);
365 gtk_container_add(GTK_CONTAINER(top_hb), list_bb);
366 gtk_widget_show(list_bb);
368 new_bt = gtk_button_new_with_label ("New");
369 gtk_signal_connect(GTK_OBJECT(new_bt), "clicked",
370 GTK_SIGNAL_FUNC(column_sel_new_cb), NULL);
371 gtk_container_add(GTK_CONTAINER(list_bb), new_bt);
372 gtk_widget_show(new_bt);
374 chg_bt = gtk_button_new_with_label ("Change");
375 gtk_widget_set_sensitive(chg_bt, FALSE);
376 gtk_signal_connect(GTK_OBJECT(chg_bt), "clicked",
377 GTK_SIGNAL_FUNC(column_sel_chg_cb), NULL);
378 gtk_container_add(GTK_CONTAINER(list_bb), chg_bt);
379 gtk_widget_show(chg_bt);
381 del_bt = gtk_button_new_with_label ("Delete");
382 gtk_widget_set_sensitive(del_bt, FALSE);
383 gtk_signal_connect(GTK_OBJECT(del_bt), "clicked",
384 GTK_SIGNAL_FUNC(column_sel_del_cb), NULL);
385 gtk_container_add(GTK_CONTAINER(list_bb), del_bt);
386 gtk_widget_show(del_bt);
388 arrow_hb = gtk_hbox_new(TRUE, 3);
389 gtk_container_add(GTK_CONTAINER(list_bb), arrow_hb);
390 gtk_widget_show(arrow_hb);
392 up_bt = gtk_button_new_with_label("Up");
393 gtk_widget_set_sensitive(up_bt, FALSE);
394 gtk_signal_connect(GTK_OBJECT(up_bt), "clicked",
395 GTK_SIGNAL_FUNC(column_sel_arrow_cb), NULL);
396 gtk_box_pack_start(GTK_BOX(arrow_hb), up_bt, TRUE, TRUE, 0);
397 gtk_widget_show(up_bt);
399 dn_bt = gtk_button_new_with_label("Down");
400 gtk_widget_set_sensitive(dn_bt, FALSE);
401 gtk_signal_connect(GTK_OBJECT(dn_bt), "clicked",
402 GTK_SIGNAL_FUNC(column_sel_arrow_cb), NULL);
403 gtk_box_pack_start(GTK_BOX(arrow_hb), dn_bt, TRUE, TRUE, 0);
404 gtk_widget_show(dn_bt);
406 column_sc = gtk_scrolled_window_new(NULL, NULL);
407 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(column_sc),
408 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
409 gtk_widget_set_usize(column_sc, 250, 150);
410 gtk_container_add(GTK_CONTAINER(top_hb), column_sc);
411 gtk_widget_show(column_sc);
413 column_l = gtk_list_new();
414 gtk_list_set_selection_mode(GTK_LIST(column_l), GTK_SELECTION_SINGLE);
415 gtk_signal_connect(GTK_OBJECT(column_l), "selection_changed",
416 GTK_SIGNAL_FUNC(column_sel_list_cb), main_vb);
417 gtk_container_add(GTK_CONTAINER(column_sc), column_l);
418 gtk_widget_show(column_l);
420 clp = g_list_first(prefs.col_list);
422 cfmt = (fmt_data *) clp->data;
423 nl_lb = gtk_label_new(cfmt->title);
424 nl_item = gtk_list_item_new();
425 gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5);
426 gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
427 gtk_widget_show(nl_lb);
428 gtk_container_add(GTK_CONTAINER(column_l), nl_item);
429 gtk_widget_show(nl_item);
430 gtk_object_set_data(GTK_OBJECT(nl_item), E_COL_LBL_KEY, nl_lb);
431 gtk_object_set_data(GTK_OBJECT(nl_item), E_COL_NAME_KEY, clp);
436 /* Colunm name entry and format selection */
437 tb = gtk_table_new(2, 2, FALSE);
438 gtk_container_add(GTK_CONTAINER(main_vb), tb);
439 gtk_table_set_row_spacings(GTK_TABLE(tb), 10);
440 gtk_table_set_col_spacings(GTK_TABLE(tb), 15);
443 lb = gtk_label_new("Column title:");
444 gtk_misc_set_alignment(GTK_MISC(lb), 1.0, 0.5);
445 gtk_table_attach_defaults(GTK_TABLE(tb), lb, 0, 1, 0, 1);
448 title_te = gtk_entry_new();
449 gtk_table_attach_defaults(GTK_TABLE(tb), title_te, 1, 2, 0, 1);
450 gtk_widget_show(title_te);
452 lb = gtk_label_new("Column format:");
453 gtk_misc_set_alignment(GTK_MISC(lb), 1.0, 0.5);
454 gtk_table_attach_defaults(GTK_TABLE(tb), lb, 0, 1, 1, 2);
457 fmt_m = gtk_option_menu_new();
458 menu = gtk_menu_new();
459 for (i = 0; i < NUM_COL_FMTS; i++) {
460 mitem = gtk_menu_item_new_with_label(col_format_desc(i));
461 gtk_menu_append(GTK_MENU(menu), mitem);
462 gtk_signal_connect_object( GTK_OBJECT(mitem), "activate",
463 GTK_SIGNAL_FUNC(column_set_fmt_cb), (gpointer) i);
464 gtk_widget_show(mitem);
466 gtk_option_menu_set_menu(GTK_OPTION_MENU(fmt_m), menu);
468 gtk_option_menu_set_history(GTK_OPTION_MENU(fmt_m), cur_fmt);
469 gtk_table_attach_defaults(GTK_TABLE(tb), fmt_m, 1, 2, 1, 2);
470 gtk_widget_show(fmt_m);
476 column_sel_list_cb(GtkWidget *l, gpointer data) {
481 gint sensitivity = FALSE, up_sens = FALSE, dn_sens = FALSE;
483 sl = GTK_LIST(l)->selection;
485 if (sl) { /* Something was selected */
486 l_item = GTK_OBJECT(sl->data);
487 clp = (GList *) gtk_object_get_data(l_item, E_COL_NAME_KEY);
489 cfmt = (fmt_data *) clp->data;
491 cur_fmt = get_column_format_from_str(cfmt->fmt);
492 gtk_option_menu_set_history(GTK_OPTION_MENU(fmt_m), cur_fmt);
494 if (clp != g_list_first(prefs.col_list))
496 if (clp != g_list_last(prefs.col_list))
501 /* Did you know that this function is called when the window is destroyed? */
503 if (!gtk_object_get_data(GTK_OBJECT(data), E_COL_CM_KEY)) {
504 gtk_entry_set_text(GTK_ENTRY(title_te), title);
505 gtk_widget_set_sensitive(chg_bt, sensitivity);
506 gtk_widget_set_sensitive(del_bt, sensitivity);
507 gtk_widget_set_sensitive(up_bt, up_sens);
508 gtk_widget_set_sensitive(dn_bt, dn_sens);
512 /* To do: add input checking to each of these callbacks */
515 column_sel_new_cb(GtkWidget *w, gpointer data) {
518 GtkWidget *nl_item, *nl_lb;
520 title = gtk_entry_get_text(GTK_ENTRY(title_te));
522 if (strlen(title) > 0) {
523 cfmt = (fmt_data *) g_malloc(sizeof(fmt_data));
524 cfmt->title = g_strdup(title);
525 cfmt->fmt = g_strdup(col_format_to_string(cur_fmt));
526 prefs.col_list = g_list_append(prefs.col_list, cfmt);
527 nl_lb = gtk_label_new(cfmt->title);
528 nl_item = gtk_list_item_new();
529 gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5);
530 gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
531 gtk_widget_show(nl_lb);
532 gtk_container_add(GTK_CONTAINER(column_l), nl_item);
533 gtk_widget_show(nl_item);
534 gtk_object_set_data(GTK_OBJECT(nl_item), E_COL_LBL_KEY, nl_lb);
535 gtk_object_set_data(GTK_OBJECT(nl_item), E_COL_NAME_KEY,
536 g_list_last(prefs.col_list));
537 gtk_list_select_child(GTK_LIST(column_l), nl_item);
542 column_sel_chg_cb(GtkWidget *w, gpointer data) {
549 sl = GTK_LIST(column_l)->selection;
550 title = gtk_entry_get_text(GTK_ENTRY(title_te));
552 if (sl) { /* Something was selected */
553 l_item = GTK_OBJECT(sl->data);
554 clp = (GList *) gtk_object_get_data(l_item, E_COL_NAME_KEY);
555 nl_lb = (GtkLabel *) gtk_object_get_data(l_item, E_COL_LBL_KEY);
557 cfmt = (fmt_data *) clp->data;
559 if (strlen(title) > 0 && cfmt) {
562 cfmt->title = g_strdup(title);
563 cfmt->fmt = g_strdup(col_format_to_string(cur_fmt));
564 gtk_label_set(nl_lb, cfmt->title);
571 column_sel_del_cb(GtkWidget *w, gpointer data) {
577 sl = GTK_LIST(column_l)->selection;
578 if (sl) { /* Something was selected */
579 l_item = GTK_OBJECT(sl->data);
580 pos = gtk_list_child_position(GTK_LIST(column_l), GTK_WIDGET(l_item));
581 clp = (GList *) gtk_object_get_data(l_item, E_COL_NAME_KEY);
583 cfmt = (fmt_data *) clp->data;
587 prefs.col_list = g_list_remove_link(prefs.col_list, clp);
588 gtk_list_clear_items(GTK_LIST(column_l), pos, pos + 1);
594 column_sel_arrow_cb(GtkWidget *w, gpointer data) {
595 GList *sl, *clp, *il;
603 sl = GTK_LIST(column_l)->selection;
604 if (sl) { /* Something was selected */
605 l_item = GTK_OBJECT(sl->data);
606 pos = gtk_list_child_position(GTK_LIST(column_l), GTK_WIDGET(l_item));
607 clp = (GList *) gtk_object_get_data(l_item, E_COL_NAME_KEY);
609 cfmt = (fmt_data *) clp->data;
610 prefs.col_list = g_list_remove(prefs.col_list, cfmt);
611 g_list_insert(prefs.col_list, cfmt, pos + inc);
612 il = (GList *) g_malloc(sizeof(GList));
616 gtk_widget_ref(GTK_WIDGET(l_item));
617 gtk_list_clear_items(GTK_LIST(column_l), pos, pos + 1);
618 gtk_list_insert_items(GTK_LIST(column_l), il, pos + inc);
619 gtk_widget_unref(GTK_WIDGET(l_item));
620 gtk_list_select_item(GTK_LIST(column_l), pos + inc);
626 column_set_fmt_cb(GtkWidget *w, gpointer data) {
627 cur_fmt = (gint) data;
631 column_prefs_ok(GtkWidget *w) {
633 column_prefs_cancel(w);
637 column_prefs_save(GtkWidget *w) {
641 column_prefs_cancel(GtkWidget *w) {
643 /* Let the list cb know we're about to destroy the widget tree, so it */
644 /* doesn't operate on widgets that don't exist. */
645 gtk_object_set_data(GTK_OBJECT(w), E_COL_CM_KEY, (gpointer)TRUE);
646 gtk_widget_destroy(GTK_WIDGET(w));