![Bill Meier](/assets/img/avatar_default.png)
gtk_container_border_width() ==> gtk_container_set_border_width() gtk_container_children() ==> gtk_container_get_children() gtk_entry_new_with_max_length() ==> gtk_entry_new(); gtk_entry_set_max_length() gtk_menu_append() ==> gtk_menu_shell_append() gtk_menu_prepend() ==> gtk_menu_shell_prepend() gtk_notebook_set_page() ==> gtk_notebook_set_current_page() gtk_paned_gutter_size() ==> gtk_paned_set_gutter_size() gtk_radio_button_group() ==> gtk_radio_button_get_group() gtk_signal_connect() ==> g_signal_connect() gtk_signal_disconnect() ==> g_signal_handler_disconnect() gtk_signal_emit_by_name() ==> g_signal_emit_by_name() gtk_signal_handler_block_by_data() ==> g_signal_handlers_block_matched() gtk_signal_handler_block_by_func() ==> g_signal_handlers_block_by_func() gtk_signal_handler_unblock_by_data() ==> g_signal-handlers_unblock_matched() gtk_signal_handler_unblock_by_func() ==> g_signal-handlers_unblock_by_func() gtk_spin_button_get_value_as_float() ==> gtk_spin_button_get_value() gtk_toggle_button_set_state() ==> gtk_toggle_button_set_active() svn path=/trunk/; revision=25634
918 lines
28 KiB
C
918 lines
28 KiB
C
/* profile_dlg.c
|
|
* Dialog box for profiles editing
|
|
* Stig Bjørlykke <stig@bjorlykke.org>, 2008
|
|
*
|
|
* $Id$
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <string.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
#include <gdk/gdkkeysyms.h>
|
|
|
|
#include <epan/filesystem.h>
|
|
#include <epan/prefs.h>
|
|
|
|
#include "../simple_dialog.h"
|
|
#include <wsutil/file_util.h>
|
|
|
|
#include "gtk/main.h"
|
|
#include "gtk/profile_dlg.h"
|
|
#include "gtk/dlg_utils.h"
|
|
#include "gtk/gui_utils.h"
|
|
#include "gtk/gtkglobals.h"
|
|
#include "gtk/help_dlg.h"
|
|
|
|
|
|
#define E_PROF_PROFILE_L_KEY "profile_profile_l"
|
|
#define E_PROF_COPY_BT_KEY "profile_copy_bt"
|
|
#define E_PROF_DEL_BT_KEY "profile_del_bt"
|
|
#define E_PROF_NAME_TE_KEY "profile_name_te"
|
|
|
|
static GtkWidget *global_profile_w = NULL;
|
|
static GList *current_profiles = NULL;
|
|
static GList *edited_profiles = NULL;
|
|
|
|
#define PROF_STAT_DEFAULT 1
|
|
#define PROF_STAT_EXISTS 2
|
|
#define PROF_STAT_NEW 3
|
|
#define PROF_STAT_CHANGED 4
|
|
#define PROF_STAT_COPY 5
|
|
|
|
typedef struct {
|
|
char *name; /* profile name */
|
|
char *reference; /* profile reference */
|
|
int status;
|
|
} profile_def;
|
|
|
|
static GList *
|
|
add_profile_entry(GList *fl, const char *profilename, const char *reference, int status)
|
|
{
|
|
profile_def *profile;
|
|
|
|
profile = (profile_def *) g_malloc(sizeof(profile_def));
|
|
profile->name = g_strdup(profilename);
|
|
profile->reference = g_strdup(reference);
|
|
profile->status = status;
|
|
return g_list_append(fl, profile);
|
|
}
|
|
|
|
static GList *
|
|
remove_profile_entry(GList *fl, GList *fl_entry)
|
|
{
|
|
profile_def *profile;
|
|
|
|
profile = (profile_def *) fl_entry->data;
|
|
g_free(profile->name);
|
|
g_free(profile->reference);
|
|
g_free(profile);
|
|
return g_list_remove_link(fl, fl_entry);
|
|
}
|
|
|
|
static GList *
|
|
add_to_profile_list(const char *name, const char *expression, int status)
|
|
{
|
|
edited_profiles = add_profile_entry(edited_profiles, name, expression, status);
|
|
|
|
return g_list_last(edited_profiles);
|
|
}
|
|
|
|
static void
|
|
remove_from_profile_list(GList *fl_entry)
|
|
{
|
|
edited_profiles = remove_profile_entry(edited_profiles, fl_entry);
|
|
}
|
|
|
|
static void
|
|
empty_profile_list(gboolean edit_list)
|
|
{
|
|
GList **flpp;
|
|
|
|
if (edit_list) {
|
|
flpp = &edited_profiles;
|
|
|
|
while(*flpp) {
|
|
*flpp = remove_profile_entry(*flpp, g_list_first(*flpp));
|
|
}
|
|
|
|
g_assert(g_list_length(*flpp) == 0);
|
|
}
|
|
|
|
flpp = ¤t_profiles;
|
|
|
|
while(*flpp) {
|
|
*flpp = remove_profile_entry(*flpp, g_list_first(*flpp));
|
|
}
|
|
|
|
g_assert(g_list_length(*flpp) == 0);
|
|
}
|
|
|
|
static void
|
|
copy_profile_list(void)
|
|
{
|
|
GList *flp_src;
|
|
profile_def *profile;
|
|
|
|
flp_src = edited_profiles;
|
|
|
|
/* throw away the "old" destination list - a NULL list is ok here */
|
|
empty_profile_list(FALSE);
|
|
|
|
/* copy the list entries */
|
|
while(flp_src) {
|
|
profile = (flp_src)->data;
|
|
|
|
current_profiles = add_profile_entry(current_profiles, profile->name,
|
|
profile->reference, profile->status);
|
|
flp_src = g_list_next(flp_src);
|
|
}
|
|
}
|
|
|
|
|
|
static GtkTreeIter *
|
|
fill_list(GtkWidget *main_w)
|
|
{
|
|
ETH_DIR *dir; /* scanned directory */
|
|
ETH_DIRENT *file; /* current file */
|
|
GList *fl_entry;
|
|
profile_def *profile;
|
|
GtkTreeView *profile_l;
|
|
GtkListStore *store;
|
|
GtkTreeIter iter, *l_select = NULL;
|
|
const gchar *profile_name = get_profile_name ();
|
|
const gchar *profiles_dir, *name;
|
|
gchar *filename;
|
|
|
|
profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
|
|
store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
|
|
|
|
fl_entry = add_to_profile_list(DEFAULT_PROFILE, DEFAULT_PROFILE, PROF_STAT_DEFAULT);
|
|
gtk_list_store_append(store, &iter);
|
|
gtk_list_store_set(store, &iter, 0, DEFAULT_PROFILE, 1, fl_entry, -1);
|
|
if (strcmp (profile_name, DEFAULT_PROFILE)==0) {
|
|
l_select = g_memdup(&iter, sizeof(iter));
|
|
}
|
|
|
|
/* fill in data */
|
|
profiles_dir = get_profiles_dir();
|
|
if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
|
|
while ((file = ws_dir_read_name(dir)) != NULL) {
|
|
name = ws_dir_get_name(file);
|
|
filename = g_strdup_printf ("%s%s%s", profiles_dir, G_DIR_SEPARATOR_S, name);
|
|
|
|
if (test_for_directory(filename) == EISDIR) {
|
|
fl_entry = add_to_profile_list(name, name, PROF_STAT_EXISTS);
|
|
profile = (profile_def *) fl_entry->data;
|
|
gtk_list_store_append(store, &iter);
|
|
gtk_list_store_set(store, &iter, 0, profile->name, 1, fl_entry, -1);
|
|
|
|
if (profile->name) {
|
|
if (strcmp(profile_name, profile->name) == 0) {
|
|
/*
|
|
* XXX - We're assuming that we can just copy a GtkTreeIter
|
|
* and use it later without any crashes. This may not be a
|
|
* valid assumption.
|
|
*/
|
|
l_select = g_memdup(&iter, sizeof(iter));
|
|
}
|
|
}
|
|
}
|
|
g_free (filename);
|
|
}
|
|
ws_dir_close (dir);
|
|
}
|
|
|
|
/* Make the current list an the edited list equal */
|
|
copy_profile_list ();
|
|
|
|
return l_select;
|
|
}
|
|
|
|
static gboolean
|
|
profile_is_invalid_name(gchar *name)
|
|
{
|
|
gchar *message = NULL;
|
|
|
|
#ifdef _WIN32
|
|
char *invalid_dir_char = "\\/:*?\"<>|";
|
|
gboolean invalid = FALSE;
|
|
int i;
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
if (strchr(name, invalid_dir_char[i])) {
|
|
/* Invalid character in directory */
|
|
invalid = TRUE;
|
|
}
|
|
}
|
|
if (name[0] == '.' || name[strlen(name)-1] == '.') {
|
|
/* Profile name cannot start or end with period */
|
|
invalid = TRUE;
|
|
}
|
|
if (invalid) {
|
|
message = g_strdup_printf("start or end with period (.), or contain any of the following characters:\n"
|
|
" \\ / : * ? \" < > |");
|
|
}
|
|
#else
|
|
if (strchr(name, '/')) {
|
|
/* Invalid character in directory */
|
|
message = g_strdup_printf("contain the '/' character.");
|
|
}
|
|
#endif
|
|
|
|
if (message) {
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "A profile name cannot %s\nProfiles unchanged.", message);
|
|
g_free(message);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
profile_select(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
|
|
{
|
|
GList *fl_entry;
|
|
profile_def *profile;
|
|
GtkTreeSelection *sel;
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
|
|
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
|
|
|
|
if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
|
|
gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
|
|
if (fl_entry) {
|
|
profile = (profile_def *) fl_entry->data;
|
|
if (profile_exists (profile->name)) {
|
|
/* The new profile exists, change */
|
|
change_configuration_profile (profile->name);
|
|
} else if (!profile_exists (get_profile_name())) {
|
|
/* The new profile does not exist, and the previous profile has
|
|
been deleted. Change to the default profile */
|
|
change_configuration_profile (NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (destroy) {
|
|
/*
|
|
* Destroy the profile dialog box.
|
|
*/
|
|
empty_profile_list (TRUE);
|
|
window_destroy(main_w);
|
|
}
|
|
}
|
|
|
|
static void
|
|
profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
|
|
{
|
|
char *pf_dir_path, *pf_dir_path2;
|
|
GList *fl1, *fl2;
|
|
profile_def *profile1, *profile2;
|
|
gboolean found;
|
|
|
|
/* First validate all profile names */
|
|
fl1 = g_list_first(edited_profiles);
|
|
while (fl1) {
|
|
found = FALSE;
|
|
profile1 = (profile_def *) fl1->data;
|
|
g_strstrip(profile1->name);
|
|
if (profile_is_invalid_name(profile1->name)) {
|
|
return;
|
|
}
|
|
fl1 = g_list_next(fl1);
|
|
}
|
|
|
|
/* Then create new and rename changed */
|
|
fl1 = g_list_first(edited_profiles);
|
|
while (fl1) {
|
|
found = FALSE;
|
|
profile1 = (profile_def *) fl1->data;
|
|
g_strstrip(profile1->name);
|
|
if (profile1->status == PROF_STAT_NEW) {
|
|
/* We do not create a directory for the default profile */
|
|
if (strcmp(profile1->name, DEFAULT_PROFILE)!=0) {
|
|
if (create_persconffile_profile(profile1->name, &pf_dir_path) == -1) {
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
|
"Can't create directory\n\"%s\":\n%s.",
|
|
pf_dir_path, strerror(errno));
|
|
|
|
g_free(pf_dir_path);
|
|
}
|
|
profile1->status = PROF_STAT_EXISTS;
|
|
if (profile1->reference) {
|
|
g_free (profile1->reference);
|
|
}
|
|
profile1->reference = g_strdup(profile1->name);
|
|
}
|
|
} else if (profile1->status == PROF_STAT_CHANGED) {
|
|
if (strcmp(profile1->reference, profile1->name)!=0) {
|
|
/* Rename old profile directory to new */
|
|
if (rename_persconffile_profile(profile1->reference, profile1->name,
|
|
&pf_dir_path, &pf_dir_path2) == -1) {
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
|
"Can't rename directory\n\"%s\" to\n\"%s\":\n%s.",
|
|
pf_dir_path, pf_dir_path2, strerror(errno));
|
|
|
|
g_free(pf_dir_path);
|
|
}
|
|
profile1->status = PROF_STAT_EXISTS;
|
|
g_free (profile1->reference);
|
|
profile1->reference = g_strdup(profile1->name);
|
|
}
|
|
}
|
|
fl1 = g_list_next(fl1);
|
|
}
|
|
|
|
/* Last remove deleted */
|
|
fl1 = g_list_first(current_profiles);
|
|
while (fl1) {
|
|
found = FALSE;
|
|
profile1 = (profile_def *) fl1->data;
|
|
fl2 = g_list_first(edited_profiles);
|
|
while (fl2) {
|
|
profile2 = (profile_def *) fl2->data;
|
|
if (strcmp(profile1->name, profile2->name)==0) {
|
|
/* Profile exists in both lists */
|
|
found = TRUE;
|
|
} else if (strcmp(profile1->name, profile2->reference)==0) {
|
|
/* Profile has been renamed */
|
|
found = TRUE;
|
|
}
|
|
fl2 = fl2->next;
|
|
}
|
|
if (!found) {
|
|
/* Exists in existing list and not in edited, this is a deleted profile */
|
|
if (delete_persconffile_profile(profile1->name, &pf_dir_path) == -1) {
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
|
"Can't delete profile directory\n\"%s\":\n%s.",
|
|
pf_dir_path, strerror(errno));
|
|
|
|
g_free(pf_dir_path);
|
|
}
|
|
}
|
|
fl1 = g_list_next(fl1);
|
|
}
|
|
|
|
copy_profile_list();
|
|
profile_select(main_w, profile_l, destroy);
|
|
}
|
|
|
|
static void
|
|
profile_dlg_ok_cb(GtkWidget *ok_bt, gpointer data _U_)
|
|
{
|
|
GtkWidget *main_w = gtk_widget_get_toplevel(ok_bt);
|
|
GtkTreeView *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
|
|
|
|
/*
|
|
* Apply the profile and destroy the dialog box.
|
|
*/
|
|
profile_apply(main_w, profile_l, TRUE);
|
|
}
|
|
|
|
static void
|
|
profile_dlg_apply_cb(GtkWidget *apply_bt, gpointer data _U_)
|
|
{
|
|
GtkWidget *main_w = gtk_widget_get_toplevel(apply_bt);
|
|
GtkTreeView *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
|
|
|
|
/*
|
|
* Apply the profile, but don't destroy the dialog box.
|
|
*/
|
|
profile_apply(main_w, profile_l, FALSE);
|
|
}
|
|
|
|
/* cancel button pressed, revert changes and exit dialog */
|
|
static void
|
|
profile_dlg_cancel_cb(GtkWidget *cancel_bt, gpointer data _U_)
|
|
{
|
|
GtkWidget *main_w = gtk_widget_get_toplevel(cancel_bt);
|
|
|
|
empty_profile_list (TRUE);
|
|
window_destroy(GTK_WIDGET(main_w));
|
|
}
|
|
|
|
/* Treat this as a cancel, by calling "profile_dlg_cancel_cb()" */
|
|
static gboolean
|
|
profile_dlg_delete_event_cb(GtkWidget *main_w, GdkEvent *event _U_,
|
|
gpointer data)
|
|
{
|
|
profile_dlg_cancel_cb(main_w, data);
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
profile_dlg_destroy_cb(GtkWidget *w _U_, gpointer data _U_)
|
|
{
|
|
global_profile_w = NULL;
|
|
}
|
|
|
|
|
|
static gint
|
|
profile_button_press_cb(GtkWidget *list, GdkEventButton *event, gpointer data _U_)
|
|
{
|
|
if (event->type == GDK_2BUTTON_PRESS) {
|
|
GtkWidget *main_w = gtk_widget_get_toplevel(list);
|
|
|
|
profile_apply (main_w, GTK_TREE_VIEW(list), TRUE);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gint
|
|
profile_key_release_cb(GtkWidget *list, GdkEventKey *event, gpointer data _U_)
|
|
{
|
|
if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter) {
|
|
GtkWidget *main_w = gtk_widget_get_toplevel(list);
|
|
|
|
profile_apply (main_w, GTK_TREE_VIEW(list), TRUE);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
profile_sel_list_cb(GtkTreeSelection *sel, gpointer data _U_)
|
|
{
|
|
GtkWidget *profile_l = GTK_WIDGET(gtk_tree_selection_get_tree_view(sel));
|
|
GtkWidget *main_w = gtk_widget_get_toplevel(profile_l);
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
GtkWidget *name_te = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
|
|
GtkWidget *copy_bt = g_object_get_data(G_OBJECT(main_w), E_PROF_COPY_BT_KEY);
|
|
GtkWidget *del_bt = g_object_get_data(G_OBJECT(main_w), E_PROF_DEL_BT_KEY);
|
|
profile_def *profile;
|
|
gchar *name = NULL;
|
|
GList *fl_entry;
|
|
gint sensitivity = FALSE;
|
|
|
|
if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
|
|
gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
|
|
if (fl_entry) {
|
|
profile= (profile_def *) fl_entry->data;
|
|
name = g_strdup(profile->name);
|
|
if (profile->status!=PROF_STAT_DEFAULT) {
|
|
sensitivity = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Did you know that this function is called when the window is destroyed?
|
|
* Funny, that.
|
|
* This means that we have to:
|
|
*
|
|
* attach to the top-level window data items containing pointers to
|
|
* the widgets we affect here;
|
|
*
|
|
* give each of those widgets their own destroy callbacks;
|
|
*
|
|
* clear that pointer when the widget is destroyed;
|
|
*
|
|
* don't do anything to the widget if the pointer we get back is
|
|
* null;
|
|
*
|
|
* so that if we're called after any of the widgets we'd affect are
|
|
* destroyed, we know that we shouldn't do anything to those widgets.
|
|
*/
|
|
if (name_te != NULL) {
|
|
gtk_entry_set_text(GTK_ENTRY(name_te), name ? name : "");
|
|
gtk_widget_set_sensitive(name_te, sensitivity);
|
|
}
|
|
if (copy_bt != NULL)
|
|
gtk_widget_set_sensitive(copy_bt, sensitivity);
|
|
if (del_bt != NULL)
|
|
gtk_widget_set_sensitive(del_bt, sensitivity);
|
|
if (name != NULL)
|
|
g_free(name);
|
|
}
|
|
|
|
static void
|
|
profile_new_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
|
|
{
|
|
GtkWidget *main_w = gtk_widget_get_toplevel(w);
|
|
GtkWidget *name_te = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
|
|
GtkTreeView *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
|
|
GtkListStore *store;
|
|
GtkTreeIter iter;
|
|
GList *fl_entry;
|
|
const gchar *name = "New profile";
|
|
|
|
/* Add a new entry to the profile list. */
|
|
fl_entry = add_to_profile_list(name, "", PROF_STAT_NEW);
|
|
|
|
store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
|
|
gtk_list_store_append(store, &iter);
|
|
gtk_list_store_set(store, &iter, 0, name, 1, fl_entry, -1);
|
|
/* Select the item. */
|
|
gtk_tree_selection_select_iter(gtk_tree_view_get_selection(profile_l), &iter);
|
|
|
|
gtk_editable_select_region(GTK_EDITABLE(name_te), 0, -1);
|
|
gtk_widget_grab_focus(name_te);
|
|
}
|
|
|
|
#if 0
|
|
static void
|
|
profile_copy_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
|
|
{
|
|
GtkWidget *main_w = gtk_widget_get_toplevel(w);
|
|
GtkWidget *name_te = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
|
|
GtkTreeView *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
|
|
GtkListStore *store;
|
|
GtkTreeIter iter;
|
|
GList *fl_entry;
|
|
const gchar *name = gtk_entry_get_text(GTK_ENTRY(name_te));
|
|
gchar *new_name;
|
|
|
|
new_name = g_strdup_printf ("%s (copy)", name);
|
|
|
|
/* Add a new entry to the profile list. */
|
|
fl_entry = add_to_profile_list(new_name, name, PROF_STAT_COPY);
|
|
|
|
store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
|
|
gtk_list_store_append(store, &iter);
|
|
gtk_list_store_set(store, &iter, 0, new_name, 1, fl_entry, -1);
|
|
/* Select the item. */
|
|
gtk_tree_selection_select_iter(gtk_tree_view_get_selection(profile_l), &iter);
|
|
|
|
gtk_editable_select_region(GTK_EDITABLE(name_te), 0, -1);
|
|
gtk_widget_grab_focus(name_te);
|
|
|
|
g_free (new_name);
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
profile_name_te_changed_cb(GtkWidget *w, gpointer data _U_)
|
|
{
|
|
GtkWidget *main_w = gtk_widget_get_toplevel(w);
|
|
GtkWidget *name_te = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
|
|
GtkWidget *profile_l = g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY);
|
|
profile_def *profile;
|
|
GList *fl_entry;
|
|
const gchar *name = "";
|
|
|
|
GtkTreeSelection *sel;
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
|
|
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
|
|
name = gtk_entry_get_text(GTK_ENTRY(name_te));
|
|
|
|
/* if something was selected */
|
|
if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
|
|
gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
|
|
if (fl_entry != NULL) {
|
|
profile = (profile_def *) fl_entry->data;
|
|
|
|
if (strlen(name) > 0 && profile) {
|
|
if (profile->status != PROF_STAT_DEFAULT) {
|
|
g_free(profile->name);
|
|
profile->name = g_strdup(name);
|
|
if (profile->status != PROF_STAT_NEW) {
|
|
profile->status = PROF_STAT_CHANGED;
|
|
}
|
|
gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, name, -1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
profile_del_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
|
|
{
|
|
GtkWidget *main_w = gtk_widget_get_toplevel(w);
|
|
GtkWidget *profile_l = g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY);
|
|
GList *fl_entry;
|
|
|
|
GtkTreeSelection *sel;
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
|
|
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
|
|
/* If something was selected */
|
|
if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
|
|
gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
|
|
|
|
if (fl_entry != NULL) {
|
|
remove_from_profile_list (fl_entry);
|
|
gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
|
|
}
|
|
}
|
|
|
|
if (gtk_tree_model_get_iter_first (model, &iter)) {
|
|
gtk_tree_selection_select_iter(sel, &iter);
|
|
}
|
|
}
|
|
|
|
static GtkWidget *
|
|
profile_dialog_new(void)
|
|
{
|
|
GtkWidget *main_w, /* main window */
|
|
*main_vb, /* main container */
|
|
*bbox, /* button container */
|
|
*ok_bt, /* "OK" button */
|
|
*apply_bt, /* "Apply" button */
|
|
*cancel_bt, /* "Cancel" button */
|
|
*help_bt; /* "Help" button */
|
|
GtkWidget *profile_vb, /* profile settings box */
|
|
*props_vb;
|
|
GtkWidget *top_hb,
|
|
*list_bb,
|
|
*new_bt,
|
|
#if 0
|
|
*copy_bt,
|
|
#endif
|
|
*del_bt,
|
|
*profile_sc,
|
|
*profile_l,
|
|
*middle_hb,
|
|
*name_lb,
|
|
*name_te,
|
|
*profile_fr,
|
|
*edit_fr,
|
|
*props_fr;
|
|
GtkTooltips *tooltips;
|
|
GtkListStore *store;
|
|
GtkCellRenderer *renderer;
|
|
GtkTreeViewColumn *column;
|
|
GtkTreeSelection *sel;
|
|
GtkTreeIter *l_select;
|
|
|
|
/* Get a pointer to a static variable holding the type of profile on
|
|
which we're working, so we can pass that pointer to callback
|
|
routines. */
|
|
|
|
tooltips = gtk_tooltips_new ();
|
|
|
|
main_w = dlg_conf_window_new("Wireshark: Configuration Profiles");
|
|
gtk_window_set_default_size(GTK_WINDOW(main_w), 400, 400);
|
|
|
|
main_vb = gtk_vbox_new(FALSE, 0);
|
|
gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
|
|
gtk_container_add(GTK_CONTAINER(main_w), main_vb);
|
|
gtk_widget_show(main_vb);
|
|
|
|
/* Container for each row of widgets */
|
|
profile_vb = gtk_vbox_new(FALSE, 0);
|
|
gtk_container_set_border_width(GTK_CONTAINER(profile_vb), 0);
|
|
gtk_container_add(GTK_CONTAINER(main_vb), profile_vb);
|
|
gtk_widget_show(profile_vb);
|
|
|
|
/* Top row: Buttons and profile list */
|
|
top_hb = gtk_hbox_new(FALSE, 0);
|
|
gtk_container_add(GTK_CONTAINER(profile_vb), top_hb);
|
|
gtk_widget_show(top_hb);
|
|
|
|
edit_fr = gtk_frame_new("Edit");
|
|
gtk_box_pack_start(GTK_BOX(top_hb), edit_fr, FALSE, FALSE, 0);
|
|
gtk_widget_show(edit_fr);
|
|
|
|
list_bb = gtk_vbox_new(TRUE, 0);
|
|
gtk_container_set_border_width(GTK_CONTAINER(list_bb), 5);
|
|
gtk_container_add(GTK_CONTAINER(edit_fr), list_bb);
|
|
gtk_widget_show(list_bb);
|
|
|
|
new_bt = gtk_button_new_from_stock(GTK_STOCK_NEW);
|
|
g_signal_connect(new_bt, "clicked", G_CALLBACK(profile_new_bt_clicked_cb), NULL);
|
|
gtk_widget_show(new_bt);
|
|
gtk_box_pack_start (GTK_BOX (list_bb), new_bt, FALSE, FALSE, 0);
|
|
gtk_tooltips_set_tip (tooltips, new_bt,
|
|
"Create a new profile (with default properties)", NULL);
|
|
|
|
#if 0
|
|
copy_bt = gtk_button_new_from_stock(GTK_STOCK_COPY);
|
|
gtk_widget_set_sensitive(copy_bt, FALSE);
|
|
g_signal_connect(copy_bt, "clicked", G_CALLBACK(profile_copy_bt_clicked_cb), NULL);
|
|
g_object_set_data(G_OBJECT(main_w), E_PROF_COPY_BT_KEY, copy_bt);
|
|
gtk_widget_show(copy_bt);
|
|
gtk_box_pack_start (GTK_BOX (list_bb), copy_bt, FALSE, FALSE, 0);
|
|
gtk_tooltips_set_tip (tooltips, copy_bt,
|
|
"Copy the selected profile", NULL);
|
|
#endif
|
|
|
|
del_bt = gtk_button_new_from_stock(GTK_STOCK_DELETE);
|
|
gtk_widget_set_sensitive(del_bt, FALSE);
|
|
g_signal_connect(del_bt, "clicked", G_CALLBACK(profile_del_bt_clicked_cb), NULL);
|
|
g_object_set_data(G_OBJECT(main_w), E_PROF_DEL_BT_KEY, del_bt);
|
|
gtk_widget_show(del_bt);
|
|
gtk_box_pack_start (GTK_BOX (list_bb), del_bt, FALSE, FALSE, 0);
|
|
gtk_tooltips_set_tip (tooltips, del_bt, "Delete the selected profile", NULL);
|
|
|
|
profile_fr = gtk_frame_new("Configuration Profiles");
|
|
gtk_box_pack_start(GTK_BOX(top_hb), profile_fr, TRUE, TRUE, 0);
|
|
gtk_widget_show(profile_fr);
|
|
|
|
profile_sc = scrolled_window_new(NULL, NULL);
|
|
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(profile_sc),
|
|
GTK_SHADOW_IN);
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (profile_sc), 5);
|
|
gtk_container_add(GTK_CONTAINER(profile_fr), profile_sc);
|
|
gtk_widget_show(profile_sc);
|
|
|
|
store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
|
|
profile_l = tree_view_new(GTK_TREE_MODEL(store));
|
|
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(profile_l), FALSE);
|
|
renderer = gtk_cell_renderer_text_new();
|
|
column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL);
|
|
gtk_tree_view_column_set_sort_column_id(column, 0);
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(profile_l), column);
|
|
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
|
|
gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
|
|
g_signal_connect(sel, "changed", G_CALLBACK(profile_sel_list_cb), profile_vb);
|
|
g_signal_connect(profile_l, "button_press_event", G_CALLBACK(profile_button_press_cb), NULL);
|
|
g_signal_connect(profile_l, "key_release_event", G_CALLBACK(profile_key_release_cb), NULL);
|
|
g_object_set_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY, profile_l);
|
|
gtk_container_add(GTK_CONTAINER(profile_sc), profile_l);
|
|
gtk_widget_show(profile_l);
|
|
|
|
/* fill in data */
|
|
l_select = fill_list(main_w);
|
|
|
|
g_object_unref(G_OBJECT(store));
|
|
|
|
props_fr = gtk_frame_new("Properties");
|
|
gtk_box_pack_start(GTK_BOX(profile_vb), props_fr, FALSE, FALSE, 0);
|
|
gtk_widget_show(props_fr);
|
|
|
|
props_vb = gtk_vbox_new(FALSE, 3);
|
|
gtk_container_set_border_width(GTK_CONTAINER(props_vb), 5);
|
|
gtk_container_add(GTK_CONTAINER(props_fr), props_vb);
|
|
gtk_widget_show(props_vb);
|
|
|
|
/* row: Profile name entry */
|
|
middle_hb = gtk_hbox_new(FALSE, 3);
|
|
gtk_container_add(GTK_CONTAINER(props_vb), middle_hb);
|
|
gtk_widget_show(middle_hb);
|
|
|
|
name_lb = gtk_label_new("Profile name:");
|
|
gtk_box_pack_start(GTK_BOX(middle_hb), name_lb, FALSE, FALSE, 0);
|
|
gtk_widget_show(name_lb);
|
|
|
|
name_te = gtk_entry_new();
|
|
gtk_box_pack_start(GTK_BOX(middle_hb), name_te, TRUE, TRUE, 0);
|
|
g_object_set_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY, name_te);
|
|
g_signal_connect(name_te, "changed", G_CALLBACK(profile_name_te_changed_cb), NULL);
|
|
#ifdef _WIN32
|
|
gtk_tooltips_set_tip (tooltips, name_te, "A profile name cannot start or end with a period (.), and cannot contain any of the following characters:\n \\ / : * ? \" < > |", NULL);
|
|
#else
|
|
gtk_tooltips_set_tip (tooltips, name_te, "A profile name cannot contain the '/' character", NULL);
|
|
#endif
|
|
gtk_widget_show(name_te);
|
|
|
|
/* button row (create all possible buttons and hide the unrequired later - it's a lot easier) */
|
|
bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_CANCEL, GTK_STOCK_HELP, NULL);
|
|
gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 5);
|
|
gtk_widget_show(bbox);
|
|
|
|
ok_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
|
|
g_signal_connect(ok_bt, "clicked", G_CALLBACK(profile_dlg_ok_cb), NULL);
|
|
gtk_tooltips_set_tip (tooltips, ok_bt, "Apply the profiles and close this dialog", NULL);
|
|
|
|
/* Catch the "activate" signal on the profile name and profile
|
|
list entries, so that if the user types Return
|
|
there, we act as if the "OK" button had been selected, as
|
|
happens if Return is typed if some widget that *doesn't*
|
|
handle the Return key has the input focus. */
|
|
dlg_set_activate(name_te, ok_bt);
|
|
|
|
apply_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_APPLY);
|
|
g_signal_connect(apply_bt, "clicked", G_CALLBACK(profile_dlg_apply_cb), NULL);
|
|
gtk_tooltips_set_tip (tooltips, apply_bt, "Apply the profiles and keep this dialog open", NULL);
|
|
|
|
cancel_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
|
|
gtk_tooltips_set_tip (tooltips, cancel_bt, "Cancel the changes", NULL);
|
|
g_signal_connect(cancel_bt, "clicked", G_CALLBACK(profile_dlg_cancel_cb), NULL);
|
|
window_set_cancel_button(main_w, cancel_bt, NULL);
|
|
|
|
help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
|
|
g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_CONFIG_PROFILES_DIALOG);
|
|
gtk_tooltips_set_tip (tooltips, help_bt, "Show topic specific help", NULL);
|
|
|
|
if(ok_bt) {
|
|
gtk_widget_grab_default(ok_bt);
|
|
}
|
|
|
|
|
|
/* DO SELECTION THINGS *AFTER* SHOWING THE DIALOG! */
|
|
/* otherwise the updatings can get confused */
|
|
if (l_select) {
|
|
gtk_tree_selection_select_iter(sel, l_select);
|
|
g_free(l_select);
|
|
}
|
|
|
|
if (profile_l) {
|
|
gtk_widget_grab_focus(profile_l);
|
|
}
|
|
|
|
g_signal_connect(main_w, "delete_event", G_CALLBACK(profile_dlg_delete_event_cb), NULL);
|
|
g_signal_connect(main_w, "destroy", G_CALLBACK(profile_dlg_destroy_cb), NULL);
|
|
|
|
gtk_widget_show(main_w);
|
|
|
|
window_present(main_w);
|
|
|
|
return main_w;
|
|
}
|
|
|
|
|
|
static void
|
|
select_profile_cb (GtkWidget *w _U_, gpointer data)
|
|
{
|
|
const gchar *current_profile = get_profile_name ();
|
|
gchar *selected_profile = (gchar *) data;
|
|
|
|
if (strcmp (selected_profile, current_profile) != 0) {
|
|
change_configuration_profile (selected_profile);
|
|
}
|
|
}
|
|
|
|
gboolean
|
|
profile_show_popup_cb (GtkWidget *w _U_, GdkEvent *event)
|
|
{
|
|
GdkEventButton *bevent = (GdkEventButton *)event;
|
|
const gchar *profile_name = get_profile_name ();
|
|
const gchar *profiles_dir, *name;
|
|
ETH_DIR *dir; /* scanned directory */
|
|
ETH_DIRENT *file; /* current file */
|
|
GtkWidget *menu;
|
|
GtkWidget *menu_item;
|
|
|
|
menu = gtk_menu_new ();
|
|
|
|
/* Add a menu item for the Default profile */
|
|
menu_item = gtk_check_menu_item_new_with_label (DEFAULT_PROFILE);
|
|
if (strcmp (profile_name, DEFAULT_PROFILE)==0) {
|
|
/* Check current profile */
|
|
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(menu_item), TRUE);
|
|
}
|
|
g_object_set (G_OBJECT(menu_item), "draw-as-radio", TRUE, NULL);
|
|
g_signal_connect (menu_item, "activate", G_CALLBACK(select_profile_cb), g_strdup (DEFAULT_PROFILE));
|
|
gtk_menu_append (menu, menu_item);
|
|
gtk_widget_show (menu_item);
|
|
|
|
profiles_dir = get_profiles_dir();
|
|
if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
|
|
while ((file = ws_dir_read_name(dir)) != NULL) {
|
|
name = ws_dir_get_name(file);
|
|
|
|
if (profile_exists(name)) {
|
|
menu_item = gtk_check_menu_item_new_with_label (name);
|
|
if (strcmp (name, profile_name)==0) {
|
|
/* Check current profile */
|
|
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(menu_item), TRUE);
|
|
}
|
|
g_object_set (G_OBJECT(menu_item), "draw-as-radio", TRUE, NULL);
|
|
g_signal_connect (menu_item, "activate", G_CALLBACK(select_profile_cb), g_strdup (name));
|
|
gtk_menu_append (menu, menu_item);
|
|
gtk_widget_show (menu_item);
|
|
}
|
|
}
|
|
}
|
|
|
|
gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL,
|
|
bevent->button, bevent->time);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Create a profile dialog for editing display profiles; this is to be used
|
|
as a callback for menu items, toolbars, etc.. */
|
|
void
|
|
profile_dialog_cb(GtkWidget *w _U_)
|
|
{
|
|
/* Has a profiles dialog box already been opened */
|
|
if (global_profile_w != NULL) {
|
|
/* Yes. Just reactivate it. */
|
|
reactivate_window(global_profile_w);
|
|
} else {
|
|
global_profile_w = profile_dialog_new ();
|
|
}
|
|
}
|
|
|