diff options
author | Stig Bjørlykke <stig@bjorlykke.org> | 2010-10-01 16:29:37 +0000 |
---|---|---|
committer | Stig Bjørlykke <stig@bjorlykke.org> | 2010-10-01 16:29:37 +0000 |
commit | 98f6aa93114eb9529bc8da961789a97e7f76e853 (patch) | |
tree | c2613e71492404ced8036ef24122b14520f30e68 | |
parent | 0c2f1829e17cfc1f8c825571c87234e9c3523314 (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.c | 6 | ||||
-rw-r--r-- | epan/filesystem.h | 5 | ||||
-rw-r--r-- | gtk/keys.h | 1 | ||||
-rw-r--r-- | gtk/main_statusbar.c | 7 | ||||
-rw-r--r-- | gtk/menus.c | 80 | ||||
-rw-r--r-- | gtk/menus.h | 6 | ||||
-rw-r--r-- | gtk/profile_dlg.c | 226 | ||||
-rw-r--r-- | gtk/profile_dlg.h | 28 |
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 |