aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStig Bjørlykke <stig@bjorlykke.org>2010-10-01 16:29:37 +0000
committerStig Bjørlykke <stig@bjorlykke.org>2010-10-01 16:29:37 +0000
commit98f6aa93114eb9529bc8da961789a97e7f76e853 (patch)
treec2613e71492404ced8036ef24122b14520f30e68
parent0c2f1829e17cfc1f8c825571c87234e9c3523314 (diff)
Add a new right-click popup menu for the statusbar profiles for easy functions
to create new, copy, delete and rename configuration profiles. svn path=/trunk/; revision=34312
-rw-r--r--epan/filesystem.c6
-rw-r--r--epan/filesystem.h5
-rw-r--r--gtk/keys.h1
-rw-r--r--gtk/main_statusbar.c7
-rw-r--r--gtk/menus.c80
-rw-r--r--gtk/menus.h6
-rw-r--r--gtk/profile_dlg.c226
-rw-r--r--gtk/profile_dlg.h28
8 files changed, 354 insertions, 5 deletions
diff --git a/epan/filesystem.c b/epan/filesystem.c
index b5e149029f..283ea30dd7 100644
--- a/epan/filesystem.c
+++ b/epan/filesystem.c
@@ -965,6 +965,12 @@ get_profile_name(void)
}
}
+gboolean
+is_default_profile(void)
+{
+ return (!persconfprofile || strcmp(persconfprofile, DEFAULT_PROFILE) == 0) ? TRUE : FALSE;
+}
+
void
profile_store_persconffiles(gboolean store)
{
diff --git a/epan/filesystem.h b/epan/filesystem.h
index ce5cc386bc..28d3ee926a 100644
--- a/epan/filesystem.h
+++ b/epan/filesystem.h
@@ -104,6 +104,11 @@ extern void set_profile_name(const gchar *profilename);
extern const char *get_profile_name(void);
/*
+ * Check if current profile is default profile.
+ */
+extern gboolean is_default_profile(void);
+
+/*
* Get the directory used to store configuration profile directories.
*/
extern const char *get_profiles_dir(void);
diff --git a/gtk/keys.h b/gtk/keys.h
index b8b2fba17e..bdbbfee2c6 100644
--- a/gtk/keys.h
+++ b/gtk/keys.h
@@ -53,6 +53,7 @@
#define PM_PACKET_LIST_KEY "popup_menu_packet_list"
#define PM_TREE_VIEW_KEY "popup_menu_tree_view"
#define PM_BYTES_VIEW_KEY "popup_menu_bytes_view"
+#define PM_STATUSBAR_PROFILES_KEY "popup_menu_statusbar_profiles"
#define E_TB_MAIN_KEY "toolbar_main"
#define E_TB_FILTER_KEY "toolbar_filter"
diff --git a/gtk/main_statusbar.c b/gtk/main_statusbar.c
index 4a11f454de..5a55c4e726 100644
--- a/gtk/main_statusbar.c
+++ b/gtk/main_statusbar.c
@@ -56,6 +56,8 @@
#include "gtk/profile_dlg.h"
#include "gtk/main_welcome.h"
#include "gtk/expert_indicators.h"
+#include "gtk/keys.h"
+#include "gtk/menus.h"
/*
* The order below defines the priority of info bar contexts.
@@ -411,6 +413,8 @@ profile_bar_new(void)
profile_bar = gtk_statusbar_new();
gtk_container_add(GTK_CONTAINER(profile_bar_event), profile_bar);
g_signal_connect(profile_bar_event, "button_press_event", G_CALLBACK(profile_show_popup_cb), NULL);
+ g_signal_connect(profile_bar_event, "button_press_event", G_CALLBACK(popup_menu_handler),
+ g_object_get_data(G_OBJECT(popup_menu_object), PM_STATUSBAR_PROFILES_KEY));
profile_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(profile_bar), "profile");
gtk_tooltips_set_tip (tooltips, profile_bar_event,
"Click to change configuration profile", NULL);
@@ -478,8 +482,9 @@ profile_bar_update(void)
}
profile_str = g_strdup_printf (" Profile: %s", get_profile_name ());
-
gtk_statusbar_push(GTK_STATUSBAR(profile_bar), profile_ctx, profile_str);
+
+ set_menus_for_profiles(is_default_profile());
}
}
diff --git a/gtk/menus.c b/gtk/menus.c
index c8779be5a0..07e8e967a8 100644
--- a/gtk/menus.c
+++ b/gtk/menus.c
@@ -44,7 +44,6 @@
#include <epan/plugins.h>
#include <epan/epan_dissect.h>
#include <epan/column.h>
-#include "gtk/dissector_tables_dlg.h"
#include "../print.h"
#include "../ui_util.h"
@@ -96,6 +95,7 @@
#include "gtk/gui_utils.h"
#include "gtk/manual_addr_resolv.h"
#include "gtk/proto_help.h"
+#include "gtk/dissector_tables_dlg.h"
#define MENUS_USE_UIMANAGER 1
@@ -2279,6 +2279,7 @@ static GtkUIManager *ui_manager_packet_list_heading = NULL;
static GtkUIManager *ui_manager_packet_list_menu = NULL;
static GtkUIManager *ui_manager_tree_view_menu = NULL;
static GtkUIManager *ui_manager_bytes_menu = NULL;
+static GtkUIManager *ui_manager_statusbar_profiles_menu = NULL;
#else
static GtkItemFactory *packet_list_heading_factory = NULL;
static GtkItemFactory *packet_list_menu_factory = NULL;
@@ -3458,6 +3459,32 @@ static const GtkRadioActionEntry bytes_menu_radio_action_entries [] =
{ "/HexView", NULL, "Hex View", NULL, NULL, BYTES_HEX },
{ "/BitsView", NULL, "Bits View", NULL, NULL, BYTES_BITS },
};
+
+static const char *ui_statusbar_profiles_menu_popup =
+"<ui>\n"
+" <popup name='ProfilesMenuPopup' action='PopupAction'>\n"
+" <menuitem name='Profiles' action='/Profiles'/>\n"
+" <separator/>\n"
+" <menuitem name='New' action='/New'/>\n"
+" <menuitem name='Copy' action='/Copy'/>\n"
+" <menuitem name='Delete' action='/Delete'/>\n"
+" <menuitem name='Rename' action='/Rename'/>\n"
+" <separator/>\n"
+" <menu name='Change' action='/Change'>\n"
+" <menuitem name='Default' action='/Change/Default'/>\n"
+" </menu>\n"
+" </popup>\n"
+"</ui>\n";
+static const GtkActionEntry statusbar_profiles_menu_action_entries [] =
+{
+ { "/Profiles", NULL, "Configuration Profiles...", NULL, NULL, G_CALLBACK(profile_dialog_cb) },
+ { "/New", GTK_STOCK_NEW, "New...", NULL, NULL, G_CALLBACK(profile_new_cb) },
+ { "/Copy", GTK_STOCK_COPY, "Copy...", NULL, NULL, G_CALLBACK(profile_copy_cb) },
+ { "/Delete", GTK_STOCK_DELETE, "Delete", NULL, NULL, G_CALLBACK(profile_delete_cb) },
+ { "/Rename", GTK_STOCK_EDIT, "Rename...", NULL, NULL, G_CALLBACK(profile_rename_cb) },
+ { "/Change", NULL, "Change", NULL, NULL, NULL },
+ { "/Change/Default", NULL, "Default", NULL, NULL, NULL },
+};
#endif
GtkWidget *
@@ -3617,7 +3644,8 @@ static void
menus_init(void) {
#ifdef MENUS_USE_UIMANAGER
GtkActionGroup *packet_list_heading_action_group, *packet_list_action_group,
- *packet_list_details_action_group, *packet_list_byte_menu_action_group;
+ *packet_list_details_action_group, *packet_list_byte_menu_action_group,
+ *statusbar_profiles_action_group;
GError *error = NULL;
#endif
@@ -3748,7 +3776,7 @@ menus_init(void) {
* for text widgets.
*/
#ifdef MENUS_USE_UIMANAGER
- packet_list_byte_menu_action_group = gtk_action_group_new ("PacketListDetailsMenuPopUpActionGroup");
+ packet_list_byte_menu_action_group = gtk_action_group_new ("PacketListByteMenuPopUpActionGroup");
gtk_action_group_add_radio_actions (packet_list_byte_menu_action_group, /* the action group */
@@ -3830,6 +3858,35 @@ menus_init(void) {
main_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", grp);
gtk_item_factory_create_items_ac(main_menu_factory, nmenu_items, menu_items, NULL, 2);
#endif /* MAIN_MENU_USE_UIMANAGER */
+
+#ifdef MENUS_USE_UIMANAGER
+ statusbar_profiles_action_group = gtk_action_group_new ("StatusBarProfilesPopUpMenuActionGroup");
+
+ gtk_action_group_add_actions (statusbar_profiles_action_group, /* the action group */
+ statusbar_profiles_menu_action_entries, /* an array of action descriptions */
+ G_N_ELEMENTS(statusbar_profiles_menu_action_entries), /* the number of entries */
+ popup_menu_object); /* data to pass to the action callbacks */
+
+ ui_manager_statusbar_profiles_menu = gtk_ui_manager_new ();
+ gtk_ui_manager_insert_action_group (ui_manager_statusbar_profiles_menu,
+ statusbar_profiles_action_group,
+ 0); /* the position at which the group will be inserted. */
+
+ gtk_ui_manager_add_ui_from_string (ui_manager_statusbar_profiles_menu,ui_statusbar_profiles_menu_popup, -1, &error);
+ if (error != NULL)
+ {
+ fprintf (stderr, "Warning: building Statusbar Profiles Pop-Up failed: %s\n",
+ error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+
+ g_object_set_data(G_OBJECT(popup_menu_object), PM_STATUSBAR_PROFILES_KEY,
+ gtk_ui_manager_get_widget(ui_manager_statusbar_profiles_menu, "/ProfilesMenuPopup"));
+
+ popup_menu_list = g_slist_append((GSList *)popup_menu_list, ui_manager_statusbar_profiles_menu);
+#endif /* MENUS_USE_UIMANAGER */
+
menu_dissector_filter();
merge_all_tap_menus(tap_menu_tree_root);
@@ -6866,6 +6923,23 @@ void set_menus_for_file_set(gboolean file_set, gboolean previous_file, gboolean
#endif /* MAIN_MENU_USE_UIMANAGER */
}
+GtkWidget *menus_get_profiles_menu (void)
+{
+#ifdef MENUS_USE_UIMANAGER
+ return gtk_ui_manager_get_widget(ui_manager_statusbar_profiles_menu, "/ProfilesMenuPopup/Change");
+#else
+ return NULL;
+#endif /* MENUS_USE_UIMANAGER */
+}
+
+void set_menus_for_profiles(gboolean default_profile)
+{
+#ifdef MENUS_USE_UIMANAGER
+ set_menu_sensitivity(ui_manager_statusbar_profiles_menu, "/ProfilesMenuPopup/Delete", !default_profile);
+ set_menu_sensitivity(ui_manager_statusbar_profiles_menu, "/ProfilesMenuPopup/Rename", !default_profile);
+#endif /* MENUS_USE_UIMANAGER */
+}
+
/*
* Editor modelines
*
diff --git a/gtk/menus.h b/gtk/menus.h
index fb41e07795..41b3e8fcc7 100644
--- a/gtk/menus.h
+++ b/gtk/menus.h
@@ -120,6 +120,9 @@ void menus_set_column_align_default (gboolean right_justify);
/* Update the packet list heading menu to indicate if column can be resolved. */
void menus_set_column_resolved (gboolean resolved, gboolean can_resolve);
+/* Fetch the statusbar profiles submenu */
+extern GtkWidget *menus_get_profiles_menu (void);
+
/* Enable or disable menu items based on whether a tree row is selected
and and on whether a "Match Selected" can be done. */
void set_menus_for_selected_tree_row(capture_file *cf);
@@ -142,6 +145,9 @@ void set_menus_for_captured_packets(gboolean);
/* Enable or disable menu items based on whether a packet is selected. */
void set_menus_for_selected_packet(capture_file *cf);
+/* Enable or disable menu items based on configuration profile */
+void set_menus_for_profiles(gboolean default_profile);
+
/*#define MAIN_MENU_USE_UIMANAGER 1 */
#ifdef MAIN_MENU_USE_UIMANAGER
diff --git a/gtk/profile_dlg.c b/gtk/profile_dlg.c
index 43c310538f..3da1dce8ce 100644
--- a/gtk/profile_dlg.c
+++ b/gtk/profile_dlg.c
@@ -39,6 +39,7 @@
#include <wsutil/file_util.h>
#include "gtk/main.h"
+#include "gtk/menus.h"
#include "gtk/profile_dlg.h"
#include "gtk/dlg_utils.h"
#include "gtk/gui_utils.h"
@@ -60,6 +61,10 @@ static GList *edited_profiles = NULL;
#define PROF_STAT_CHANGED 4
#define PROF_STAT_COPY 5
+#define PROF_OPERATION_NEW 1
+#define PROF_OPERATION_COPY 2
+#define PROF_OPERATION_EDIT 3
+
typedef struct {
char *name; /* profile name */
char *reference; /* profile reference */
@@ -242,7 +247,7 @@ fill_list(GtkWidget *main_w)
}
static gboolean
-profile_is_invalid_name(gchar *name)
+profile_is_invalid_name(const gchar *name)
{
gchar *message = NULL;
@@ -918,6 +923,11 @@ profile_show_popup_cb (GtkWidget *w _U_, GdkEvent *event, gpointer user_data _U_
menu = gtk_menu_new ();
+ if (bevent->button != 1) {
+ GtkWidget *top_menu = menus_get_profiles_menu ();
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM(top_menu), menu);
+ }
+
/* 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) {
@@ -948,12 +958,226 @@ profile_show_popup_cb (GtkWidget *w _U_, GdkEvent *event, gpointer user_data _U_
}
}
+ if (bevent->button != 1) {
+ /* Second-click is handled in popup_menu_handler() */
+ return FALSE;
+ }
+
gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL,
bevent->button, bevent->time);
return TRUE;
}
+static void
+profile_name_edit_ok (GtkWidget *w _U_, gpointer parent_w)
+{
+ gint operation = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(w), "operation"));
+ GtkWidget *entry = g_object_get_data (G_OBJECT(w), "entry");
+ const gchar *new_name = gtk_entry_get_text(GTK_ENTRY(entry));
+ const gchar *profile_name = get_profile_name();
+ char *pf_dir_path, *pf_dir_path2, *pf_filename;
+
+ if (strlen(new_name) == 0 || profile_is_invalid_name(new_name)) {
+ return;
+ }
+
+ if (operation == PROF_OPERATION_EDIT && strcmp(new_name, profile_name) == 0) {
+ /* Rename without a change, do nothing */
+ window_destroy(GTK_WIDGET(parent_w));
+ return;
+ }
+
+ if (profile_exists (new_name)) {
+ simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
+ "The profile already exists:\n%s.", new_name);
+ return;
+ }
+
+ switch (operation) {
+ case PROF_OPERATION_NEW:
+ if (create_persconffile_profile(new_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);
+ } else {
+ change_configuration_profile (new_name);
+ }
+ break;
+ case PROF_OPERATION_COPY:
+ if (create_persconffile_profile(new_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);
+ } else {
+ if (copy_persconffile_profile(new_name, profile_name, &pf_filename,
+ &pf_dir_path, &pf_dir_path2) == -1) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "Can't copy file \"%s\" in directory\n\"%s\" to\n\"%s\":\n%s.",
+ pf_filename, pf_dir_path2, pf_dir_path, strerror(errno));
+
+ g_free(pf_filename);
+ g_free(pf_dir_path);
+ g_free(pf_dir_path2);
+ } else {
+ change_configuration_profile (new_name);
+ }
+ }
+ break;
+ case PROF_OPERATION_EDIT:
+ if (rename_persconffile_profile(profile_name, new_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);
+ g_free(pf_dir_path2);
+ } else {
+ change_configuration_profile (new_name);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ window_destroy(GTK_WIDGET(parent_w));
+}
+
+static void
+profile_name_edit_cancel (GtkWidget *w _U_, gpointer parent_w)
+{
+ window_destroy(GTK_WIDGET(parent_w));
+}
+
+static void
+profile_name_edit_dlg (gint operation)
+{
+ GtkWidget *win, *main_tb, *main_vb, *bbox, *cancel_bt, *ok_bt;
+ GtkWidget *entry, *label;
+ gchar *window_title, *new_name;
+ const gchar *profile_name;
+ GtkTooltips *tooltips;
+
+ tooltips = gtk_tooltips_new();
+ profile_name = get_profile_name();
+
+ switch (operation) {
+ case PROF_OPERATION_NEW:
+ window_title = g_strdup ("Create New Profile");
+ break;
+ case PROF_OPERATION_COPY:
+ window_title = g_strdup_printf ("Copy: %s", profile_name);
+ break;
+ case PROF_OPERATION_EDIT:
+ window_title = g_strdup_printf ("Rename: %s", profile_name);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ win = dlg_window_new(window_title);
+ g_free (window_title);
+
+ gtk_window_set_resizable(GTK_WINDOW(win),FALSE);
+ gtk_window_resize(GTK_WINDOW(win), 400, 100);
+
+ main_vb = gtk_vbox_new(FALSE, 5);
+ gtk_container_add(GTK_CONTAINER(win), main_vb);
+ gtk_container_set_border_width(GTK_CONTAINER(main_vb), 6);
+
+ main_tb = gtk_table_new(2, 2, FALSE);
+ gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
+ gtk_table_set_col_spacings(GTK_TABLE(main_tb), 10);
+
+ label = gtk_label_new(ep_strdup_printf("Profile name:"));
+ gtk_table_attach_defaults(GTK_TABLE(main_tb), label, 0, 1, 1, 2);
+ gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
+
+ entry = gtk_entry_new();
+ gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2, 1, 2);
+ switch (operation) {
+ case PROF_OPERATION_NEW:
+ gtk_entry_set_text(GTK_ENTRY(entry), "New profile");
+ break;
+ case PROF_OPERATION_COPY:
+ new_name = g_strdup_printf ("%s (copy)", profile_name);
+ gtk_entry_set_text(GTK_ENTRY(entry), new_name);
+ g_free (new_name);
+ break;
+ case PROF_OPERATION_EDIT:
+ gtk_entry_set_text(GTK_ENTRY(entry), profile_name);
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+#ifdef _WIN32
+ gtk_tooltips_set_tip (tooltips, entry, "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, entry, "A profile name cannot contain the '/' character", NULL);
+#endif
+
+ bbox = dlg_button_row_new(GTK_STOCK_CANCEL,GTK_STOCK_OK, NULL);
+ gtk_box_pack_end(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
+
+ ok_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
+ g_object_set_data (G_OBJECT(ok_bt), "entry", entry);
+ g_object_set_data (G_OBJECT(ok_bt), "operation", GINT_TO_POINTER(operation));
+ g_signal_connect(ok_bt, "clicked", G_CALLBACK(profile_name_edit_ok), win);
+
+ dlg_set_activate(entry, ok_bt);
+
+ cancel_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
+ g_signal_connect(cancel_bt, "clicked", G_CALLBACK(profile_name_edit_cancel), win);
+ window_set_cancel_button(win, cancel_bt, NULL);
+
+ gtk_widget_grab_default(ok_bt);
+ gtk_widget_show_all(win);
+}
+
+void
+profile_new_cb (GtkWidget *w _U_, gpointer data _U_)
+{
+ profile_name_edit_dlg (PROF_OPERATION_NEW);
+}
+
+void
+profile_copy_cb (GtkWidget *w _U_, gpointer data _U_)
+{
+ profile_name_edit_dlg (PROF_OPERATION_COPY);
+}
+
+void
+profile_delete_cb (GtkWidget *w _U_, gpointer data _U_)
+{
+ const gchar *name = get_profile_name();
+ char *pf_dir_path;
+
+ if (profile_exists(name) && strcmp (name, DEFAULT_PROFILE) != 0) {
+ if (delete_persconffile_profile(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);
+ }
+
+ /* Change to the default profile */
+ change_configuration_profile (NULL);
+ }
+}
+
+void
+profile_rename_cb (GtkWidget *w _U_, gpointer data _U_)
+{
+ profile_name_edit_dlg (PROF_OPERATION_EDIT);
+}
+
/* Create a profile dialog for editing display profiles; this is to be used
as a callback for menu items, toolbars, etc.. */
void
diff --git a/gtk/profile_dlg.h b/gtk/profile_dlg.h
index 5ebe9e6a52..57e0d02e84 100644
--- a/gtk/profile_dlg.h
+++ b/gtk/profile_dlg.h
@@ -39,6 +39,34 @@
*/
gboolean profile_show_popup_cb(GtkWidget *w _U_, GdkEvent *event, gpointer user_data _U_);
+/** User requested to create a new profile.
+ *
+ * @param w parent widget (unused)
+ * @param data pointer to user_data (unused)
+ */
+void profile_new_cb (GtkWidget *w _U_, gpointer data _U_);
+
+/** User requested to copy the current profile.
+ *
+ * @param w parent widget (unused)
+ * @param data pointer to user_data (unused)
+ */
+void profile_copy_cb (GtkWidget *w _U_, gpointer data _U_);
+
+/** User requested to delete the current profile.
+ *
+ * @param w parent widget (unused)
+ * @param data pointer to user_data (unused)
+ */
+void profile_delete_cb (GtkWidget *w _U_, gpointer data _U_);
+
+/** User requested to rename the current profile.
+ *
+ * @param w parent widget (unused)
+ * @param data pointer to user_data (unused)
+ */
+void profile_rename_cb (GtkWidget *w _U_, gpointer data _U_);
+
/** User requested the "Configuration Profiles" dialog box by menu or toolbar.
*
* @param widget parent widget