4 * User Accessible Tables GUI
5 * Maintain an array of user accessible data strucures
7 * (c) 2007, Luis E. Garcia Ontanon <luis@ontanon.org>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 2001 Gerald Combs
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 * - field value check (red/green editbox)
32 * - tooltips (add field descriptions)
33 * - Make cells editable
34 * - Allow reordering via drag and drop
43 #if GTK_CHECK_VERSION(3,0,0)
44 # include <gdk/gdkkeysyms-compat.h>
47 #include <wsutil/report_err.h>
49 #include <epan/dfilter/dfilter-macro.h>
50 #include <epan/proto.h>
51 #include <epan/packet.h>
52 #include <epan/uat-int.h>
53 #include <epan/value_string.h>
54 #include <wsutil/filesystem.h>
56 #include <epan/stat_groups.h>
58 #include "ui/help_url.h"
59 #include "ui/gtk/gtkglobals.h"
60 #include "ui/gtk/gui_utils.h"
61 #include "ui/gtk/dlg_utils.h"
62 #include "ui/gtk/stock_icons.h"
63 #include "ui/gtk/gui_stat_menu.h"
64 #include "ui/gtk/main.h"
65 #include "ui/gtk/uat_gui.h"
66 #include "ui/gtk/packet_list.h"
67 #include "ui/gtk/webbrowser.h"
68 #include "ui/gtk/old-gtk-compat.h"
69 #include "ui/gtk/packet_win.h"
71 # define BUTTON_SIZE_X -1
72 # define BUTTON_SIZE_Y -1
77 GtkWidget *scrolledwindow;
79 GtkListStore *list_store;
85 GtkWidget *bt_refresh;
92 GtkWidget *unsaved_window;
102 struct _uat_dlg_data {
109 GPtrArray *tobe_freed;
112 static gboolean unsaved_dialog(GtkWindow *w, GdkEvent *e, gpointer u);
113 static gboolean uat_window_delete_event_cb(GtkWindow *w, GdkEvent *e, gpointer u);
115 static void set_buttons(uat_t *uat, gint row) {
117 if (!uat->rep) return;
120 gtk_widget_set_sensitive (uat->rep->bt_up, TRUE);
122 gtk_widget_set_sensitive (uat->rep->bt_up, FALSE);
125 if (row < (gint)(uat->raw_data->len - 1) && row >= 0) {
126 gtk_widget_set_sensitive (uat->rep->bt_down, TRUE);
128 gtk_widget_set_sensitive (uat->rep->bt_down, FALSE);
131 gtk_widget_set_sensitive (uat->rep->bt_new, TRUE);
132 gtk_widget_set_sensitive (uat->rep->bt_clear, TRUE);
135 gtk_widget_set_sensitive (uat->rep->bt_edit, FALSE);
136 gtk_widget_set_sensitive (uat->rep->bt_copy, FALSE);
137 gtk_widget_set_sensitive (uat->rep->bt_delete, FALSE);
139 gtk_widget_set_sensitive (uat->rep->bt_edit, TRUE);
140 gtk_widget_set_sensitive (uat->rep->bt_copy, TRUE);
141 gtk_widget_set_sensitive (uat->rep->bt_delete, TRUE);
145 g_signal_handlers_disconnect_by_func(uat->rep->window, uat_window_delete_event_cb, uat);
146 g_signal_connect(uat->rep->window, "delete_event", G_CALLBACK(unsaved_dialog), uat);
147 g_signal_connect(uat->rep->window, "destroy", G_CALLBACK(unsaved_dialog), uat);
149 g_signal_handlers_disconnect_by_func(uat->rep->window, unsaved_dialog, uat);
150 g_signal_connect(GTK_WINDOW(uat->rep->window), "delete_event", G_CALLBACK(uat_window_delete_event_cb), uat);
151 g_signal_connect(GTK_WINDOW(uat->rep->window), "destroy", G_CALLBACK(uat_window_delete_event_cb), uat);
155 static void limit_buttons(uat_t *uat) {
157 if (!uat->rep) return;
159 gtk_widget_set_sensitive (uat->rep->bt_up, FALSE);
160 gtk_widget_set_sensitive (uat->rep->bt_down, FALSE);
162 gtk_widget_set_sensitive (uat->rep->bt_new, FALSE);
163 gtk_widget_set_sensitive (uat->rep->bt_edit, FALSE);
164 gtk_widget_set_sensitive (uat->rep->bt_copy, FALSE);
165 gtk_widget_set_sensitive (uat->rep->bt_delete, FALSE);
167 gtk_widget_set_sensitive (uat->rep->bt_clear, FALSE);
170 static char *fld_tostr(void *rec, uat_field_t *f) {
175 f->cb.tostr(rec, &ptr, &len, f->cbdata.tostr, f->fld_data);
179 case PT_TXTMOD_STRING:
181 case PT_TXTMOD_FILENAME:
182 case PT_TXTMOD_DIRECTORYNAME:
183 out = g_strndup(ptr, len);
185 case PT_TXTMOD_HEXBYTES: {
186 GString *s = g_string_sized_new( len*2 + 1 );
189 for (i=0; i<len;i++) g_string_append_printf(s, "%.2X", ((const guint8*)ptr)[i]);
191 out = g_strdup(s->str);
193 g_string_free(s, TRUE);
197 g_assert_not_reached();
208 static void append_row(uat_t *uat, guint idx) {
209 void *rec = UAT_INDEX_PTR(uat, idx);
210 uat_field_t *f = uat->fields;
215 if (! uat->rep) return;
217 gtk_list_store_insert_before(uat->rep->list_store, &iter, NULL);
218 for ( colnum = 0; colnum < uat->ncols; colnum++ ) {
219 tmp_str = fld_tostr(rec, &(f[colnum]));
220 gtk_list_store_set(uat->rep->list_store, &iter, colnum, tmp_str, -1);
225 static void reset_row(uat_t *uat, guint idx) {
226 void *rec = UAT_INDEX_PTR(uat, idx);
227 uat_field_t *f = uat->fields;
233 if (! uat->rep) return;
235 path = gtk_tree_path_new_from_indices(idx, -1);
236 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(uat->rep->list_store), &iter, path)) {
240 for ( colnum = 0; colnum < uat->ncols; colnum++ ) {
241 tmp_str = fld_tostr(rec, &(f[colnum]));
242 gtk_list_store_set(uat->rep->list_store, &iter, colnum, tmp_str, -1);
247 static guint8 *unhexbytes(const char *si, guint len, guint *len_p, char** err) {
250 const guint8 *s = (const guint8 *)si;
254 *err = g_strdup_printf("Uneven number of chars hex string %u \n'%s'", len, si);
258 buf = (guint8 *)g_malloc(len/2+1);
261 for (i = 0; i<len ; i += 2) {
265 if (hi >= '0' && hi <= '9') {
267 } else if (hi >= 'a' && hi <= 'f') {
270 } else if (hi >= 'A' && hi <= 'F') {
277 if (lo >= '0' && lo <= '9') {
279 } else if (lo >= 'a' && lo <= 'f') {
282 } else if (lo >= 'A' && lo <= 'F') {
289 *(p++) = (hi*0x10) + lo;
294 if (len_p) *len_p = len;
302 *err = g_strdup("Error parsing hex string");
307 static gboolean uat_dlg_cb(GtkWidget *win _U_, gpointer user_data) {
308 struct _uat_dlg_data *dd = (struct _uat_dlg_data *)user_data;
309 guint ncols = dd->uat->ncols;
310 uat_field_t *f = dd->uat->fields;
311 char *err = NULL, *tmp_err = NULL;
314 for ( colnum = 0; colnum < ncols; colnum++ ) {
315 void *e = g_ptr_array_index(dd->entries, colnum);
316 const char *text = NULL;
317 char *text_free = NULL;
320 switch(f[colnum].mode) {
321 case PT_TXTMOD_FILENAME:
322 case PT_TXTMOD_DIRECTORYNAME:
323 text = text_free = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(e));
325 len = (unsigned) strlen(text);
332 case PT_TXTMOD_STRING:
333 text = gtk_entry_get_text(GTK_ENTRY(e));
334 len = (unsigned) strlen(text);
336 case PT_TXTMOD_HEXBYTES: {
337 text = gtk_entry_get_text(GTK_ENTRY(e));
339 text_free = unhexbytes(text, (guint) strlen(text), &len, &err);
340 text = (const char *)text_free;
344 err = g_strdup_printf("error in field '%s': %s", f[colnum].title, tmp_err);
351 case PT_TXTMOD_ENUM: {
353 text = (idx >= 0) ? ((const value_string *)(f[colnum].fld_data))[idx].strptr : "";
354 len = (unsigned) strlen(text);
357 case PT_TXTMOD_NONE: break;
359 g_assert_not_reached();
363 if (f[colnum].cb.chk) {
364 if (! f[colnum].cb.chk(dd->rec, text, len, f[colnum].cbdata.chk, f[colnum].fld_data, &err)) {
366 err = g_strdup_printf("error in column '%s': %s", f[colnum].title, tmp_err);
372 f[colnum].cb.set(dd->rec, text, len, f[colnum].cbdata.set, f[colnum].fld_data);
377 if (dd->uat->update_cb) {
378 if (!dd->uat->update_cb(dd->rec, &err)) {
380 err = g_strdup_printf("error updating record: %s", tmp_err);
387 void *rec_tmp = dd->rec;
388 dd->rec = uat_add_record(dd->uat, dd->rec, TRUE);
390 if (dd->uat->free_cb) {
391 dd->uat->free_cb(rec_tmp);
396 uat_update_record(dd->uat, dd->rec, TRUE);
399 dd->uat->changed = TRUE;
401 set_buttons(dd->uat, dd->uat->rep ? dd->uat->rep->selected : -1);
404 append_row(dd->uat, dd->uat->raw_data->len - 1 );
406 reset_row(dd->uat, dd->row);
409 g_ptr_array_free(dd->entries, TRUE);
410 window_destroy(GTK_WIDGET(dd->win));
413 window_present(GTK_WIDGET(dd->uat->rep->window));
415 while (dd->tobe_freed->len) g_free( g_ptr_array_remove_index_fast(dd->tobe_freed, dd->tobe_freed->len - 1 ) );
422 report_failure("%s", err);
427 static gboolean uat_cancel_dlg_cb(GtkWidget *win _U_, gpointer user_data) {
428 struct _uat_dlg_data *dd = (struct _uat_dlg_data *)user_data;
431 window_present(GTK_WIDGET(dd->uat->rep->window));
433 /* Reset the buttons */
434 set_buttons(dd->uat, dd->uat->rep ? dd->uat->rep->selected : -1);
436 if (dd->is_new) g_free(dd->rec);
437 g_ptr_array_free(dd->entries, TRUE);
438 window_destroy(GTK_WIDGET(dd->win));
440 while (dd->tobe_freed->len) g_free( g_ptr_array_remove_index_fast(dd->tobe_freed, dd->tobe_freed->len - 1 ) );
447 static void fld_combo_box_changed_cb(GtkComboBox *combo_box, gpointer user_data) {
448 int *valptr = (int *)user_data;
450 *valptr = gtk_combo_box_get_active(combo_box);
453 static void uat_edit_dialog(uat_t *uat, gint row, gboolean copy) {
454 GtkWidget *win, *main_grid, *main_vb, *bbox, *bt_cancel, *bt_ok;
455 struct _uat_dlg_data *dd = (struct _uat_dlg_data *)g_malloc(sizeof(struct _uat_dlg_data));
456 uat_field_t *f = uat->fields;
460 /* Only allow a single operation at a time, prevents bug 9129 */
463 dd->entries = g_ptr_array_new();
464 tmp_str = g_strdup_printf("%s: %s", uat->name, (row == -1 ? "New" : "Edit"));
465 dd->win = dlg_conf_window_new(tmp_str);
468 if (copy && row >= 0) {
469 dd->rec = g_malloc0(uat->record_size);
471 uat->copy_cb (dd->rec, UAT_INDEX_PTR(uat, row), uat->record_size);
474 /* According to documentation of uat_copy_cb_t memcpy should be used if uat->copy_cb is NULL */
475 memcpy(dd->rec, UAT_INDEX_PTR(uat, row), uat->record_size);
478 } else if (row >= 0) {
479 dd->rec = UAT_INDEX_PTR(uat, row);
482 dd->rec = g_malloc0(uat->record_size);
486 dd->tobe_freed = g_ptr_array_new();
490 gtk_window_set_resizable(GTK_WINDOW(win), FALSE);
491 gtk_window_resize(GTK_WINDOW(win), 400, 30*(uat->ncols+2));
493 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
494 gtk_container_add(GTK_CONTAINER(win), main_vb);
495 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 6);
497 main_grid = ws_gtk_grid_new();
498 gtk_box_pack_start(GTK_BOX(main_vb), main_grid, FALSE, FALSE, 0);
499 ws_gtk_grid_set_row_spacing(GTK_GRID(main_grid), 5);
500 ws_gtk_grid_set_column_spacing(GTK_GRID(main_grid), 10);
502 bbox = dlg_button_row_new(GTK_STOCK_CANCEL, GTK_STOCK_OK, NULL);
503 gtk_box_pack_end(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
505 bt_ok = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
506 g_signal_connect(bt_ok, "clicked", G_CALLBACK(uat_dlg_cb), dd);
508 bt_cancel = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
509 g_signal_connect(bt_cancel, "clicked", G_CALLBACK(uat_cancel_dlg_cb), dd);
510 window_set_cancel_button(win, bt_cancel, NULL);
512 for ( colnum = 0; colnum < uat->ncols; colnum++ ) {
513 GtkWidget *entry, *label, *event_box;
514 char *text = fld_tostr(dd->rec, &(f[colnum]));
518 event_box = gtk_event_box_new();
520 label_text = g_strdup_printf("%s:", f[colnum].title);
521 label = gtk_label_new(label_text);
522 if (f[colnum].desc != NULL)
523 gtk_widget_set_tooltip_text(event_box, f[colnum].desc);
526 gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
527 ws_gtk_grid_attach_defaults(GTK_GRID(main_grid), event_box, 0, colnum, 1, 1);
528 gtk_container_add(GTK_CONTAINER(event_box), label);
530 switch(f[colnum].mode) {
531 case PT_TXTMOD_FILENAME:
532 case PT_TXTMOD_DIRECTORYNAME:
533 entry = gtk_file_chooser_button_new(f[colnum].desc,
534 (f[colnum].mode == PT_TXTMOD_FILENAME) ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
535 if (! dd->is_new || copy) {
536 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(entry), text);
540 * Some versions of GTK+ will crash if fc_filename is NULL.
541 * Make sure we have a valid location set.
543 fc_filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(entry));
545 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(entry), get_datafile_dir());
549 g_ptr_array_add(dd->entries, entry);
550 ws_gtk_grid_attach_defaults(GTK_GRID(main_grid), entry, 1, colnum, 1, 1);
554 case PT_TXTMOD_STRING:
555 case PT_TXTMOD_HEXBYTES:
556 entry = gtk_entry_new();
557 if (! dd->is_new || copy) {
558 gtk_entry_set_text(GTK_ENTRY(entry), text);
560 g_ptr_array_add(dd->entries, entry);
561 ws_gtk_grid_attach_defaults(GTK_GRID(main_grid), entry, 1, colnum, 1, 1);
562 if (f[colnum].mode != PT_TXTMOD_NONE)
563 dlg_set_activate(entry, bt_ok);
565 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
568 case PT_TXTMOD_ENUM: {
569 GtkWidget *combo_box;
571 const value_string *enum_vals = (const value_string *)f[colnum].fld_data;
572 int *valptr = (int *)g_malloc(sizeof(int)); /* A place to store the index of the */
573 /* "active" fld_data array entry */
574 /* -1 means "nothing selected (active)" */
575 combo_box = gtk_combo_box_text_new();
577 for (idx = 0; enum_vals[idx].strptr != NULL; idx++) {
578 const char *str = enum_vals[idx].strptr;
579 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(combo_box), str);
581 if ( g_str_equal(str, text) ) {
586 g_ptr_array_add(dd->entries, valptr);
587 g_ptr_array_add(dd->tobe_freed, valptr);
590 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), *valptr);
592 g_signal_connect(combo_box, "changed", G_CALLBACK(fld_combo_box_changed_cb), valptr);
593 ws_gtk_grid_attach_defaults(GTK_GRID(main_grid), combo_box, 1, colnum, 1, 1);
598 g_assert_not_reached();
604 gtk_widget_grab_default(bt_ok);
605 gtk_widget_show_all(win);
614 static void uat_del_cb(GtkButton *button _U_, gpointer u) {
615 struct _uat_del *ud = (struct _uat_del *)u;
619 uat_remove_record_idx(ud->uat, ud->idx);
622 path = gtk_tree_path_new_from_indices(ud->idx, -1);
623 if (path && gtk_tree_model_get_iter(GTK_TREE_MODEL(ud->uat->rep->list_store), &iter, path)) {
624 gtk_list_store_remove(ud->uat->rep->list_store, &iter);
628 ud->uat->changed = TRUE;
629 set_buttons(ud->uat, -1);
631 window_destroy(GTK_WIDGET(ud->win));
634 window_present(GTK_WIDGET(ud->uat->rep->window));
639 static void uat_cancel_del_cb(GtkButton *button _U_, gpointer u) {
640 struct _uat_del *ud = (struct _uat_del *)u;
642 window_destroy(GTK_WIDGET(ud->win));
644 /* Reset the buttons */
645 set_buttons(ud->uat, ud->uat->rep ? ud->uat->rep->selected : -1);
648 window_present(GTK_WIDGET(ud->uat->rep->window));
652 static void uat_del_dlg(uat_t *uat, int idx) {
653 GtkWidget *win, *main_grid, *main_vb, *bbox, *bt_cancel, *bt_ok;
654 uat_field_t *f = uat->fields;
656 void *rec = UAT_INDEX_PTR(uat, idx);
659 struct _uat_del *ud = (struct _uat_del *)g_malloc(sizeof(struct _uat_del));
661 /* Only allow a single operation at a time, prevents bug 9129 */
666 tmp_str = g_strdup_printf("%s: Confirm Delete", uat->name);
667 ud->win = win = dlg_conf_window_new(tmp_str);
670 gtk_window_set_resizable(GTK_WINDOW(win), FALSE);
671 gtk_window_resize(GTK_WINDOW(win), 400, 25*(uat->ncols+2));
673 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
674 gtk_container_add(GTK_CONTAINER(win), main_vb);
675 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 6);
677 main_grid = ws_gtk_grid_new();
678 gtk_box_pack_start(GTK_BOX(main_vb), main_grid, FALSE, FALSE, 0);
679 ws_gtk_grid_set_row_spacing(GTK_GRID(main_grid), 10);
680 ws_gtk_grid_set_column_spacing(GTK_GRID(main_grid), 15);
682 for ( colnum = 0; colnum < uat->ncols; colnum++ ) {
684 char *text = fld_tostr(rec, &(f[colnum]));
686 tmp_str = g_strdup_printf("%s:", f[colnum].title);
687 label = gtk_label_new(tmp_str);
688 gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
689 ws_gtk_grid_attach_defaults(GTK_GRID(main_grid), label, 0, colnum, 1, 1);
692 label = gtk_label_new(text);
693 gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
694 ws_gtk_grid_attach_defaults(GTK_GRID(main_grid), label, 1, colnum, 1, 1);
698 bbox = dlg_button_row_new(GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL);
699 gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
701 bt_ok = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_DELETE);
702 g_signal_connect(bt_ok, "clicked", G_CALLBACK(uat_del_cb), ud);
704 bt_cancel = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
705 g_signal_connect(bt_cancel, "clicked", G_CALLBACK(uat_cancel_del_cb), ud);
706 window_set_cancel_button( win, bt_cancel, NULL);
708 gtk_widget_show_all(win);
711 static void uat_new_cb(GtkButton *button _U_, gpointer u) {
712 uat_t *uat = (uat_t *)u;
714 if (! uat->rep) return;
716 uat_edit_dialog(uat, -1, FALSE);
719 static void uat_edit_cb(GtkWidget *button _U_, gpointer u) {
720 uat_t *uat = (uat_t *)u;
722 if (! uat->rep) return;
724 uat_edit_dialog(uat, uat->rep->selected, FALSE);
727 static void uat_copy_cb(GtkWidget *button _U_, gpointer u) {
728 uat_t *uat = (uat_t *)u;
730 if (! uat->rep) return;
732 uat_edit_dialog(uat, uat->rep->selected, TRUE);
735 static void uat_double_click_cb(GtkWidget *tv, GtkTreePath *path _U_, GtkTreeViewColumn *column _U_, gpointer u) {
739 static void uat_delete_cb(GtkButton *button _U_, gpointer u) {
740 uat_t *uat = (uat_t *)u;
742 if (! uat->rep) return;
744 uat_del_dlg(uat, uat->rep->selected);
747 static gboolean uat_window_delete_event_cb(GtkWindow *w _U_, GdkEvent *e _U_, gpointer u) {
748 uat_t *uat = (uat_t *)u;
751 void *rep = uat->rep;
753 g_signal_handlers_disconnect_by_func(uat->rep->window, uat_window_delete_event_cb, uat);
754 g_signal_handlers_disconnect_by_func(uat->rep->window, unsaved_dialog, uat);
756 gtk_widget_destroy(uat->rep->window);
764 static void uat_up_cb(GtkButton *button _U_, gpointer u) {
765 uat_t *uat = (uat_t *)u;
766 gint row = uat->rep->selected;
770 uat_swap(uat, row, row-1);
771 tree_view_list_store_move_selection(uat->rep->list, TRUE);
776 uat->rep->selected = row;
777 set_buttons(uat, row);
780 static void uat_down_cb(GtkButton *button _U_, gpointer u) {
781 uat_t *uat = (uat_t *)u;
782 gint row = uat->rep->selected;
784 g_assert(row >= 0 && (guint) row < uat->raw_data->len - 1);
786 uat_swap(uat, row, row+1);
787 tree_view_list_store_move_selection(uat->rep->list, FALSE);
792 uat->rep->selected = row;
793 set_buttons(uat, row);
796 static void uat_apply_changes(uat_t *uat) {
797 if (uat->flags & UAT_AFFECTS_FIELDS) {
798 /* Recreate list with new fields and redissect packets */
799 main_fields_changed ();
801 if (uat->flags & UAT_AFFECTS_DISSECTION) {
802 /* Just redissect packets if we have any */
803 if (cfile.state != FILE_CLOSED) {
804 redissect_packets ();
805 redissect_all_packet_windows ();
811 static void uat_cancel_cb(GtkWidget *button _U_, gpointer u) {
812 uat_t *uat = (uat_t *)u;
817 if (!uat_load(uat, &err)) {
818 report_failure("Error while loading %s: %s", uat->name, err);
822 uat_apply_changes (uat);
825 g_signal_handlers_disconnect_by_func(uat->rep->window, uat_window_delete_event_cb, uat);
826 g_signal_handlers_disconnect_by_func(uat->rep->window, unsaved_dialog, uat);
827 gtk_widget_destroy(uat->rep->window);
832 static void uat_apply_cb(GtkButton *button _U_, gpointer u) {
833 uat_t *uat = (uat_t *)u;
836 if (uat->post_update_cb) uat->post_update_cb();
837 uat_apply_changes (uat);
841 static void uat_ok_cb(GtkButton *button _U_, gpointer u) {
842 uat_t *uat = (uat_t *)u;
846 if (!uat_save(uat, &err)) {
847 report_failure("Error while saving %s: %s", uat->name, err);
851 if (uat->post_update_cb) uat->post_update_cb();
852 uat_apply_changes (uat);
855 g_signal_handlers_disconnect_by_func(uat->rep->window, uat_window_delete_event_cb, uat);
856 g_signal_handlers_disconnect_by_func(uat->rep->window, unsaved_dialog, uat);
857 gtk_widget_destroy(uat->rep->window);
862 static void uat_clear_cb(GtkButton *button _U_, gpointer u) {
863 uat_t *uat = (uat_t *)u;
865 gtk_list_store_clear(uat->rep->list_store);
870 static void uat_refresh_cb(GtkButton *button _U_, gpointer u) {
871 uat_t *uat = (uat_t *)u;
876 uat_clear_cb(button, u);
878 uat->from_global = TRUE;
879 success = uat_load(uat, &err);
880 uat->from_global = FALSE;
884 report_failure("Error while loading %s: %s", uat->name, err);
888 for (i = 0 ; i < uat->raw_data->len; i++) {
894 static void remember_selected_row(GtkWidget *w _U_, gpointer u) {
895 uat_t *uat = (uat_t *)u;
898 row = tree_view_list_store_get_selected_row(uat->rep->list);
899 uat->rep->selected = row;
901 gtk_widget_set_sensitive (uat->rep->bt_edit, TRUE);
902 gtk_widget_set_sensitive (uat->rep->bt_copy, uat->copy_cb ? TRUE : FALSE);
903 gtk_widget_set_sensitive(uat->rep->bt_delete, TRUE);
905 set_buttons(uat, row);
908 static void uat_yessave_cb(GtkWindow *w _U_, void *u) {
909 uat_t *uat = (uat_t *)u;
912 window_delete_event_cb(uat->rep->unsaved_window, NULL, NULL);
914 if (!uat_save(uat, &err)) {
915 report_failure("Error while saving %s: %s", uat->name, err);
919 g_signal_handlers_disconnect_by_func(uat->rep->window, uat_window_delete_event_cb, uat);
920 g_signal_handlers_disconnect_by_func(uat->rep->window, unsaved_dialog, uat);
921 window_destroy(uat->rep->window);
928 static void uat_nosave_cb(GtkWindow *w _U_, void *u) {
929 uat_t *uat = (uat_t *)u;
931 window_delete_event_cb(uat->rep->unsaved_window, NULL, NULL);
932 g_signal_handlers_disconnect_by_func(uat->rep->window, uat_window_delete_event_cb, uat);
933 g_signal_handlers_disconnect_by_func(uat->rep->window, unsaved_dialog, uat);
934 window_destroy(uat->rep->window);
940 static gboolean unsaved_dialog(GtkWindow *w _U_, GdkEvent *e _U_, gpointer u) {
941 GtkWidget *win, *vbox, *label, *bbox;
942 GtkWidget *yes_bt, *no_bt;
944 uat_t *uat = (uat_t *)u;
946 if (uat->rep->unsaved_window) {
947 window_present(uat->rep->unsaved_window);
951 uat->rep->unsaved_window = win = dlg_conf_window_new("Discard Changes?");
952 gtk_window_set_default_size(GTK_WINDOW(win), 360, 140);
954 gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER_ON_PARENT);
955 vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 12, FALSE);
956 gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
957 gtk_container_add(GTK_CONTAINER(win), vbox);
959 message = g_strdup_printf("Changes to '%s' are not being saved.\n"
960 "Do you want to save '%s'?", uat->name, uat->name);
962 label = gtk_label_new(message);
965 bbox = dlg_button_row_new(GTK_STOCK_YES, GTK_STOCK_NO, NULL);
967 yes_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_YES);
968 no_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_NO);
970 g_signal_connect(no_bt, "clicked", G_CALLBACK(uat_nosave_cb), uat);
971 g_signal_connect(yes_bt, "clicked", G_CALLBACK(uat_yessave_cb), uat);
973 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
974 gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
976 gtk_widget_show_all(win);
982 static void uat_help_cb(GtkWidget *w _U_, gpointer u) {
983 gchar *help_page, *url;
985 help_page = g_strdup_printf("%s.html", ((uat_t*)u)->help);
986 url = user_guide_url(help_page);
988 browser_open_url(url);
994 static GtkWidget *uat_window(void *u) {
995 uat_t *uat = (uat_t *)u;
996 uat_field_t *f = uat->fields;
1001 GtkWidget *hbox, *vbox, *move_hbox, *edit_hbox, *refresh_hbox;
1002 GtkTreeViewColumn *column;
1003 GtkCellRenderer *renderer;
1004 GtkTreeSelection *selection;
1005 gchar *global_fname;
1006 gboolean global_file_exists;
1009 window_present(uat->rep->window);
1010 return uat->rep->window;
1012 uat->rep = rep = (uat_rep_t *)g_malloc0(sizeof(uat_rep_t));
1015 global_fname = get_datafile_path(uat->filename);
1016 global_file_exists = file_exists(global_fname);
1017 g_free (global_fname);
1019 rep->window = dlg_conf_window_new(uat->name);
1021 gtk_window_set_default_size(GTK_WINDOW(rep->window), 720, 512);
1022 gtk_window_set_position(GTK_WINDOW(rep->window), GTK_WIN_POS_CENTER_ON_PARENT);
1024 gtk_container_set_border_width(GTK_CONTAINER(rep->window), 6);
1026 rep->vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 12, FALSE);
1027 gtk_container_set_border_width(GTK_CONTAINER(rep->vbox), 6);
1028 gtk_container_add(GTK_CONTAINER(rep->window), rep->vbox);
1030 hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12, FALSE);
1031 gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
1032 gtk_box_pack_start(GTK_BOX(rep->vbox), hbox, TRUE, TRUE, 0);
1034 vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 12, FALSE);
1035 gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
1036 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
1038 rep->scrolledwindow = scrolled_window_new(NULL, NULL);
1039 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(rep->scrolledwindow), GTK_SHADOW_IN);
1041 col_types = (GType *)g_malloc(sizeof(GType) *uat->ncols);
1042 for ( colnum = 0; colnum < uat->ncols; colnum++ ) {
1043 col_types[colnum] = G_TYPE_STRING;
1045 rep->list_store = gtk_list_store_newv(uat->ncols, col_types);
1048 rep->list = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(rep->list_store))); /*uat->ncols */
1049 gtk_container_add(GTK_CONTAINER(rep->scrolledwindow), GTK_WIDGET(rep->list));
1050 gtk_box_pack_start(GTK_BOX(hbox), rep->scrolledwindow, TRUE, TRUE, 0);
1052 selection = gtk_tree_view_get_selection(rep->list);
1053 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
1056 for ( colnum = 0; colnum < uat->ncols; colnum++ ) {
1057 renderer = gtk_cell_renderer_text_new();
1058 column = gtk_tree_view_column_new_with_attributes(f[colnum].title,
1059 renderer, "text", colnum, NULL);
1060 gtk_tree_view_column_set_resizable (column, TRUE);
1061 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1062 gtk_tree_view_append_column (rep->list, column);
1063 if (f[colnum].desc != NULL)
1064 gtk_widget_set_tooltip_text(gtk_tree_view_column_get_button(column), f[colnum].desc);
1067 for ( i = 0 ; i < uat->raw_data->len; i++ ) {
1072 GtkWidget *help_btn;
1073 rep->bbox = dlg_button_row_new(GTK_STOCK_HELP, GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_CANCEL, NULL);
1074 help_btn = (GtkWidget *)g_object_get_data(G_OBJECT(rep->bbox), GTK_STOCK_HELP);
1075 g_signal_connect(help_btn, "clicked", G_CALLBACK(uat_help_cb), uat);
1078 rep->bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_CANCEL, NULL);
1081 move_hbox = gtk_button_box_new(GTK_ORIENTATION_VERTICAL);
1082 gtk_box_pack_start(GTK_BOX(vbox), move_hbox, TRUE, FALSE, 0);
1084 edit_hbox = gtk_button_box_new(GTK_ORIENTATION_VERTICAL);
1085 gtk_box_pack_start(GTK_BOX(vbox), edit_hbox, TRUE, FALSE, 0);
1087 refresh_hbox = gtk_button_box_new(GTK_ORIENTATION_VERTICAL);
1088 gtk_box_pack_end(GTK_BOX(vbox), refresh_hbox, TRUE, FALSE, 0);
1091 rep->bt_up = ws_gtk_button_new_from_stock(GTK_STOCK_GO_UP);
1092 gtk_widget_set_tooltip_text(rep->bt_up, "Move selected entry up");
1094 rep->bt_down = ws_gtk_button_new_from_stock(GTK_STOCK_GO_DOWN);
1095 gtk_widget_set_tooltip_text(rep->bt_down, "Move selected entry down");
1097 gtk_box_pack_start(GTK_BOX(move_hbox), rep->bt_up, TRUE, FALSE, 5);
1098 gtk_box_pack_start(GTK_BOX(move_hbox), rep->bt_down, TRUE, FALSE, 5);
1101 rep->bt_new = ws_gtk_button_new_from_stock(GTK_STOCK_NEW);
1102 gtk_widget_set_tooltip_text(rep->bt_new, "Create a new entry");
1104 rep->bt_edit = ws_gtk_button_new_from_stock(WIRESHARK_STOCK_EDIT);
1105 gtk_widget_set_tooltip_text(rep->bt_edit, "Edit selected entry");
1107 rep->bt_copy = ws_gtk_button_new_from_stock(GTK_STOCK_COPY);
1108 gtk_widget_set_tooltip_text(rep->bt_copy, "Copy selected entry");
1110 rep->bt_delete = ws_gtk_button_new_from_stock(GTK_STOCK_DELETE);
1111 gtk_widget_set_tooltip_text(rep->bt_delete, "Delete selected entry");
1113 gtk_box_pack_end(GTK_BOX(edit_hbox), rep->bt_new, TRUE, FALSE, 5);
1114 gtk_box_pack_end(GTK_BOX(edit_hbox), rep->bt_edit, TRUE, FALSE, 5);
1115 gtk_box_pack_end(GTK_BOX(edit_hbox), rep->bt_copy, TRUE, FALSE, 5);
1116 gtk_box_pack_end(GTK_BOX(edit_hbox), rep->bt_delete, TRUE, FALSE, 5);
1118 rep->bt_refresh = ws_gtk_button_new_from_stock(GTK_STOCK_REFRESH);
1119 gtk_widget_set_tooltip_text(rep->bt_refresh, "Refresh from system defaults");
1121 rep->bt_clear = ws_gtk_button_new_from_stock(GTK_STOCK_CLEAR);
1122 gtk_widget_set_tooltip_text(rep->bt_clear, "Delete all entries");
1124 gtk_box_pack_end(GTK_BOX(refresh_hbox), rep->bt_refresh, TRUE, FALSE, 5);
1125 gtk_box_pack_end(GTK_BOX(refresh_hbox), rep->bt_clear, TRUE, FALSE, 5);
1128 rep->bt_apply = (GtkWidget *)g_object_get_data(G_OBJECT(rep->bbox), GTK_STOCK_APPLY);
1129 rep->bt_cancel = (GtkWidget *)g_object_get_data(G_OBJECT(rep->bbox), GTK_STOCK_CANCEL);
1130 rep->bt_ok = (GtkWidget *)g_object_get_data(G_OBJECT(rep->bbox), GTK_STOCK_OK);
1132 gtk_box_pack_end(GTK_BOX(rep->vbox), rep->bbox, FALSE, FALSE, 0);
1134 gtk_widget_set_sensitive (rep->bt_up, FALSE);
1135 gtk_widget_set_sensitive (rep->bt_down, FALSE);
1136 gtk_widget_set_sensitive (rep->bt_edit, FALSE);
1137 gtk_widget_set_sensitive (rep->bt_copy, FALSE);
1138 gtk_widget_set_sensitive (rep->bt_delete, FALSE);
1139 gtk_widget_set_sensitive (rep->bt_refresh, global_file_exists);
1141 g_signal_connect(rep->list, "row-activated", G_CALLBACK(uat_double_click_cb), uat);
1142 g_signal_connect(selection, "changed", G_CALLBACK(remember_selected_row), uat);
1145 g_signal_connect(rep->bt_new, "clicked", G_CALLBACK(uat_new_cb), uat);
1146 g_signal_connect(rep->bt_edit, "clicked", G_CALLBACK(uat_edit_cb), uat);
1147 g_signal_connect(rep->bt_copy, "clicked", G_CALLBACK(uat_copy_cb), uat);
1148 g_signal_connect(rep->bt_delete, "clicked", G_CALLBACK(uat_delete_cb), uat);
1150 g_signal_connect(rep->bt_refresh, "clicked", G_CALLBACK(uat_refresh_cb), uat);
1151 g_signal_connect(rep->bt_clear, "clicked", G_CALLBACK(uat_clear_cb), uat);
1153 g_signal_connect(rep->bt_up, "clicked", G_CALLBACK(uat_up_cb), uat);
1154 g_signal_connect(rep->bt_down, "clicked", G_CALLBACK(uat_down_cb), uat);
1156 g_signal_connect(rep->bt_apply, "clicked", G_CALLBACK(uat_apply_cb), uat);
1157 g_signal_connect(rep->bt_cancel, "clicked", G_CALLBACK(uat_cancel_cb), uat);
1158 g_signal_connect(rep->bt_ok, "clicked", G_CALLBACK(uat_ok_cb), uat);
1160 window_set_cancel_button(rep->window, rep->bt_cancel, NULL); /*set esc to activate cancel button */
1163 g_signal_connect(GTK_WINDOW(rep->window), "delete_event", G_CALLBACK(unsaved_dialog), uat);
1164 g_signal_connect(GTK_WINDOW(rep->window), "destroy", G_CALLBACK(unsaved_dialog), uat);
1166 g_signal_connect(GTK_WINDOW(rep->window), "delete_event", G_CALLBACK(uat_window_delete_event_cb), uat);
1167 g_signal_connect(GTK_WINDOW(rep->window), "destroy", G_CALLBACK(uat_window_delete_event_cb), uat);
1170 gtk_widget_grab_focus(GTK_WIDGET(rep->list));
1172 gtk_widget_show_all(rep->window);
1173 window_present(rep->window);
1178 void uat_window_cb(GtkWidget *u _U_, void *uat) {
1183 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1188 * indent-tabs-mode: t
1191 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1192 * :indentSize=8:tabSize=8:noTabs=false: