Support putting preferences into arbitrary places in a tree, which is

used to construct the "Edit->Preferences" dialog box; this includes the
ability to register a "subtree" for preferences.  Instead of
special-casing protocol preferences, have a subtree "Protocols" for
protocol preferences.

svn path=/trunk/; revision=6808
This commit is contained in:
Guy Harris 2002-12-20 01:48:57 +00:00
parent e4633bc783
commit 392fee6d7a
4 changed files with 319 additions and 117 deletions

View File

@ -1,7 +1,7 @@
/* prefs_dlg.c /* prefs_dlg.c
* Routines for handling preferences * Routines for handling preferences
* *
* $Id: prefs_dlg.c,v 1.56 2002/11/28 01:58:27 guy Exp $ * $Id: prefs_dlg.c,v 1.57 2002/12/20 01:48:57 guy Exp $
* *
* Ethereal - Network traffic analyzer * Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com> * By Gerald Combs <gerald@ethereal.com>
@ -78,7 +78,7 @@ static void prefs_tree_select_cb(GtkTreeSelection *, gpointer);
#define E_NAMERES_PAGE_KEY "nameres_options_page" #define E_NAMERES_PAGE_KEY "nameres_options_page"
#define E_TOOLTIPS_KEY "tooltips" #define E_TOOLTIPS_KEY "tooltips"
#define FIRST_PROTO_PREFS_PAGE 6 static int first_proto_prefs_page = -1;
/* /*
* Keep a static pointer to the notebook to be able to choose the * Keep a static pointer to the notebook to be able to choose the
@ -102,14 +102,17 @@ static GtkWidget *prefs_w;
static e_prefs saved_prefs; static e_prefs saved_prefs;
struct ct_struct { struct ct_struct {
GtkWidget *main_vb;
GtkWidget *notebook; GtkWidget *notebook;
GtkWidget *tree; GtkWidget *tree;
#if GTK_MAJOR_VERSION >= 2 #if GTK_MAJOR_VERSION < 2
GtkTreeIter proto_iter;
#endif
GtkCTreeNode *node; GtkCTreeNode *node;
#else
GtkTreeIter iter;
#endif
GtkTooltips *tooltips; GtkTooltips *tooltips;
gint page; gint page;
gboolean is_protocol;
}; };
static void static void
@ -203,57 +206,108 @@ static void
module_prefs_show(module_t *module, gpointer user_data) module_prefs_show(module_t *module, gpointer user_data)
{ {
struct ct_struct *cts = user_data; struct ct_struct *cts = user_data;
struct ct_struct child_cts;
GtkWidget *main_vb, *main_tb, *frame; GtkWidget *main_vb, *main_tb, *frame;
gchar label_str[MAX_TREE_NODE_NAME_LEN]; gchar label_str[MAX_TREE_NODE_NAME_LEN];
#if GTK_MAJOR_VERSION < 2 #if GTK_MAJOR_VERSION < 2
gchar *label_ptr = label_str; gchar *label_ptr = label_str;
GtkCTreeNode *ct_node; GtkCTreeNode *ct_node;
#else #else
GtkTreeStore *model; GtkTreeStore *model;
GtkTreeIter iter; GtkTreeIter iter;
#endif #endif
/* Frame */ /*
frame = gtk_frame_new(module->title); * Add this module to the tree.
gtk_widget_show(frame); */
/* Main vertical box */
main_vb = gtk_vbox_new(FALSE, 5);
gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
gtk_container_add(GTK_CONTAINER(frame), main_vb);
/* Main table */
main_tb = gtk_table_new(module->numprefs, 2, FALSE);
gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
OBJECT_SET_DATA(main_tb, E_TOOLTIPS_KEY, cts->tooltips);
/* Add items for each of the preferences */
prefs_pref_foreach(module, pref_show, main_tb);
gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), frame, NULL);
strcpy(label_str, module->title); strcpy(label_str, module->title);
#if GTK_MAJOR_VERSION < 2 #if GTK_MAJOR_VERSION < 2
ct_node = gtk_ctree_insert_node(GTK_CTREE(cts->tree), cts->node, NULL, ct_node = gtk_ctree_insert_node(GTK_CTREE(cts->tree), cts->node, NULL,
&label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE); &label_ptr, 5, NULL, NULL, NULL, NULL, !module->is_subtree,
gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node, FALSE);
GINT_TO_POINTER(cts->page));
#else #else
model = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(cts->tree))); model = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(cts->tree)));
gtk_tree_store_append(model, &iter, &cts->proto_iter); gtk_tree_store_append(model, &iter, &cts->iter);
gtk_tree_store_set(model, &iter, 0, label_str, 1, cts->page, -1);
#endif #endif
cts->page++;
/* Show 'em what we got */ /*
gtk_widget_show_all(main_vb); * Is this a subtree?
*/
if (module->is_subtree) {
/*
* Yes.
*/
/* Note that there's no page attached to this item */
#if GTK_MAJOR_VERSION < 2
gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node,
GINT_TO_POINTER(-1));
#else
gtk_tree_store_set(model, &iter, 0, label_str, 1, -1, -1);
#endif
/*
* Walk the subtree and attach stuff to it.
*/
child_cts = *cts;
#if GTK_MAJOR_VERSION < 2
child_cts.node = ct_node;
#else
child_cts.iter = iter;
#endif
if (module == protocols_module)
child_cts.is_protocol = TRUE;
prefs_module_list_foreach(module->prefs, module_prefs_show, &child_cts);
} else {
/*
* No.
* Create a notebook page for it.
*/
/* Frame */
frame = gtk_frame_new(module->title);
gtk_widget_show(frame);
/* Main vertical box */
main_vb = gtk_vbox_new(FALSE, 5);
gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
gtk_container_add(GTK_CONTAINER(frame), main_vb);
/* Main table */
main_tb = gtk_table_new(module->numprefs, 2, FALSE);
gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
OBJECT_SET_DATA(main_tb, E_TOOLTIPS_KEY, cts->tooltips);
/* Add items for each of the preferences */
prefs_pref_foreach(module, pref_show, main_tb);
/* Add the page to the notebook */
gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), frame, NULL);
/* Attach the page to the tree item */
#if GTK_MAJOR_VERSION < 2
gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node,
GINT_TO_POINTER(cts->page));
#else
gtk_tree_store_set(model, &iter, 0, label_str, 1, cts->page, -1);
#endif
/* If this is the first protocol page, remember its page number */
if (first_proto_prefs_page == -1)
first_proto_prefs_page = cts->page;
cts->page++;
/* Show 'em what we got */
gtk_widget_show_all(main_vb);
}
} }
void void
prefs_cb(GtkWidget *w _U_, gpointer dummy _U_) prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
{ {
GtkWidget *main_vb, *top_hb, *bbox, *prefs_nb, *ct_sb, *frame, GtkWidget *top_hb, *bbox, *prefs_nb, *ct_sb, *frame,
*ok_bt, *apply_bt, *save_bt, *cancel_bt; *ok_bt, *apply_bt, *save_bt, *cancel_bt;
GtkWidget *print_pg, *column_pg, *stream_pg, *gui_pg; GtkWidget *print_pg, *column_pg, *stream_pg, *gui_pg;
#ifdef HAVE_LIBPCAP #ifdef HAVE_LIBPCAP
@ -266,7 +320,6 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
gchar *label_ptr = label_str; gchar *label_ptr = label_str;
GtkCTreeNode *ct_node; GtkCTreeNode *ct_node;
#else #else
GtkTreeStore *store;
GtkTreeSelection *selection; GtkTreeSelection *selection;
GtkCellRenderer *renderer; GtkCellRenderer *renderer;
GtkTreeViewColumn *column; GtkTreeViewColumn *column;
@ -297,14 +350,14 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
cts.tooltips = gtk_tooltips_new(); cts.tooltips = gtk_tooltips_new();
/* Container for each row of widgets */ /* Container for each row of widgets */
main_vb = gtk_vbox_new(FALSE, 5); cts.main_vb = gtk_vbox_new(FALSE, 5);
gtk_container_border_width(GTK_CONTAINER(main_vb), 5); gtk_container_border_width(GTK_CONTAINER(cts.main_vb), 5);
gtk_container_add(GTK_CONTAINER(prefs_w), main_vb); gtk_container_add(GTK_CONTAINER(prefs_w), cts.main_vb);
gtk_widget_show(main_vb); gtk_widget_show(cts.main_vb);
/* Top row: Preferences tree and notebook */ /* Top row: Preferences tree and notebook */
top_hb = gtk_hbox_new(FALSE, 10); top_hb = gtk_hbox_new(FALSE, 10);
gtk_container_add(GTK_CONTAINER(main_vb), top_hb); gtk_container_add(GTK_CONTAINER(cts.main_vb), top_hb);
gtk_widget_show(top_hb); gtk_widget_show(top_hb);
/* Place a Ctree on the left for preference categories */ /* Place a Ctree on the left for preference categories */
@ -331,7 +384,8 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column), gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
GTK_TREE_VIEW_COLUMN_AUTOSIZE); GTK_TREE_VIEW_COLUMN_AUTOSIZE);
#endif #endif
cts.page = 0; cts.page = 0;
cts.node = NULL;
gtk_container_add(GTK_CONTAINER(ct_sb), cts.tree); gtk_container_add(GTK_CONTAINER(ct_sb), cts.tree);
#if GTK_MAJOR_VERSION < 2 #if GTK_MAJOR_VERSION < 2
@ -344,8 +398,8 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
/* A notebook widget sans tabs is used to flip between prefs */ /* A notebook widget sans tabs is used to flip between prefs */
notebook = prefs_nb = gtk_notebook_new(); notebook = prefs_nb = gtk_notebook_new();
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE); gtk_notebook_set_show_tabs(GTK_NOTEBOOK(prefs_nb), FALSE);
gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE); gtk_notebook_set_show_border(GTK_NOTEBOOK(prefs_nb), FALSE);
gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb); gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb);
gtk_widget_show(prefs_nb); gtk_widget_show(prefs_nb);
@ -474,26 +528,14 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
/* Registered prefs */ /* Registered prefs */
cts.notebook = prefs_nb; cts.notebook = prefs_nb;
strcpy(label_str, "Protocols"); cts.is_protocol = FALSE;
#if GTK_MAJOR_VERSION < 2 prefs_module_list_foreach(NULL, module_prefs_show, &cts);
cts.node = gtk_ctree_insert_node(GTK_CTREE(cts.tree), NULL, NULL,
&label_ptr, 5, NULL, NULL, NULL, NULL, FALSE, FALSE);
gtk_ctree_node_set_row_data(GTK_CTREE(cts.tree), cts.node,
GINT_TO_POINTER(-1));
gtk_ctree_node_set_selectable(GTK_CTREE(cts.tree), cts.node, FALSE);
#else
gtk_tree_store_append(store, &cts.proto_iter, NULL);
gtk_tree_store_set(store, &cts.proto_iter, 0, label_str, 1, -1, -1);
#endif
prefs_module_foreach(module_prefs_show, &cts);
/* Button row: OK and cancel buttons */ /* Button row: OK and cancel buttons */
bbox = gtk_hbutton_box_new(); bbox = gtk_hbutton_box_new();
gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END); gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
gtk_container_add(GTK_CONTAINER(main_vb), bbox); gtk_container_add(GTK_CONTAINER(cts.main_vb), bbox);
gtk_widget_show(bbox); gtk_widget_show(bbox);
#if GTK_MAJOR_VERSION < 2 #if GTK_MAJOR_VERSION < 2
@ -914,7 +956,7 @@ prefs_main_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
#endif /* _WIN32 */ #endif /* _WIN32 */
#endif /* HAVE_LIBPCAP */ #endif /* HAVE_LIBPCAP */
nameres_prefs_fetch(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY)); nameres_prefs_fetch(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
prefs_module_foreach(module_prefs_fetch, &must_redissect); prefs_modules_foreach(module_prefs_fetch, &must_redissect);
/* Now apply those preferences. */ /* Now apply those preferences. */
printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY)); printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
@ -966,7 +1008,7 @@ prefs_main_apply_cb(GtkWidget *apply_bt _U_, gpointer parent_w)
#endif /* _WIN32 */ #endif /* _WIN32 */
#endif /* HAVE_LIBPCAP */ #endif /* HAVE_LIBPCAP */
nameres_prefs_fetch(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY)); nameres_prefs_fetch(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
prefs_module_foreach(module_prefs_fetch, &must_redissect); prefs_modules_foreach(module_prefs_fetch, &must_redissect);
/* Now apply those preferences. */ /* Now apply those preferences. */
printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY)); printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
@ -1018,7 +1060,7 @@ prefs_main_save_cb(GtkWidget *save_bt _U_, gpointer parent_w)
#endif /* _WIN32 */ #endif /* _WIN32 */
#endif /* HAVE_LIBPCAP */ #endif /* HAVE_LIBPCAP */
nameres_prefs_fetch(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY)); nameres_prefs_fetch(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY));
prefs_module_foreach(module_prefs_fetch, &must_redissect); prefs_modules_foreach(module_prefs_fetch, &must_redissect);
/* Create the directory that holds personal configuration files, if /* Create the directory that holds personal configuration files, if
necessary. */ necessary. */
@ -1151,7 +1193,7 @@ prefs_main_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
copy_prefs(&prefs, &saved_prefs); copy_prefs(&prefs, &saved_prefs);
/* Now revert the registered preferences. */ /* Now revert the registered preferences. */
prefs_module_foreach(module_prefs_revert, &must_redissect); prefs_modules_foreach(module_prefs_revert, &must_redissect);
/* Now apply the reverted-to preferences. */ /* Now apply the reverted-to preferences. */
printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY)); printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY));
@ -1203,10 +1245,11 @@ prefs_main_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
/* Free up the saved preferences (both for "prefs" and for registered /* Free up the saved preferences (both for "prefs" and for registered
preferences). */ preferences). */
free_prefs(&saved_prefs); free_prefs(&saved_prefs);
prefs_module_foreach(module_prefs_clean, NULL); prefs_modules_foreach(module_prefs_clean, NULL);
/* Note that we no longer have a "Preferences" dialog box. */ /* Note that we no longer have a "Preferences" dialog box. */
prefs_w = NULL; prefs_w = NULL;
first_proto_prefs_page = -1;
} }
struct properties_data { struct properties_data {
@ -1258,11 +1301,11 @@ properties_cb(GtkWidget *w, gpointer dummy)
} }
p.w = notebook; p.w = notebook;
p.page_num = FIRST_PROTO_PREFS_PAGE; p.page_num = first_proto_prefs_page;
p.title = title; p.title = title;
prefs_module_foreach(module_search_properties, &p); prefs_module_list_foreach(protocols_module->prefs, module_search_properties,
&p);
} }
/* Prefs tree selection callback. The node data has been loaded with /* Prefs tree selection callback. The node data has been loaded with

View File

@ -2,7 +2,7 @@
* Definitions for implementation of preference handling routines; * Definitions for implementation of preference handling routines;
* used by "friends" of the preferences type. * used by "friends" of the preferences type.
* *
* $Id: prefs-int.h,v 1.9 2002/08/28 21:00:40 jmayer Exp $ * $Id: prefs-int.h,v 1.10 2002/12/20 01:48:54 guy Exp $
* *
* Ethereal - Network traffic analyzer * Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com> * By Gerald Combs <gerald@ethereal.com>
@ -29,14 +29,20 @@
struct pref_module { struct pref_module {
const char *name; /* name of module */ const char *name; /* name of module */
const char *title; /* title of module (displayed in preferences notebook) */ const char *title; /* title of module (displayed in preferences notebook) */
gboolean is_subtree; /* if TRUE, this has other modules, not preferences, under it */
void (*apply_cb)(void); /* routine to call when preferences applied */ void (*apply_cb)(void); /* routine to call when preferences applied */
GList *prefs; /* list of its preferences */ GList *prefs; /* list of its preferences or submodules */
int numprefs; /* number of non-obsolete preferences */ int numprefs; /* number of non-obsolete preferences */
gboolean prefs_changed; /* if TRUE, a preference has changed since we last checked */ gboolean prefs_changed; /* if TRUE, a preference has changed since we last checked */
gboolean obsolete; /* if TRUE, this is a module that used to gboolean obsolete; /* if TRUE, this is a module that used to
exist but no longer does */ exist but no longer does */
}; };
/*
* Module used for protocol preferences.
*/
extern module_t *protocols_module;
/* /*
* PREF_OBSOLETE is used for preferences that a module used to support * PREF_OBSOLETE is used for preferences that a module used to support
* but no longer supports; we give different error messages for them. * but no longer supports; we give different error messages for them.

196
prefs.c
View File

@ -1,7 +1,7 @@
/* prefs.c /* prefs.c
* Routines for handling preferences * Routines for handling preferences
* *
* $Id: prefs.c,v 1.91 2002/09/28 15:23:13 gerald Exp $ * $Id: prefs.c,v 1.92 2002/12/20 01:48:54 guy Exp $
* *
* Ethereal - Network traffic analyzer * Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com> * By Gerald Combs <gerald@ethereal.com>
@ -51,6 +51,9 @@
/* Internal functions */ /* Internal functions */
static module_t *find_module(const char *name); static module_t *find_module(const char *name);
static module_t *prefs_register_module_or_subtree(module_t *parent,
const char *name, const char *title, gboolean is_subtree,
void (*apply_cb)(void));
static struct preference *find_preference(module_t *, const char *); static struct preference *find_preference(module_t *, const char *);
static int set_pref(gchar*, gchar*); static int set_pref(gchar*, gchar*);
static GList *get_string_list(gchar *); static GList *get_string_list(gchar *);
@ -85,10 +88,16 @@ gchar *gui_hex_dump_highlight_style_text[] =
{ "BOLD", "INVERSE", NULL }; { "BOLD", "INVERSE", NULL };
/* /*
* List of modules with preference settings. * List of all modules with preference settings.
*/ */
static GList *modules; static GList *modules;
/*
* List of all modules that should show up at the top level of the
* tree in the preference dialog box.
*/
static GList *top_level_modules;
static gint static gint
module_compare_name(gconstpointer p1_arg, gconstpointer p2_arg) module_compare_name(gconstpointer p1_arg, gconstpointer p2_arg)
{ {
@ -98,15 +107,46 @@ module_compare_name(gconstpointer p1_arg, gconstpointer p2_arg)
return g_strcasecmp(p1->name, p2->name); return g_strcasecmp(p1->name, p2->name);
} }
static gint
module_compare_title(gconstpointer p1_arg, gconstpointer p2_arg)
{
const module_t *p1 = p1_arg;
const module_t *p2 = p2_arg;
return g_strcasecmp(p1->title, p2->title);
}
/* /*
* Register a module that will have preferences. * Register a module that will have preferences.
* Specify the name used for the module in the preferences file, the * Specify the module under which to register it or NULL to register it
* title used in the tab for it in a preferences dialog box, and a * at the top level, the name used for the module in the preferences file,
* the title used in the tab for it in a preferences dialog box, and a
* routine to call back when we apply the preferences. * routine to call back when we apply the preferences.
*/ */
module_t * module_t *
prefs_register_module(const char *name, const char *title, prefs_register_module(module_t *parent, const char *name, const char *title,
void (*apply_cb)(void)) void (*apply_cb)(void))
{
return prefs_register_module_or_subtree(parent, name, title, FALSE,
apply_cb);
}
/*
* Register a subtree that will have modules under it.
* Specify the module under which to register it or NULL to register it
* at the top level and the title used in the tab for it in a preferences
* dialog box.
*/
module_t *
prefs_register_subtree(module_t *parent, const char *title)
{
return prefs_register_module_or_subtree(parent, NULL, title, TRUE,
NULL);
}
static module_t *
prefs_register_module_or_subtree(module_t *parent, const char *name,
const char *title, gboolean is_subtree, void (*apply_cb)(void))
{ {
module_t *module; module_t *module;
const guchar *p; const guchar *p;
@ -114,6 +154,7 @@ prefs_register_module(const char *name, const char *title,
module = g_malloc(sizeof (module_t)); module = g_malloc(sizeof (module_t));
module->name = name; module->name = name;
module->title = title; module->title = title;
module->is_subtree = is_subtree;
module->apply_cb = apply_cb; module->apply_cb = apply_cb;
module->prefs = NULL; /* no preferences, to start */ module->prefs = NULL; /* no preferences, to start */
module->numprefs = 0; module->numprefs = 0;
@ -121,28 +162,69 @@ prefs_register_module(const char *name, const char *title,
module->obsolete = FALSE; module->obsolete = FALSE;
/* /*
* Make sure that only lower-case ASCII letters, numbers, * Do we have a module name?
* underscores, and dots appear in the module name.
*
* Crash if there is, as that's an error in the code;
* you can make the title a nice string with capitalization,
* white space, punctuation, etc., but the name can be used
* on the command line, and shouldn't require quoting,
* shifting, etc.
*/ */
for (p = name; *p != '\0'; p++) if (name != NULL) {
g_assert(isascii(*p) && /*
(islower(*p) || isdigit(*p) || *p == '_' || *p == '.')); * Yes.
* Make sure that only lower-case ASCII letters, numbers,
* underscores, and dots appear in the name.
*
* Crash if there is, as that's an error in the code;
* you can make the title a nice string with capitalization,
* white space, punctuation, etc., but the name can be used
* on the command line, and shouldn't require quoting,
* shifting, etc.
*/
for (p = name; *p != '\0'; p++)
g_assert(isascii(*p) &&
(islower(*p) || isdigit(*p) || *p == '_' ||
*p == '.'));
/*
* Make sure there's not already a module with that
* name. Crash if there is, as that's an error in the
* code, and the code has to be fixed not to register
* more than one module with the same name.
*
* We search the list of all modules; the subtree stuff
* doesn't require preferences in subtrees to have names
* that reflect the subtree they're in (that would require
* protocol preferences to have a bogus "protocol.", or
* something such as that, to be added to all their names).
*/
g_assert(find_module(name) == NULL);
/*
* Insert this module in the list of all modules.
*/
modules = g_list_insert_sorted(modules, module,
module_compare_name);
} else {
/*
* This has no name, just a title; check to make sure it's a
* subtree, and crash if it's not.
*/
g_assert(is_subtree);
}
/* /*
* Make sure there's not already a module with that * Insert this module into the appropriate place in the display
* name. Crash if there is, as that's an error in the * tree.
* code, and the code has to be fixed not to register
* more than one module with the same name.
*/ */
g_assert(find_module(name) == NULL); if (parent == NULL) {
/*
modules = g_list_insert_sorted(modules, module, module_compare_name); * It goes at the top.
*/
top_level_modules = g_list_insert_sorted(top_level_modules,
module, module_compare_title);
} else {
/*
* It goes into the list for this module.
*/
parent->prefs = g_list_insert_sorted(parent->prefs, module,
module_compare_title);
}
return module; return module;
} }
@ -150,12 +232,23 @@ prefs_register_module(const char *name, const char *title,
/* /*
* Register that a protocol has preferences. * Register that a protocol has preferences.
*/ */
module_t *protocols_module;
module_t * module_t *
prefs_register_protocol(int id, void (*apply_cb)(void)) prefs_register_protocol(int id, void (*apply_cb)(void))
{ {
return prefs_register_module(proto_get_protocol_filter_name(id), /*
proto_get_protocol_short_name(id), * Have we yet created the "Protocols" subtree?
apply_cb); */
if (protocols_module == NULL) {
/*
* No. Do so.
*/
protocols_module = prefs_register_subtree(NULL, "Protocols");
}
return prefs_register_module(protocols_module,
proto_get_protocol_filter_name(id),
proto_get_protocol_short_name(id), apply_cb);
} }
/* /*
@ -167,9 +260,18 @@ prefs_register_protocol_obsolete(int id)
{ {
module_t *module; module_t *module;
module = prefs_register_module(proto_get_protocol_filter_name(id), /*
proto_get_protocol_short_name(id), * Have we yet created the "Protocols" subtree?
NULL); */
if (protocols_module == NULL) {
/*
* No. Do so.
*/
protocols_module = prefs_register_subtree(NULL, "Protocols");
}
module = prefs_register_module(protocols_module,
proto_get_protocol_filter_name(id),
proto_get_protocol_short_name(id), NULL);
module->obsolete = TRUE; module->obsolete = TRUE;
return module; return module;
} }
@ -213,19 +315,41 @@ do_module_callback(gpointer data, gpointer user_data)
} }
/* /*
* Call a callback function, with a specified argument, for each module. * Call a callback function, with a specified argument, for each module
* in a list of modules. If the list is NULL, searches the top-level
* list in the display tree of modules.
*
* Ignores "obsolete" modules; their sole purpose is to allow old
* preferences for dissectors that no longer have preferences to be
* silently ignored in preference files. Does not ignore subtrees,
* as this can be used when walking the display tree of modules.
*/
void
prefs_module_list_foreach(GList *module_list, module_cb callback,
gpointer user_data)
{
module_cb_arg_t arg;
if (module_list == NULL)
module_list = top_level_modules;
arg.callback = callback;
arg.user_data = user_data;
g_list_foreach(module_list, do_module_callback, &arg);
}
/*
* Call a callback function, with a specified argument, for each module
* in the list of all modules. (This list does not include subtrees.)
*
* Ignores "obsolete" modules; their sole purpose is to allow old * Ignores "obsolete" modules; their sole purpose is to allow old
* preferences for dissectors that no longer have preferences to be * preferences for dissectors that no longer have preferences to be
* silently ignored in preference files. * silently ignored in preference files.
*/ */
void void
prefs_module_foreach(module_cb callback, gpointer user_data) prefs_modules_foreach(module_cb callback, gpointer user_data)
{ {
module_cb_arg_t arg; prefs_module_list_foreach(modules, callback, user_data);
arg.callback = callback;
arg.user_data = user_data;
g_list_foreach(modules, do_module_callback, &arg);
} }
static void static void

53
prefs.h
View File

@ -1,7 +1,7 @@
/* prefs.h /* prefs.h
* Definitions for preference handling routines * Definitions for preference handling routines
* *
* $Id: prefs.h,v 1.41 2002/09/14 10:07:37 oabad Exp $ * $Id: prefs.h,v 1.42 2002/12/20 01:48:54 guy Exp $
* *
* Ethereal - Network traffic analyzer * Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com> * By Gerald Combs <gerald@ethereal.com>
@ -88,18 +88,27 @@ typedef struct pref_module module_t;
/* /*
* Register a module that will have preferences. * Register a module that will have preferences.
* Specify the name used for the module in the preferences file, the * Specify the module under which to register it or NULL to register it
* title used in the tab for it in a preferences dialog box, and a * at the top level, the name used for the module in the preferences file,
* the title used in the tab for it in a preferences dialog box, and a
* routine to call back when we apply the preferences. * routine to call back when we apply the preferences.
* Note: *
* In case of dissectors, the specified name should be the protocol * This should not be used for dissector preferences;
* name specified at the proto_register_protocol() call in order to * "prefs_register_protocol()" should be used for that, so that the
* make the "Protocol Properties..." menu item work. * preferences go under the "Protocols" subtree, and so that the
* name is the protocol name specified at the "proto_register_protocol()"
* call so that the "Protocol Properties..." menu item works.
*/ */
extern module_t *prefs_register_module(const char *name, const char *title, extern module_t *prefs_register_module(module_t *parent, const char *name,
void (*apply_cb)(void)); const char *title, void (*apply_cb)(void));
typedef void (*module_cb)(module_t *module, gpointer user_data); /*
* Register a subtree that will have modules under it.
* Specify the module under which to register it or NULL to register it
* at the top level and the title used in the tab for it in a preferences
* dialog box.
*/
extern module_t *prefs_register_subtree(module_t *parent, const char *title);
/* /*
* Register that a protocol has preferences. * Register that a protocol has preferences.
@ -113,12 +122,32 @@ extern module_t *prefs_register_protocol(int id, void (*apply_cb)(void));
extern module_t *prefs_register_protocol_obsolete(int id); extern module_t *prefs_register_protocol_obsolete(int id);
/* /*
* Call a callback function, with a specified argument, for each module. * Callback function for module list scanners.
*/
typedef void (*module_cb)(module_t *module, gpointer user_data);
/*
* Call a callback function, with a specified argument, for each module
* in a list of modules. If the list is NULL, searches the top-level
* list in the display tree of modules.
*
* Ignores "obsolete" modules; their sole purpose is to allow old
* preferences for dissectors that no longer have preferences to be
* silently ignored in preference files. Does not ignore subtrees,
* as this can be used when walking the display tree of modules.
*/
extern void prefs_module_list_foreach(GList *module_list, module_cb callback,
gpointer user_data);
/*
* Call a callback function, with a specified argument, for each module
* in the list of all modules. (This list does not include subtrees.)
*
* Ignores "obsolete" modules; their sole purpose is to allow old * Ignores "obsolete" modules; their sole purpose is to allow old
* preferences for dissectors that no longer have preferences to be * preferences for dissectors that no longer have preferences to be
* silently ignored in preference files. * silently ignored in preference files.
*/ */
extern void prefs_module_foreach(module_cb callback, gpointer user_data); extern void prefs_modules_foreach(module_cb callback, gpointer user_data);
/* /*
* Call the "apply" callback function for each module if any of its * Call the "apply" callback function for each module if any of its