6 * User Accessible Tables GUI
7 * Mantain an array of user accessible data strucures
9 * (c) 2007, Luis E. Garcia Ontanon <luis@ontanon.org>
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 2001 Gerald Combs
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 * - field value check (red/green editbox)
34 * - tooltips (add field descriptions)
35 * - Make cells editable
36 * - Allow reordering via drag and drop
48 #include <gdk/gdkkeysyms.h>
49 #if GTK_CHECK_VERSION(3,0,0)
50 # include <gdk/gdkkeysyms-compat.h>
53 #include <epan/dfilter/dfilter-macro.h>
54 #include <epan/emem.h>
55 #include <epan/report_err.h>
56 #include <epan/proto.h>
57 #include <epan/packet.h>
58 #include <epan/uat-int.h>
59 #include <epan/value_string.h>
61 #include "../stat_menu.h"
63 #include "gtk/gtkglobals.h"
64 #include "gtk/gui_utils.h"
65 #include "gtk/dlg_utils.h"
66 #include "gtk/help_dlg.h"
67 #include "gtk/stock_icons.h"
68 #include "gtk/gui_stat_menu.h"
70 #include "gtk/uat_gui.h"
71 #include "gtk/old-gtk-compat.h"
73 # define BUTTON_SIZE_X -1
74 # define BUTTON_SIZE_Y -1
79 GtkWidget* scrolledwindow;
81 GtkListStore *list_store;
92 GtkWidget* unsaved_window;
96 GtkTreeSelection *selection;
104 struct _uat_dlg_data {
111 GPtrArray* tobe_freed;
115 static gboolean unsaved_dialog(GtkWindow *w, GdkEvent* e, gpointer u);
116 static gboolean uat_window_delete_event_cb(GtkWindow *w, GdkEvent* e, gpointer u);
118 static void set_buttons(uat_t* uat, gint row) {
120 if (!uat->rep) return;
123 gtk_widget_set_sensitive (uat->rep->bt_up, TRUE);
125 gtk_widget_set_sensitive (uat->rep->bt_up, FALSE);
128 if (row < (gint)(*uat->nrows_p - 1) && row >= 0) {
129 gtk_widget_set_sensitive (uat->rep->bt_down, TRUE);
131 gtk_widget_set_sensitive (uat->rep->bt_down, FALSE);
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);
141 g_signal_handlers_disconnect_by_func(uat->rep->window, uat_window_delete_event_cb, uat);
142 g_signal_connect(uat->rep->window, "delete_event", G_CALLBACK(unsaved_dialog), uat);
143 g_signal_connect(uat->rep->window, "destroy", G_CALLBACK(unsaved_dialog), uat);
145 g_signal_handlers_disconnect_by_func(uat->rep->window, unsaved_dialog, uat);
146 g_signal_connect(GTK_WINDOW(uat->rep->window), "delete_event", G_CALLBACK(uat_window_delete_event_cb), uat);
147 g_signal_connect(GTK_WINDOW(uat->rep->window), "destroy", G_CALLBACK(uat_window_delete_event_cb), uat);
151 static char* fld_tostr(void* rec, uat_field_t* f) {
156 f->cb.tostr(rec,&ptr,&len,f->cbdata.tostr,f->fld_data);
159 case PT_TXTMOD_STRING:
161 case PT_TXTMOD_FILENAME:
162 case PT_TXTMOD_DIRECTORYNAME:
163 out = ep_strndup(ptr,len);
165 case PT_TXTMOD_HEXBYTES: {
166 GString* s = g_string_sized_new( len*2 + 1 );
169 for (i=0; i<len;i++) g_string_append_printf(s,"%.2X",((guint8*)ptr)[i]);
171 out = ep_strdup(s->str);
173 g_string_free(s,TRUE);
177 g_assert_not_reached();
187 static void append_row(uat_t* uat, guint idx) {
188 GPtrArray* a = g_ptr_array_new();
189 void* rec = UAT_INDEX_PTR(uat,idx);
190 uat_field_t* f = uat->fields;
194 if (! uat->rep) return;
196 /* gtk_clist_freeze(GTK_CLIST(uat->rep->clist)); */
198 gtk_list_store_insert_before(uat->rep->list_store, &iter, NULL);
199 for ( colnum = 0; colnum < uat->ncols; colnum++ ) {
200 g_ptr_array_add(a,fld_tostr(rec,&(f[colnum])));
201 gtk_list_store_set(uat->rep->list_store, &iter, colnum, fld_tostr(rec,&(f[colnum])), -1);
205 /* rownum = gtk_clist_append(GTK_CLIST(uat->rep->clist), (gchar**)a->pdata);
206 gtk_clist_set_row_data(GTK_CLIST(uat->rep->clist), rownum, rec); */
208 /* gtk_clist_thaw(GTK_CLIST(uat->rep->clist)); */
210 g_ptr_array_free(a,TRUE);
213 static void reset_row(uat_t* uat, guint idx) {
214 void* rec = UAT_INDEX_PTR(uat,idx);
215 uat_field_t* f = uat->fields;
220 if (! uat->rep) return;
222 /* gtk_clist_freeze(GTK_CLIST(uat->rep->clist)); */
224 path = gtk_tree_path_new_from_indices(idx, -1);
225 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(uat->rep->list_store), &iter, path)) {
229 for ( colnum = 0; colnum < uat->ncols; colnum++ ) {
230 gtk_list_store_set(uat->rep->list_store, &iter, colnum, fld_tostr(rec,&(f[colnum])), -1);
231 /* gtk_clist_set_text(GTK_CLIST(uat->rep->clist), idx, colnum, fld_tostr(rec,&(f[colnum]))); */
234 /* gtk_clist_thaw(GTK_CLIST(uat->rep->clist)); */
238 static guint8* unhexbytes(const char* si, guint len, guint* len_p, const char** err) {
241 const guint8* s = (void*)si;
245 *err = "Uneven number of chars hex string";
249 buf = ep_alloc(len/2+1);
252 for (i = 0; i<len ; i += 2) {
256 if (hi >= '0' && hi <= '9') {
258 } else if (hi >= 'a' && hi <= 'f') {
261 } else if (hi >= 'A' && hi <= 'F') {
268 if (lo >= '0' && lo <= '9') {
270 } else if (lo >= 'a' && lo <= 'f') {
273 } else if (lo >= 'A' && lo <= 'F') {
280 *(p++) = (hi*0x10) + lo;
285 if (len_p) *len_p = len;
293 *err = "Error parsing hex string";
298 static gboolean uat_dlg_cb(GtkWidget *win _U_, gpointer user_data) {
299 struct _uat_dlg_data* dd = user_data;
300 guint ncols = dd->uat->ncols;
301 uat_field_t* f = dd->uat->fields;
302 const char* err = NULL;
305 for ( colnum = 0; colnum < ncols; colnum++ ) {
306 void* e = g_ptr_array_index(dd->entries,colnum);
307 const char *text = NULL;
308 char *text_free = NULL;
311 switch(f[colnum].mode) {
312 case PT_TXTMOD_FILENAME:
313 case PT_TXTMOD_DIRECTORYNAME:
314 text = text_free = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(e));
316 len = (unsigned) strlen(text);
323 case PT_TXTMOD_STRING:
324 text = gtk_entry_get_text(GTK_ENTRY(e));
325 len = (unsigned) strlen(text);
327 case PT_TXTMOD_HEXBYTES: {
328 text = gtk_entry_get_text(GTK_ENTRY(e));
330 text = (void*) unhexbytes(text, (guint) strlen(text), &len, &err);
333 err = ep_strdup_printf("error in field '%s': %s",f[colnum].title,err);
339 case PT_TXTMOD_ENUM: {
341 text = (idx >= 0) ? ((value_string *)(f[colnum].fld_data))[idx].strptr : "";
342 len = (unsigned) strlen(text);
346 g_assert_not_reached();
350 if (f[colnum].cb.chk) {
351 if (! f[colnum].cb.chk(dd->rec, text, len, f[colnum].cbdata.chk, f[colnum].fld_data, &err)) {
352 err = ep_strdup_printf("error in column '%s': %s",f[colnum].title,err);
357 f[colnum].cb.set(dd->rec,text,len, f[colnum].cbdata.set, f[colnum].fld_data);
362 if (dd->uat->update_cb) {
363 dd->uat->update_cb(dd->rec,&err);
366 err = ep_strdup_printf("error updating record: %s",err);
372 void* rec_tmp = dd->rec;
373 dd->rec = uat_add_record(dd->uat, dd->rec);
375 if (dd->uat->free_cb) {
376 dd->uat->free_cb(rec_tmp);
382 dd->uat->changed = TRUE;
384 set_buttons(dd->uat, dd->uat->rep ? dd->uat->rep->selected : -1);
387 append_row(dd->uat, (*dd->uat->nrows_p) - 1 );
389 reset_row(dd->uat,dd->row);
392 g_ptr_array_free(dd->entries,TRUE);
393 window_destroy(GTK_WIDGET(dd->win));
396 window_present(GTK_WIDGET(dd->uat->rep->window));
398 while (dd->tobe_freed->len) g_free( g_ptr_array_remove_index_fast(dd->tobe_freed, dd->tobe_freed->len - 1 ) );
405 report_failure("%s",err);
409 static gboolean uat_cancel_dlg_cb(GtkWidget *win _U_, gpointer user_data) {
410 struct _uat_dlg_data* dd = user_data;
413 window_present(GTK_WIDGET(dd->uat->rep->window));
415 if (dd->is_new) g_free(dd->rec);
416 g_ptr_array_free(dd->entries,TRUE);
417 window_destroy(GTK_WIDGET(dd->win));
419 while (dd->tobe_freed->len) g_free( g_ptr_array_remove_index_fast(dd->tobe_freed, dd->tobe_freed->len - 1 ) );
426 static void fld_combo_box_changed_cb(GtkComboBox *combo_box, gpointer user_data) {
427 int* valptr = user_data;
428 *valptr = gtk_combo_box_get_active(combo_box);
431 static void uat_edit_dialog(uat_t* uat, gint row, gboolean copy) {
432 GtkWidget *win, *main_tb, *main_vb, *bbox, *bt_cancel, *bt_ok;
433 struct _uat_dlg_data* dd = g_malloc(sizeof(struct _uat_dlg_data));
434 uat_field_t* f = uat->fields;
437 dd->entries = g_ptr_array_new();
438 dd->win = dlg_conf_window_new(ep_strdup_printf("%s: %s", uat->name, (row == -1 ? "New" : "Edit")));
440 if (copy && row >= 0) {
441 dd->rec = g_malloc0(uat->record_size);
443 uat->copy_cb (dd->rec, UAT_INDEX_PTR(uat,row), uat->record_size);
446 } else if (row >= 0) {
447 dd->rec = UAT_INDEX_PTR(uat,row);
450 dd->rec = g_malloc0(uat->record_size);
454 dd->tobe_freed = g_ptr_array_new();
458 gtk_window_set_resizable(GTK_WINDOW(win),FALSE);
459 gtk_window_resize(GTK_WINDOW(win),400, 30*(uat->ncols+2));
461 main_vb = gtk_vbox_new(FALSE,5);
462 gtk_container_add(GTK_CONTAINER(win), main_vb);
463 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 6);
465 main_tb = gtk_table_new(uat->ncols+1, 2, FALSE);
466 gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
467 gtk_table_set_row_spacings(GTK_TABLE(main_tb), 5);
468 gtk_table_set_col_spacings(GTK_TABLE(main_tb), 10);
470 bbox = dlg_button_row_new(GTK_STOCK_CANCEL,GTK_STOCK_OK, NULL);
471 gtk_box_pack_end(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
473 bt_ok = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
474 g_signal_connect(bt_ok, "clicked", G_CALLBACK(uat_dlg_cb), dd);
476 bt_cancel = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
477 g_signal_connect(bt_cancel, "clicked", G_CALLBACK(uat_cancel_dlg_cb), dd);
478 window_set_cancel_button(win, bt_cancel, NULL);
480 for ( colnum = 0; colnum < uat->ncols; colnum++ ) {
481 GtkWidget *entry, *label, *event_box;
482 char* text = fld_tostr(dd->rec,&(f[colnum]));
484 event_box = gtk_event_box_new();
486 label = gtk_label_new(ep_strdup_printf("%s:", f[colnum].title));
487 if (f[colnum].desc != NULL)
488 gtk_widget_set_tooltip_text(event_box, f[colnum].desc);
490 gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
491 gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 0, 1, colnum+1, colnum + 2);
492 gtk_container_add(GTK_CONTAINER(event_box), label);
494 switch(f[colnum].mode) {
495 case PT_TXTMOD_FILENAME:
496 case PT_TXTMOD_DIRECTORYNAME:
497 entry = gtk_file_chooser_button_new(f[colnum].desc,
498 (f[colnum].mode == PT_TXTMOD_FILENAME) ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
499 if (! dd->is_new || copy) {
500 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(entry), text);
502 g_ptr_array_add(dd->entries,entry);
503 gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2, colnum+1, colnum + 2);
506 case PT_TXTMOD_STRING:
507 case PT_TXTMOD_HEXBYTES:
508 entry = gtk_entry_new();
509 if (! dd->is_new || copy) {
510 gtk_entry_set_text(GTK_ENTRY(entry),text);
512 g_ptr_array_add(dd->entries,entry);
513 gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2, colnum+1, colnum + 2);
514 dlg_set_activate(entry, bt_ok);
517 case PT_TXTMOD_ENUM: {
518 GtkWidget *combo_box;
520 const value_string* enum_vals = f[colnum].fld_data;
521 int* valptr = g_malloc(sizeof(int)); /* A place to store the index of the */
522 /* "active" fld_data array entry */
523 /* -1 means "nothing selected (active)" */
524 combo_box = gtk_combo_box_text_new();
526 for (idx = 0; enum_vals[idx].strptr != NULL; idx++) {
527 const char* str = enum_vals[idx].strptr;
528 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(combo_box), str);
530 if ( g_str_equal(str, text) ) {
535 g_ptr_array_add(dd->entries,valptr);
536 g_ptr_array_add(dd->tobe_freed,valptr);
539 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), *valptr);
541 g_signal_connect(combo_box, "changed", G_CALLBACK(fld_combo_box_changed_cb), valptr);
542 gtk_table_attach_defaults(GTK_TABLE(main_tb), combo_box, 1, 2, colnum+1, colnum + 2);
547 g_assert_not_reached();
552 gtk_widget_grab_default(bt_ok);
553 gtk_widget_show_all(win);
562 static void uat_del_cb(GtkButton *button _U_, gpointer u) {
563 struct _uat_del* ud = u;
567 uat_remove_record_idx(ud->uat, ud->idx);
570 path = gtk_tree_path_new_from_indices(ud->idx, -1);
571 if (path && gtk_tree_model_get_iter(GTK_TREE_MODEL(ud->uat->rep->list_store), &iter, path)) {
572 gtk_list_store_remove(ud->uat->rep->list_store, &iter);
574 /* gtk_clist_remove(GTK_CLIST(ud->uat->rep->clist),ud->idx); */
577 ud->uat->changed = TRUE;
578 set_buttons(ud->uat,-1);
580 window_destroy(GTK_WIDGET(ud->win));
583 window_present(GTK_WIDGET(ud->uat->rep->window));
588 static void uat_cancel_del_cb(GtkButton *button _U_, gpointer u) {
589 struct _uat_del* ud = u;
590 window_destroy(GTK_WIDGET(ud->win));
593 window_present(GTK_WIDGET(ud->uat->rep->window));
597 static void uat_del_dlg(uat_t* uat, int idx) {
598 GtkWidget *win, *main_tb, *main_vb, *bbox, *bt_cancel, *bt_ok;
599 uat_field_t* f = uat->fields;
601 void* rec = UAT_INDEX_PTR(uat,idx);
602 struct _uat_del* ud = g_malloc(sizeof(struct _uat_del));
606 ud->win = win = dlg_conf_window_new(ep_strdup_printf("%s: Confirm Delete", uat->name));
608 gtk_window_set_resizable(GTK_WINDOW(win),FALSE);
609 gtk_window_resize(GTK_WINDOW(win),400,25*(uat->ncols+2));
611 main_vb = gtk_vbox_new(FALSE,5);
612 gtk_container_add(GTK_CONTAINER(win), main_vb);
613 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 6);
615 main_tb = gtk_table_new(uat->ncols+1, 2, FALSE);
616 gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
617 gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
618 gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
620 for ( colnum = 0; colnum < uat->ncols; colnum++ ) {
622 char* text = fld_tostr(rec,&(f[colnum]));
624 label = gtk_label_new(ep_strdup_printf("%s:", f[colnum].title));
625 gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
626 gtk_table_attach_defaults(GTK_TABLE(main_tb), label, 0, 1, colnum+1, colnum + 2);
628 label = gtk_label_new(text);
629 gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
630 gtk_table_attach_defaults(GTK_TABLE(main_tb), label, 1, 2, colnum+1, colnum + 2);
633 bbox = dlg_button_row_new(GTK_STOCK_CANCEL,GTK_STOCK_DELETE, NULL);
634 gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
636 bt_ok = g_object_get_data(G_OBJECT(bbox),GTK_STOCK_DELETE);
637 g_signal_connect(bt_ok, "clicked", G_CALLBACK(uat_del_cb), ud);
639 bt_cancel = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
640 g_signal_connect(bt_cancel, "clicked", G_CALLBACK(uat_cancel_del_cb), ud);
641 window_set_cancel_button( win, bt_cancel, NULL);
643 gtk_widget_show_all(win);
646 static void uat_new_cb(GtkButton *button _U_, gpointer u) {
649 if (! uat->rep) return;
651 uat_edit_dialog(uat, -1, FALSE);
654 static void uat_edit_cb(GtkWidget *button _U_, gpointer u) {
657 if (! uat->rep) return;
659 uat_edit_dialog(uat, uat->rep->selected, FALSE);
662 static void uat_copy_cb(GtkWidget *button _U_, gpointer u) {
665 if (! uat->rep) return;
667 uat_edit_dialog(uat, uat->rep->selected, TRUE);
670 static void uat_double_click_cb(GtkWidget *tv, GtkTreePath *path _U_, GtkTreeViewColumn *column _U_, gpointer u) {
674 static void uat_delete_cb(GtkButton *button _U_, gpointer u) {
677 if (! uat->rep) return;
679 uat_del_dlg(uat,uat->rep->selected);
682 static gboolean uat_window_delete_event_cb(GtkWindow *w _U_, GdkEvent* e _U_, gpointer u) {
686 void* rep = uat->rep;
688 g_signal_handlers_disconnect_by_func(uat->rep->window, uat_window_delete_event_cb, uat);
689 g_signal_handlers_disconnect_by_func(uat->rep->window, unsaved_dialog, uat);
691 gtk_widget_destroy(uat->rep->window);
699 static void uat_up_cb(GtkButton *button _U_, gpointer u) {
701 gint row = uat->rep->selected;
705 uat_swap(uat,row,row-1);
706 tree_view_list_store_move_selection(uat->rep->list, TRUE);
707 /* gtk_clist_swap_rows(GTK_CLIST(uat->rep->clist),row,row-1); */
712 uat->rep->selected = row;
713 set_buttons(uat,row);
716 static void uat_down_cb(GtkButton *button _U_, gpointer u) {
718 gint row = uat->rep->selected;
720 g_assert(row >= 0 && (guint) row < *uat->nrows_p - 1);
722 uat_swap(uat,row,row+1);
723 tree_view_list_store_move_selection(uat->rep->list, FALSE);
724 /* gtk_clist_swap_rows(GTK_CLIST(uat->rep->clist),row,row+1); */
729 uat->rep->selected = row;
730 set_buttons(uat,row);
733 static void uat_cancel_cb(GtkWidget *button _U_, gpointer u) {
742 report_failure("Error while loading %s: %s",uat->name,err);
745 redissect_packets ();
748 g_signal_handlers_disconnect_by_func(uat->rep->window, uat_window_delete_event_cb, uat);
749 g_signal_handlers_disconnect_by_func(uat->rep->window, unsaved_dialog, uat);
750 gtk_widget_destroy(uat->rep->window);
755 static void uat_apply_cb(GtkButton *button _U_, gpointer u) {
759 if (uat->post_update_cb) uat->post_update_cb();
760 redissect_packets ();
764 static void uat_ok_cb(GtkButton *button _U_, gpointer u) {
772 report_failure("Error while saving %s: %s",uat->name,err);
775 if (uat->post_update_cb) uat->post_update_cb();
776 redissect_packets ();
779 g_signal_handlers_disconnect_by_func(uat->rep->window, uat_window_delete_event_cb, uat);
780 g_signal_handlers_disconnect_by_func(uat->rep->window, unsaved_dialog, uat);
781 gtk_widget_destroy(uat->rep->window);
788 static void remember_selected_row(GtkWidget *w _U_, gpointer u) {
792 row = tree_view_list_store_get_selected_row(uat->rep->list);
793 uat->rep->selected = row;
795 gtk_widget_set_sensitive (uat->rep->bt_edit, TRUE);
796 gtk_widget_set_sensitive (uat->rep->bt_copy, uat->copy_cb ? TRUE : FALSE);
797 gtk_widget_set_sensitive(uat->rep->bt_delete, TRUE);
799 set_buttons(uat,row);
802 static void uat_yessave_cb(GtkWindow *w _U_, void* u) {
806 window_delete_event_cb(uat->rep->unsaved_window,NULL,NULL);
811 report_failure("Error while saving %s: %s",uat->name,err);
814 g_signal_handlers_disconnect_by_func(uat->rep->window, uat_window_delete_event_cb, uat);
815 g_signal_handlers_disconnect_by_func(uat->rep->window, unsaved_dialog, uat);
816 window_destroy(uat->rep->window);
823 static void uat_nosave_cb(GtkWindow *w _U_, void* u) {
825 window_delete_event_cb(uat->rep->unsaved_window,NULL,NULL);
826 g_signal_handlers_disconnect_by_func(uat->rep->window, uat_window_delete_event_cb, uat);
827 g_signal_handlers_disconnect_by_func(uat->rep->window, unsaved_dialog, uat);
828 window_destroy(uat->rep->window);
834 static gboolean unsaved_dialog(GtkWindow *w _U_, GdkEvent* e _U_, gpointer u) {
835 GtkWidget *win, *vbox, *label, *bbox;
836 GtkWidget *yes_bt, *no_bt;
840 if (uat->rep->unsaved_window) {
841 window_present(uat->rep->unsaved_window);
845 uat->rep->unsaved_window = win = dlg_conf_window_new("Discard Changes?");
846 gtk_window_set_default_size(GTK_WINDOW(win), 360, 140);
848 gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER_ON_PARENT);
849 vbox = gtk_vbox_new(FALSE, 12);
850 gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
851 gtk_container_add(GTK_CONTAINER(win), vbox);
853 message = ep_strdup_printf("Changes to '%s' are not being saved!\n"
854 "Do you want to save '%s'?", uat->name, uat->name);
856 label = gtk_label_new(message);
858 bbox = dlg_button_row_new(GTK_STOCK_YES,GTK_STOCK_NO, NULL);
860 yes_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_YES);
861 no_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_NO);
863 g_signal_connect(no_bt, "clicked", G_CALLBACK(uat_nosave_cb), uat);
864 g_signal_connect(yes_bt, "clicked", G_CALLBACK(uat_yessave_cb), uat);
866 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
867 gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
869 gtk_widget_show_all(win);
875 static void uat_help_cb(GtkWidget* w _U_, gpointer u) {
876 help_topic_html(ep_strdup_printf("%s.html",((uat_t*)u)->help));
879 static GtkWidget* uat_window(void* u) {
881 uat_field_t* f = uat->fields;
886 GtkWidget *hbox, *vbox, *move_hbox, *edit_hbox;
887 GtkTreeViewColumn *column;
888 GtkCellRenderer *renderer;
889 GtkTreeSelection *selection;
892 window_present(uat->rep->window);
893 return uat->rep->window;
895 uat->rep = rep = g_malloc0(sizeof(uat_rep_t));
898 rep->window = dlg_conf_window_new(uat->name);
900 gtk_window_set_resizable(GTK_WINDOW(rep->window),TRUE);
901 gtk_window_resize(GTK_WINDOW(rep->window), 720, 512);
902 gtk_window_set_position(GTK_WINDOW(rep->window), GTK_WIN_POS_CENTER_ON_PARENT);
904 gtk_container_set_border_width(GTK_CONTAINER(rep->window), 6);
906 rep->vbox = gtk_vbox_new(FALSE, 12);
907 gtk_container_set_border_width(GTK_CONTAINER(rep->vbox), 6);
908 gtk_container_add(GTK_CONTAINER(rep->window), rep->vbox);
910 hbox = gtk_hbox_new(FALSE,12);
911 gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
912 gtk_container_add(GTK_CONTAINER(rep->vbox), hbox);
914 vbox = gtk_vbox_new(FALSE, 12);
915 gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
916 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
918 rep->scrolledwindow = scrolled_window_new(NULL, NULL);
919 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(rep->scrolledwindow), GTK_SHADOW_IN);
921 col_types = g_malloc(sizeof(GType) * uat->ncols);
922 for ( colnum = 0; colnum < uat->ncols; colnum++ ) {
923 col_types[colnum] = G_TYPE_STRING;
925 rep->list_store = gtk_list_store_newv(uat->ncols, col_types);
928 rep->list = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(rep->list_store))); /* uat->ncols */
929 gtk_container_add(GTK_CONTAINER(rep->scrolledwindow), GTK_WIDGET(rep->list));
930 gtk_box_pack_start(GTK_BOX(hbox), rep->scrolledwindow, TRUE, TRUE, 0);
932 selection = gtk_tree_view_get_selection(rep->list);
933 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
935 for ( colnum = 0; colnum < uat->ncols; colnum++ ) {
936 renderer = gtk_cell_renderer_text_new();
937 column = gtk_tree_view_column_new_with_attributes(f[colnum].title,
938 renderer, "text", colnum, NULL);
939 gtk_tree_view_column_set_resizable (column,TRUE);
940 gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE);
941 gtk_tree_view_append_column (rep->list, column);
942 if (f[colnum].desc != NULL)
943 gtk_widget_set_tooltip_text(gtk_tree_view_column_get_button(column), f[colnum].desc);
946 gtk_clist_set_column_title(GTK_CLIST(rep->clist), colnum, f[colnum].title);
947 gtk_clist_set_column_auto_resize(GTK_CLIST(rep->clist), colnum, TRUE);
952 gtk_clist_column_titles_show(GTK_CLIST(rep->clist));
953 gtk_clist_freeze(GTK_CLIST(rep->clist));
956 for ( i = 0 ; i < *(uat->nrows_p); i++ ) {
960 /* gtk_clist_thaw(GTK_CLIST(rep->clist)); */
962 /* rep->selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(rep->clist));
963 gtk_tree_selection_set_mode(rep->selection, GTK_SELECTION_SINGLE);
965 /* gtk_clist_set_selection_mode(GTK_CLIST(rep->clist), GTK_SELECTION_SINGLE); */
969 rep->bbox = dlg_button_row_new(GTK_STOCK_HELP, GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_CANCEL, NULL);
970 help_btn = g_object_get_data(G_OBJECT(rep->bbox),GTK_STOCK_HELP);
971 g_signal_connect(help_btn, "clicked", G_CALLBACK(uat_help_cb), uat);
974 rep->bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_CANCEL, NULL);
977 move_hbox = gtk_vbutton_box_new();
978 gtk_box_pack_start(GTK_BOX(vbox), move_hbox, TRUE, FALSE, 0);
980 edit_hbox = gtk_vbutton_box_new();
981 gtk_box_pack_end(GTK_BOX(vbox), edit_hbox, TRUE, FALSE, 0);
984 rep->bt_down = gtk_button_new_from_stock(GTK_STOCK_GO_DOWN);
985 rep->bt_up = gtk_button_new_from_stock(GTK_STOCK_GO_UP);
987 gtk_box_pack_start(GTK_BOX(move_hbox), rep->bt_up, TRUE, FALSE, 5);
988 gtk_box_pack_start(GTK_BOX(move_hbox), rep->bt_down, TRUE, FALSE, 5);
991 rep->bt_new = gtk_button_new_from_stock(GTK_STOCK_NEW);
992 rep->bt_edit = gtk_button_new_from_stock(WIRESHARK_STOCK_EDIT);
993 rep->bt_copy = gtk_button_new_from_stock(GTK_STOCK_COPY);
994 rep->bt_delete = gtk_button_new_from_stock(GTK_STOCK_DELETE);
996 gtk_box_pack_end(GTK_BOX(edit_hbox), rep->bt_new, TRUE, FALSE, 5);
997 gtk_box_pack_end(GTK_BOX(edit_hbox), rep->bt_edit, TRUE, FALSE, 5);
998 gtk_box_pack_end(GTK_BOX(edit_hbox), rep->bt_copy, TRUE, FALSE, 5);
999 gtk_box_pack_end(GTK_BOX(edit_hbox), rep->bt_delete, TRUE, FALSE, 5);
1002 rep->bt_apply = g_object_get_data(G_OBJECT(rep->bbox),GTK_STOCK_APPLY);
1003 rep->bt_cancel = g_object_get_data(G_OBJECT(rep->bbox),GTK_STOCK_CANCEL);
1004 rep->bt_ok = g_object_get_data(G_OBJECT(rep->bbox),GTK_STOCK_OK);
1006 gtk_box_pack_end(GTK_BOX(rep->vbox), rep->bbox, FALSE, FALSE, 0);
1008 gtk_widget_set_sensitive (rep->bt_up, FALSE);
1009 gtk_widget_set_sensitive (rep->bt_down, FALSE);
1010 gtk_widget_set_sensitive (rep->bt_edit, FALSE);
1011 gtk_widget_set_sensitive (rep->bt_copy, FALSE);
1012 gtk_widget_set_sensitive (rep->bt_delete, FALSE);
1015 /* g_signal_connect(rep->selection, "changed", G_CALLBACK(remember_selected_row), uat);*/
1016 g_signal_connect(rep->list, "row-activated", G_CALLBACK(uat_double_click_cb), uat);
1017 g_signal_connect(selection, "changed", G_CALLBACK(remember_selected_row), uat);
1020 g_signal_connect(rep->bt_new, "clicked", G_CALLBACK(uat_new_cb), uat);
1021 g_signal_connect(rep->bt_edit, "clicked", G_CALLBACK(uat_edit_cb), uat);
1022 g_signal_connect(rep->bt_copy, "clicked", G_CALLBACK(uat_copy_cb), uat);
1023 g_signal_connect(rep->bt_delete, "clicked", G_CALLBACK(uat_delete_cb), uat);
1025 g_signal_connect(rep->bt_up, "clicked", G_CALLBACK(uat_up_cb), uat);
1026 g_signal_connect(rep->bt_down, "clicked", G_CALLBACK(uat_down_cb), uat);
1028 g_signal_connect(rep->bt_apply, "clicked", G_CALLBACK(uat_apply_cb), uat);
1029 g_signal_connect(rep->bt_cancel, "clicked", G_CALLBACK(uat_cancel_cb), uat);
1030 g_signal_connect(rep->bt_ok, "clicked", G_CALLBACK(uat_ok_cb), uat);
1032 window_set_cancel_button(rep->window, rep->bt_cancel, NULL); /* set esc to activate cancel button */
1035 g_signal_connect(GTK_WINDOW(rep->window), "delete_event", G_CALLBACK(unsaved_dialog), uat);
1036 g_signal_connect(GTK_WINDOW(rep->window), "destroy", G_CALLBACK(unsaved_dialog), uat);
1038 g_signal_connect(GTK_WINDOW(rep->window), "delete_event", G_CALLBACK(uat_window_delete_event_cb), uat);
1039 g_signal_connect(GTK_WINDOW(rep->window), "destroy", G_CALLBACK(uat_window_delete_event_cb), uat);
1042 gtk_widget_grab_focus(GTK_WIDGET(rep->list));
1044 gtk_widget_show_all(rep->window);
1045 window_present(rep->window);
1050 void uat_window_cb(GtkWidget* u _U_, void* uat) {