From e91ca72a445d51b71f958f140e2eb89747f499ff Mon Sep 17 00:00:00 2001 From: Gerald Combs Date: Fri, 3 Jul 2015 15:52:49 -0500 Subject: Qt: Add initial Lua support. Add a FunnelStatistics class, which is the main interface between the Qt UI and the Funnel API. Add FunnelTextDialog, which implements the text_window, ProgDlg, menu, and other routines. Add FunnelStringDialog, which implements dlg_new. We currently only support "Tools" menu items (MENU_TOOLS_UNSORTED, aka REGISTER_TOOLS_GROUP_UNSORTED). Add a disabled placeholder to the "Tools" menu in case we don't load any scripts. Use "struct progdlg" instead of needlessly casting to funnel_progress_window_t. To do: - Add support for MENU_STAT_UNSORTED, MENU_STAT_GENERIC, etc. - Make the firewall config generator a Lua script? - Add FunnelGraphDialog? It seems like it would be useful to make QCustomPlot accessible to Lua scripts. Ping-Bug: 9845 Change-Id: Iefff02e9032ed1853666f7902509ed08b431e7a7 Reviewed-on: https://code.wireshark.org/review/9523 Petri-Dish: Gerald Combs Tested-by: Petri Dish Buildbot Reviewed-by: Gerald Combs --- color_filters.c | 2 +- color_filters.h | 2 +- epan/funnel.c | 1 + epan/funnel.h | 52 +++--- epan/wslua/wslua.h | 2 +- epan/wslua/wslua_gui.c | 14 +- ui/cli/tap-funnel.c | 1 + ui/gtk/funnel_stat.c | 34 ++-- ui/qt/CMakeLists.txt | 8 + ui/qt/Makefile.am | 4 + ui/qt/Makefile.common | 10 ++ ui/qt/Wireshark.pro | 8 + ui/qt/capture_file.cpp | 7 + ui/qt/capture_file.h | 3 + ui/qt/capture_file_progress_frame.cpp | 21 ++- ui/qt/funnel_statistics.cpp | 302 ++++++++++++++++++++++++++++++++++ ui/qt/funnel_statistics.h | 76 +++++++++ ui/qt/funnel_string_dialog.cpp | 101 ++++++++++++ ui/qt/funnel_string_dialog.h | 75 +++++++++ ui/qt/funnel_string_dialog.ui | 67 ++++++++ ui/qt/funnel_text_dialog.cpp | 239 +++++++++++++++++++++++++++ ui/qt/funnel_text_dialog.h | 98 +++++++++++ ui/qt/funnel_text_dialog.ui | 88 ++++++++++ ui/qt/main_window.cpp | 47 +++++- ui/qt/main_window.h | 6 +- ui/qt/main_window.ui | 21 +++ ui/qt/wireshark_application.cpp | 21 +++ ui/qt/wireshark_application.h | 2 + 28 files changed, 1255 insertions(+), 57 deletions(-) create mode 100644 ui/qt/funnel_statistics.cpp create mode 100644 ui/qt/funnel_statistics.h create mode 100644 ui/qt/funnel_string_dialog.cpp create mode 100644 ui/qt/funnel_string_dialog.h create mode 100644 ui/qt/funnel_string_dialog.ui create mode 100644 ui/qt/funnel_text_dialog.cpp create mode 100644 ui/qt/funnel_text_dialog.h create mode 100644 ui/qt/funnel_text_dialog.ui diff --git a/color_filters.c b/color_filters.c index 0cb8e6b57a..834c626c26 100644 --- a/color_filters.c +++ b/color_filters.c @@ -139,7 +139,7 @@ color_filters_find_by_name_cb(gconstpointer arg1, gconstpointer arg2) /* Set the filter off a temporary colorfilters and enable it */ void -color_filters_set_tmp(guint8 filt_nr, gchar *filter, gboolean disabled) +color_filters_set_tmp(guint8 filt_nr, const gchar *filter, gboolean disabled) { gchar *name = NULL; const gchar *tmpfilter = NULL; diff --git a/color_filters.h b/color_filters.h index 7fe8068011..098d1c5833 100644 --- a/color_filters.h +++ b/color_filters.h @@ -85,7 +85,7 @@ color_filters_enable(gboolean enable); * @param disabled whether the filter-rule should be disabled */ void -color_filters_set_tmp(guint8 filt_nr, gchar *filter, gboolean disabled); +color_filters_set_tmp(guint8 filt_nr, const gchar *filter, gboolean disabled); /** Reset the temporary color filters * diff --git a/epan/funnel.c b/epan/funnel.c index 876f84b57e..02cd4f1171 100644 --- a/epan/funnel.c +++ b/epan/funnel.c @@ -37,6 +37,7 @@ typedef struct _funnel_menu_t { struct _funnel_menu_t* next; } funnel_menu_t; +/* XXX This assumes one main window and one capture file. */ static const funnel_ops_t* ops = NULL; static funnel_menu_t* menus = NULL; diff --git a/epan/funnel.h b/epan/funnel.h index 3d66f54c63..b7e2ac1d01 100644 --- a/epan/funnel.h +++ b/epan/funnel.h @@ -23,17 +23,22 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef _FUNNEL_H -#define _FUNNEL_H +#ifndef __FUNNEL_H__ +#define __FUNNEL_H__ #include #include #include "ws_symbol_export.h" +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _funnel_ops_id_t funnel_ops_id_t; /* Opaque pointer to ops instance */ typedef struct _funnel_progress_window_t funnel_progress_window_t ; typedef struct _funnel_text_window_t funnel_text_window_t ; -typedef struct _funnel_tree_window_t funnel_tree_window_t ; -typedef struct _funnel_node_t funnel_node_t ; +typedef struct _funnel_tree_window_t funnel_tree_window_t ; /* XXX Unused? */ +typedef struct _funnel_node_t funnel_node_t ; /* XXX Unused? */ typedef void (*text_win_close_cb_t)(void*); @@ -49,17 +54,20 @@ typedef struct _funnel_bt_t { void (*free_data_fcn)(void*); } funnel_bt_t; +struct progdlg; + typedef struct _funnel_ops_t { - funnel_text_window_t* (*new_text_window)(const gchar* label); - void (*set_text)(funnel_text_window_t* win, const gchar* text); - void (*append_text)(funnel_text_window_t* win, const gchar* text); - void (*prepend_text)(funnel_text_window_t* win, const gchar* text); + funnel_ops_id_t *ops_id; + funnel_text_window_t* (*new_text_window)(const char* label); + void (*set_text)(funnel_text_window_t* win, const char* text); + void (*append_text)(funnel_text_window_t* win, const char* text); + void (*prepend_text)(funnel_text_window_t* win, const char* text); void (*clear_text)(funnel_text_window_t* win); - const gchar* (*get_text)(funnel_text_window_t* win); + const char* (*get_text)(funnel_text_window_t* win); void (*set_close_cb)(funnel_text_window_t* win, text_win_close_cb_t cb, void* data); void (*set_editable)(funnel_text_window_t* win, gboolean editable); void (*destroy_text_window)(funnel_text_window_t* win); - void (*add_button)(funnel_text_window_t* win, funnel_bt_t* cb, const gchar* label); + void (*add_button)(funnel_text_window_t* win, funnel_bt_t* cb, const char* label); void (*new_dialog)(const gchar* title, const gchar** fieldnames, @@ -73,22 +81,22 @@ typedef struct _funnel_ops_t { gpointer user_data); - void (*retap_packets)(void); + void (*retap_packets)(funnel_ops_id_t *ops_id); void (*copy_to_clipboard)(GString *str); - gchar * (*get_filter)(void); - void (*set_filter)(const char*); + const gchar * (*get_filter)(funnel_ops_id_t *ops_id); + void (*set_filter)(funnel_ops_id_t *ops_id, const char* filter); void (*set_color_filter_slot)(guint8 flit_nr, const gchar* filter); - gboolean (*open_file)(const char* fname, const char* filter, char** error); - void (*reload)(void); - void (*apply_filter)(void); + gboolean (*open_file)(funnel_ops_id_t *ops_id, const char* fname, const char* filter, char** error); + void (*reload)(funnel_ops_id_t *ops_id); + void (*apply_filter)(funnel_ops_id_t *ops_id); gboolean (*browser_open_url)(const gchar *url); void (*browser_open_data_file)(const gchar *filename); - funnel_progress_window_t* (*new_progress_window)(const gchar* label, const gchar* task, gboolean terminate_is_stop, gboolean *stop_flag); - void (*update_progress)(funnel_progress_window_t*, float pr, const gchar* task); - void (*destroy_progress_window)(funnel_progress_window_t*); + struct progdlg* (*new_progress_window)(funnel_ops_id_t *ops_id, const gchar* label, const gchar* task, gboolean terminate_is_stop, gboolean *stop_flag); + void (*update_progress)(struct progdlg*, float pr, const gchar* task); + void (*destroy_progress_window)(struct progdlg*); } funnel_ops_t; WS_DLL_PUBLIC const funnel_ops_t* funnel_get_funnel_ops(void); @@ -112,4 +120,8 @@ extern void initialize_funnel_ops(void); extern void funnel_dump_all_text_windows(void); -#endif +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __FUNNEL_H__ */ diff --git a/epan/wslua/wslua.h b/epan/wslua/wslua.h index 80a333618e..8d41607ee3 100644 --- a/epan/wslua/wslua.h +++ b/epan/wslua/wslua.h @@ -295,7 +295,7 @@ struct _wslua_dir { }; struct _wslua_progdlg { - funnel_progress_window_t* pw; + struct progdlg* pw; char* title; char* task; gboolean stopped; diff --git a/epan/wslua/wslua_gui.c b/epan/wslua/wslua_gui.c index c505eb15f6..0586293aa3 100644 --- a/epan/wslua/wslua_gui.c +++ b/epan/wslua/wslua_gui.c @@ -292,7 +292,7 @@ WSLUA_CONSTRUCTOR ProgDlg_new(lua_State* L) { /* Creates a new `ProgDlg` progres pd->stopped = FALSE; if (ops->new_progress_window) { - pd->pw = ops->new_progress_window(pd->title,pd->task,TRUE,&(pd->stopped)); + pd->pw = ops->new_progress_window(ops->ops_id, pd->title, pd->task, TRUE, &(pd->stopped)); } else { WSLUA_ERROR(ProgDlg_new, "GUI not available"); return 0; @@ -697,7 +697,7 @@ WSLUA_FUNCTION wslua_retap_packets(lua_State* L) { Rescan all packets and just run taps - don't reconstruct the display. */ if ( ops->retap_packets ) { - ops->retap_packets(); + ops->retap_packets(ops->ops_id); } else { WSLUA_ERROR(wslua_retap_packets, "GUI not available"); } @@ -737,7 +737,7 @@ WSLUA_FUNCTION wslua_open_capture_file(lua_State* L) { /* Open and display a cap return 0; } - if (! ops->open_file(fname,filter,&error) ) { + if (! ops->open_file(ops->ops_id, fname, filter, &error) ) { lua_pushboolean(L,FALSE); if (error) { @@ -761,7 +761,7 @@ WSLUA_FUNCTION wslua_get_filter(lua_State* L) { /* Get the main filter text. */ return 0; } - filter_str = ops->get_filter(); + filter_str = ops->get_filter(ops->ops_id); lua_pushstring(L,filter_str); return 1; @@ -776,7 +776,7 @@ WSLUA_FUNCTION wslua_set_filter(lua_State* L) { /* Set the main filter text. */ return 0; } - ops->set_filter(filter_str); + ops->set_filter(ops->ops_id, filter_str); return 0; } @@ -803,7 +803,7 @@ WSLUA_FUNCTION wslua_apply_filter(lua_State* L) { /* Apply the filter in the mai return 0; } - ops->apply_filter(); + ops->apply_filter(ops->ops_id); return 0; } @@ -816,7 +816,7 @@ WSLUA_FUNCTION wslua_reload(lua_State* L) { /* Reload the current capture file. return 0; } - ops->reload(); + ops->reload(ops->ops_id); return 0; } diff --git a/ui/cli/tap-funnel.c b/ui/cli/tap-funnel.c index 0c79d89b97..fe42dcbe03 100644 --- a/ui/cli/tap-funnel.c +++ b/ui/cli/tap-funnel.c @@ -85,6 +85,7 @@ static void funnel_logger(const gchar *log_domain _U_, static const funnel_ops_t funnel_ops = { + NULL, new_text_window, text_window_set_text, text_window_append, diff --git a/ui/gtk/funnel_stat.c b/ui/gtk/funnel_stat.c index 319f80ec75..b791b423cd 100644 --- a/ui/gtk/funnel_stat.c +++ b/ui/gtk/funnel_stat.c @@ -141,7 +141,7 @@ static gboolean text_window_delete_event_cb(GtkWidget *win _U_, GdkEvent *event return TRUE; } -static funnel_text_window_t* new_text_window(const gchar* title) { +static funnel_text_window_t* new_text_window(const char* title) { funnel_text_window_t* tw = (funnel_text_window_t *)g_malloc(sizeof(funnel_text_window_t)); GtkWidget *txt_scrollw, *main_vb, *hbox; @@ -243,7 +243,7 @@ static void text_window_append(funnel_text_window_t* tw, const char *str) } -static void text_window_set_text(funnel_text_window_t* tw, const gchar* text) +static void text_window_set_text(funnel_text_window_t* tw, const char* text) { if (! tw->win) return; @@ -410,12 +410,11 @@ static void funnel_new_dialog(const gchar* title, dd->dlg_cb = dlg_cb; dd->data = data; - for (i=0; fieldnames[i]; i++); - win = dlg_window_new(title); dd->win = win; + for (i=0; fieldnames[i]; i++); gtk_window_resize(GTK_WINDOW(win),400,10*(i+2)); main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE); @@ -457,11 +456,11 @@ static void funnel_new_dialog(const gchar* title, gtk_widget_show(win); } -static gchar * funnel_get_filter(void) { - return (gchar *)gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget)); +static const gchar * funnel_get_filter(funnel_ops_id_t *ops_id _U_ _U_) { + return gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget)); } -static void funnel_set_filter(const char* filter_string) { +static void funnel_set_filter(funnel_ops_id_t *ops_id _U_, const char* filter_string) { gtk_entry_set_text(GTK_ENTRY(main_display_filter_widget), filter_string); } @@ -469,7 +468,7 @@ static void funnel_set_color_filter_slot(guint8 filt_nr, const gchar* filter_str color_filters_set_tmp(filt_nr, (gchar *)filter_string, FALSE); } -static void funnel_apply_filter(void) { +static void funnel_apply_filter(funnel_ops_id_t *ops_id _U_) { const char* filter_string = gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget)); main_filter_packets(&cfile, filter_string, FALSE); } @@ -482,11 +481,11 @@ static void funnel_logger(const gchar *log_domain _U_, fputs(message,stderr); } -static void funnel_retap_packets(void) { +static void funnel_retap_packets(funnel_ops_id_t *ops_id _U_) { cf_retap_packets(&cfile); } -static gboolean funnel_open_file(const char* fname, const char* filter, char** err_str) { +static gboolean funnel_open_file(funnel_ops_id_t *ops_id _U_, const char* fname, const char* filter, char** err_str) { int err = 0; dfilter_t *rfcode = NULL; @@ -529,23 +528,24 @@ static gboolean funnel_open_file(const char* fname, const char* filter, char** e return TRUE; } -static funnel_progress_window_t* funnel_new_progress_window(const gchar* label, const gchar* task, gboolean terminate_is_stop, gboolean *stop_flag) { - return (funnel_progress_window_t*)create_progress_dlg(top_level, label, task, terminate_is_stop, stop_flag); +static struct progdlg* funnel_new_progress_window(funnel_ops_id_t *ops_id _U_, const gchar* label, const gchar* task, gboolean terminate_is_stop, gboolean *stop_flag) { + return create_progress_dlg(top_level, label, task, terminate_is_stop, stop_flag); } -static void funnel_update_progress(funnel_progress_window_t* win, float pr, const gchar* task) { - update_progress_dlg((progdlg_t*)win, pr, task); +static void funnel_update_progress(struct progdlg* win, float pr, const gchar* task) { + update_progress_dlg(win, pr, task); } -static void funnel_destroy_progress_window(funnel_progress_window_t* win) { - destroy_progress_dlg((progdlg_t*)win); +static void funnel_destroy_progress_window(struct progdlg* win) { + destroy_progress_dlg(win); } -static void funnel_reload(void) { +static void funnel_reload(funnel_ops_id_t *ops_id _U_) { if (cfile.state == FILE_READ_DONE) cf_reload(&cfile); } static const funnel_ops_t funnel_ops = { + NULL, /* ops_id */ new_text_window, text_window_set_text, text_window_append, diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt index dbd57ad3c0..bb64a01df4 100644 --- a/ui/qt/CMakeLists.txt +++ b/ui/qt/CMakeLists.txt @@ -63,6 +63,9 @@ set(WIRESHARK_QT_HEADERS follow_stream_dialog.h follow_stream_text.h font_color_preferences_frame.h + funnel_string_dialog.h + funnel_text_dialog.h + funnel_statistics.h import_text_dialog.h interface_tree.h io_graph_dialog.h @@ -182,6 +185,8 @@ set(WIRESHARK_QT_SRC follow_stream_dialog.cpp follow_stream_text.cpp font_color_preferences_frame.cpp + funnel_string_dialog.cpp + funnel_text_dialog.cpp import_text_dialog.cpp interface_tree.cpp label_stack.cpp @@ -262,6 +267,7 @@ endif() set(WIRESHARK_QT_TAP_SRC conversation_dialog.cpp endpoint_dialog.cpp + funnel_statistics.cpp io_graph_dialog.cpp stats_tree_dialog.cpp ) @@ -293,6 +299,8 @@ set(WIRESHARK_QT_UI filter_expressions_preferences_frame.ui follow_stream_dialog.ui font_color_preferences_frame.ui + funnel_string_dialog.ui + funnel_text_dialog.ui import_text_dialog.ui io_graph_dialog.ui layout_preferences_frame.ui diff --git a/ui/qt/Makefile.am b/ui/qt/Makefile.am index 01cd6ab54b..cc9ff5aa1c 100644 --- a/ui/qt/Makefile.am +++ b/ui/qt/Makefile.am @@ -164,6 +164,10 @@ follow_stream_dialog.cpp: ui_follow_stream_dialog.h font_color_preferences_frame.cpp font_color_preferences_frame.h: ui_font_color_preferences_frame.h +funnel_string_dialog.cpp funnel_string_dialog.h: ui_funnel_string_dialog.h + +funnel_text_dialog.cpp funnel_text_dialog.h: ui_funnel_text_dialog.h + import_text_dialog.cpp import_text_dialog.h: ui_import_text_dialog.h io_graph_dialog.cpp io_graph_dialog.h: ui_io_graph_dialog.h diff --git a/ui/qt/Makefile.common b/ui/qt/Makefile.common index 9536d983ca..1e89b4c94b 100644 --- a/ui/qt/Makefile.common +++ b/ui/qt/Makefile.common @@ -51,6 +51,8 @@ NODIST_GENERATED_HEADER_FILES = \ ui_filter_expressions_preferences_frame.h \ ui_follow_stream_dialog.h \ ui_font_color_preferences_frame.h \ + ui_funnel_string_dialog.h \ + ui_funnel_text_dialog.h \ ui_import_text_dialog.h \ ui_io_graph_dialog.h \ ui_layout_preferences_frame.h \ @@ -168,6 +170,9 @@ MOC_HDRS = \ follow_stream_dialog.h \ follow_stream_text.h \ font_color_preferences_frame.h \ + funnel_string_dialog.h \ + funnel_text_dialog.h \ + funnel_statistics.h \ import_text_dialog.h \ interface_tree.h \ io_graph_dialog.h \ @@ -254,6 +259,8 @@ UI_FILES = \ filter_expressions_preferences_frame.ui \ follow_stream_dialog.ui \ font_color_preferences_frame.ui \ + funnel_string_dialog.ui \ + funnel_text_dialog.ui \ import_text_dialog.ui \ io_graph_dialog.ui \ layout_preferences_frame.ui \ @@ -387,6 +394,9 @@ WIRESHARK_QT_SRC = \ follow_stream_dialog.cpp \ follow_stream_text.cpp \ font_color_preferences_frame.cpp \ + funnel_string_dialog.cpp \ + funnel_text_dialog.cpp \ + funnel_statistics.cpp \ import_text_dialog.cpp \ interface_tree.cpp \ io_graph_dialog.cpp \ diff --git a/ui/qt/Wireshark.pro b/ui/qt/Wireshark.pro index f9d6a2b689..72140d221e 100644 --- a/ui/qt/Wireshark.pro +++ b/ui/qt/Wireshark.pro @@ -227,6 +227,8 @@ FORMS += \ filter_expressions_preferences_frame.ui \ follow_stream_dialog.ui \ font_color_preferences_frame.ui \ + funnel_string_dialog.ui \ + funnel_text_dialog.ui \ import_text_dialog.ui \ io_graph_dialog.ui \ layout_preferences_frame.ui \ @@ -299,6 +301,9 @@ HEADERS += $$HEADERS_WS_C \ follow_stream_dialog.h \ follow_stream_text.h \ font_color_preferences_frame.h \ + funnel_string_dialog.h \ + funnel_text_dialog.h \ + funnel_statistics.h \ layout_preferences_frame.h \ lbm_lbtrm_transport_dialog.h \ lbm_lbtru_transport_dialog.h \ @@ -662,6 +667,9 @@ SOURCES += \ follow_stream_dialog.cpp \ follow_stream_text.cpp \ font_color_preferences_frame.cpp \ + funnel_string_dialog.cpp \ + funnel_text_dialog.cpp \ + funnel_statistics.cpp \ import_text_dialog.cpp \ interface_tree.cpp \ io_graph_dialog.cpp \ diff --git a/ui/qt/capture_file.cpp b/ui/qt/capture_file.cpp index 37358e044d..82a26d1f19 100644 --- a/ui/qt/capture_file.cpp +++ b/ui/qt/capture_file.cpp @@ -96,6 +96,13 @@ void CaptureFile::retapPackets() } } +void CaptureFile::reload() +{ + if (cap_file_ && cap_file_->state == FILE_READ_DONE) { + cf_reload(cap_file_); + } +} + void CaptureFile::stopLoading() { setCaptureStopFlag(true); diff --git a/ui/qt/capture_file.h b/ui/qt/capture_file.h index 9fd8ba92c8..a4b77fdaaf 100644 --- a/ui/qt/capture_file.h +++ b/ui/qt/capture_file.h @@ -72,6 +72,9 @@ public: */ void retapPackets(); + /** Re;load the capture file + */ + void reload(); // XXX This shouldn't be needed. static capture_file *globalCapFile(); diff --git a/ui/qt/capture_file_progress_frame.cpp b/ui/qt/capture_file_progress_frame.cpp index 2a42958d26..329510f715 100644 --- a/ui/qt/capture_file_progress_frame.cpp +++ b/ui/qt/capture_file_progress_frame.cpp @@ -38,14 +38,10 @@ // - Start adding the progress bar to dialogs. // - Don't complain so loudly when the user stops a capture. -progdlg_t * -delayed_create_progress_dlg(const gpointer top_level_window, const gchar *task_title, const gchar *item_title, - gboolean terminate_is_stop, gboolean *stop_flag, - const GTimeVal *start_time, gfloat progress) -{ +progdlg_t *create_progress_dlg(const gpointer top_level_window, const gchar *task_title, const gchar *item_title, + gboolean terminate_is_stop, gboolean *stop_flag) { Q_UNUSED(task_title); Q_UNUSED(item_title); - Q_UNUSED(start_time); CaptureFileProgressFrame *cfpf; QWidget *main_window; @@ -65,7 +61,18 @@ delayed_create_progress_dlg(const gpointer top_level_window, const gchar *task_t if (!cfpf) { return NULL; } - return cfpf->show(true, terminate_is_stop, stop_flag, progress * 100); + return cfpf->show(true, terminate_is_stop, stop_flag, 0); +} + +progdlg_t * +delayed_create_progress_dlg(const gpointer top_level_window, const gchar *task_title, const gchar *item_title, + gboolean terminate_is_stop, gboolean *stop_flag, + const GTimeVal *start_time, gfloat progress) +{ + Q_UNUSED(start_time); + progdlg_t *progress_dialog = create_progress_dlg(top_level_window, task_title, item_title, terminate_is_stop, stop_flag); + update_progress_dlg(progress_dialog, progress, item_title); + return progress_dialog; } /* diff --git a/ui/qt/funnel_statistics.cpp b/ui/qt/funnel_statistics.cpp new file mode 100644 index 0000000000..d2d1ee3063 --- /dev/null +++ b/ui/qt/funnel_statistics.cpp @@ -0,0 +1,302 @@ +/* funnel_statistics.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include + +#include "color.h" +#include "color_filters.h" +#include "file.h" + +#include "epan/funnel.h" + +#include "ui/progress_dlg.h" + +#include "funnel_statistics.h" +#include "funnel_string_dialog.h" +#include "funnel_text_dialog.h" + +#include +#include +#include +#include +#include + +#include "wireshark_application.h" + +// To do: +// - Handle menu paths. Do we create a new path (GTK+) or use the base element? +// - Add a FunnelGraphDialog class? + +extern "C" { +static void funnel_statistics_logger(const gchar *, GLogLevelFlags, const gchar *message, gpointer); +static void funnel_statistics_retap_packets(funnel_ops_id_t *ops_id); +static void funnel_statistics_copy_to_clipboard(GString *text); +static const gchar *funnel_statistics_get_filter(funnel_ops_id_t *ops_id); +static void funnel_statistics_set_filter(funnel_ops_id_t *ops_id, const char* filter_string); +static void funnel_statistics_set_color_filter_slot(guint8 filter_num, const gchar* filter_string); +static gboolean funnel_statistics_open_file(funnel_ops_id_t *ops_id, const char* fname, const char* filter, char**); +static void funnel_statistics_reload(funnel_ops_id_t *ops_id); +static void funnel_statistics_apply_filter(funnel_ops_id_t *ops_id); +static gboolean browser_open_url(const gchar *url); +static void browser_open_data_file(const gchar *filename); +static struct progdlg *progress_window_new(funnel_ops_id_t *ops_id, const gchar* title, const gchar* task, gboolean terminate_is_stop, gboolean *stop_flag); +static void progress_window_update(struct progdlg *progress_dialog, float percentage, const gchar* status); +static void progress_window_destroy(struct progdlg *progress_dialog); +} + +class FunnelAction : public QAction +{ +public: + FunnelAction(const QString title, void (*callback)(gpointer), gpointer callback_data, gboolean retap) : + QAction(NULL), + callback_(callback), + callback_data_(callback_data), + retap_(retap) + { + setText(title); + } + + void triggerCallback() { + if (callback_) { + callback_(callback_data_); + } + } + + bool retap() { + if (retap_) return true; + return false; + } + +private: + void (*callback_)(gpointer); + gpointer callback_data_; + gboolean retap_; +}; + +static QList funnel_actions_; + +FunnelStatistics::FunnelStatistics(QObject *parent, CaptureFile &cf) : + QObject(parent), + capture_file_(cf) +{ + funnel_ops_ = new(struct _funnel_ops_t); + memset(funnel_ops_, 0, sizeof(struct _funnel_ops_t)); + + funnel_ops_->ops_id = (funnel_ops_id_t*) this; + funnel_ops_->new_text_window = text_window_new; + funnel_ops_->set_text = text_window_set_text; + funnel_ops_->append_text = text_window_append; + funnel_ops_->prepend_text = text_window_prepend; + funnel_ops_->clear_text = text_window_clear; + funnel_ops_->get_text = text_window_get_text; + funnel_ops_->set_close_cb = text_window_set_close_cb; + funnel_ops_->set_editable = text_window_set_editable; + funnel_ops_->destroy_text_window = text_window_destroy; + funnel_ops_->add_button = text_window_add_button; + funnel_ops_->new_dialog = string_dialog_new; + funnel_ops_->logger = funnel_statistics_logger; + funnel_ops_->retap_packets = funnel_statistics_retap_packets; + funnel_ops_->copy_to_clipboard = funnel_statistics_copy_to_clipboard; + funnel_ops_->get_filter = funnel_statistics_get_filter; + funnel_ops_->set_filter = funnel_statistics_set_filter; + funnel_ops_->set_color_filter_slot = funnel_statistics_set_color_filter_slot; + funnel_ops_->open_file = funnel_statistics_open_file; + funnel_ops_->reload = funnel_statistics_reload; + funnel_ops_->apply_filter = funnel_statistics_apply_filter; + funnel_ops_->browser_open_url = browser_open_url; + funnel_ops_->browser_open_data_file = browser_open_data_file; + funnel_ops_->new_progress_window = progress_window_new; + funnel_ops_->update_progress = progress_window_update; + funnel_ops_->destroy_progress_window = progress_window_destroy; + + funnel_set_funnel_ops(funnel_ops_); +} + +void FunnelStatistics::retapPackets() +{ + capture_file_.retapPackets(); +} + +struct progdlg *FunnelStatistics::progressDialogNew(const gchar *task_title, const gchar *item_title, gboolean terminate_is_stop, gboolean *stop_flag) +{ + return create_progress_dlg(capture_file_.window(), task_title, item_title, terminate_is_stop, stop_flag); +} + +const char *FunnelStatistics::displayFilter() +{ + return display_filter_.constData(); +} + +void FunnelStatistics::emitSetDisplayFilter(const QString &filter) +{ + emit setDisplayFilter(filter); +} + +void FunnelStatistics::reloadPackets() +{ + capture_file_.reload(); +} + +void FunnelStatistics::emitApplyDisplayFilter() +{ + emit applyDisplayFilter(); +} + +void FunnelStatistics::emitOpenCaptureFile(QString &cf_path, QString &filter) +{ + emit openCaptureFile(cf_path, filter); +} + +void FunnelStatistics::funnelActionTriggered() +{ + FunnelAction *funnel_action = dynamic_cast(sender()); + if (!funnel_action) return; + + funnel_action->triggerCallback(); +} + +void FunnelStatistics::displayFilterTextChanged(const QString &filter) +{ + display_filter_ = filter.toUtf8(); +} + + +/* The GTK+ code says "finish this." We shall follow its lead */ +// XXX Finish this. +void funnel_statistics_logger(const gchar *, + GLogLevelFlags, + const gchar *message, + gpointer) { + qDebug() << message; +} +void funnel_statistics_retap_packets(funnel_ops_id_t *ops_id) { + FunnelStatistics *funnel_statistics = dynamic_cast((FunnelStatistics *)ops_id); + if (!funnel_statistics) return; + + funnel_statistics->retapPackets(); +} + +void funnel_statistics_copy_to_clipboard(GString *text) { + wsApp->clipboard()->setText(text->str); +} + +const gchar *funnel_statistics_get_filter(funnel_ops_id_t *ops_id) { + FunnelStatistics *funnel_statistics = dynamic_cast((FunnelStatistics *)ops_id); + if (!funnel_statistics) return NULL; + + return funnel_statistics->displayFilter(); +} + +void funnel_statistics_set_filter(funnel_ops_id_t *ops_id, const char* filter_string) { + FunnelStatistics *funnel_statistics = dynamic_cast((FunnelStatistics *)ops_id); + if (!funnel_statistics) return; + + funnel_statistics->emitSetDisplayFilter(filter_string); +} + +void funnel_statistics_set_color_filter_slot(guint8 filter_num, const gchar* filter_string) { + color_filters_set_tmp(filter_num, (gchar *)filter_string, FALSE); +} + +gboolean funnel_statistics_open_file(funnel_ops_id_t *ops_id, const char* fname, const char* filter, char**) { + // XXX We need to return a proper error value. We should probably move + // MainWindow::openCaptureFile to CaptureFile and add error handling + // there. + FunnelStatistics *funnel_statistics = dynamic_cast((FunnelStatistics *)ops_id); + if (!funnel_statistics) return FALSE; + + QString cf_name(fname); + QString cf_filter(filter); + funnel_statistics->emitOpenCaptureFile(cf_name, cf_filter); + return TRUE; +} + +void funnel_statistics_reload(funnel_ops_id_t *ops_id) { + FunnelStatistics *funnel_statistics = dynamic_cast((FunnelStatistics *)ops_id); + if (!funnel_statistics) return; + + funnel_statistics->reloadPackets(); +} + +void funnel_statistics_apply_filter(funnel_ops_id_t *ops_id) { + FunnelStatistics *funnel_statistics = dynamic_cast((FunnelStatistics *)ops_id); + if (!funnel_statistics) return; + + funnel_statistics->emitApplyDisplayFilter(); +} + +gboolean browser_open_url(const gchar *url) { + return QDesktopServices::openUrl(QUrl(url)) ? TRUE : FALSE; +} + +void browser_open_data_file(const gchar *filename) { + QDesktopServices::openUrl(QUrl::fromLocalFile(filename)); +} + +struct progdlg *progress_window_new(funnel_ops_id_t *ops_id, const gchar* task_title, const gchar* item_title, gboolean terminate_is_stop, gboolean *stop_flag) { + FunnelStatistics *funnel_statistics = dynamic_cast((FunnelStatistics *)ops_id); + if (!funnel_statistics) return NULL; + + return funnel_statistics->progressDialogNew(task_title, item_title, terminate_is_stop, stop_flag); +} + +void progress_window_update(struct progdlg *progress_dialog, float percentage, const gchar* status) { + update_progress_dlg(progress_dialog, percentage, status); +} + +void progress_window_destroy(progdlg *progress_dialog) { + destroy_progress_dlg(progress_dialog); +} + +extern "C" { + +static void register_menu_cb(const char *name, + register_stat_group_t group, + void (*callback)(gpointer), + gpointer callback_data, + gboolean retap) { + FunnelAction *funnel_action = new FunnelAction(name, callback, callback_data, retap); + wsApp->addFunnelGroupItem(group, funnel_action); + funnel_actions_ << funnel_action; +} + +void +register_tap_listener_qt_funnel(void) +{ + funnel_register_all_menus(register_menu_cb); +} + +} // extern "C" + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/qt/funnel_statistics.h b/ui/qt/funnel_statistics.h new file mode 100644 index 0000000000..ba8e2bf31d --- /dev/null +++ b/ui/qt/funnel_statistics.h @@ -0,0 +1,76 @@ +/* funnel_statistics.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FUNNELSTATISTICS_H +#define FUNNELSTATISTICS_H + +#include + +#include "capture_file.h" + +#include "funnel_text_dialog.h" + +struct _funnel_ops_t; +struct _funnel_progress_window_t; +struct progdlg; + +class FunnelStatistics : public QObject +{ + Q_OBJECT +public: + explicit FunnelStatistics(QObject *parent, CaptureFile &cf); + void retapPackets(); + struct progdlg *progressDialogNew(const gchar *task_title, const gchar *item_title, gboolean terminate_is_stop, gboolean *stop_flag); + const char *displayFilter(); + void emitSetDisplayFilter(const QString &filter); + void reloadPackets(); + void emitApplyDisplayFilter(); + void emitOpenCaptureFile(QString &cf_path, QString &filter); + +signals: + void setDisplayFilter(const QString &filter); + void applyDisplayFilter(); + void openCaptureFile(QString &cf_path, QString &filter); + +public slots: + void funnelActionTriggered(); + void displayFilterTextChanged(const QString &filter); + +private: + struct _funnel_ops_t *funnel_ops_; + CaptureFile &capture_file_; + QByteArray display_filter_; +}; + +#endif // FUNNELSTATISTICS_H + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/qt/funnel_string_dialog.cpp b/ui/qt/funnel_string_dialog.cpp new file mode 100644 index 0000000000..187acbfd27 --- /dev/null +++ b/ui/qt/funnel_string_dialog.cpp @@ -0,0 +1,101 @@ +/* funnel_string_dialog.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "funnel_string_dialog.h" +#include "ui_funnel_string_dialog.h" + +#include +#include + +#include "qt_ui_utils.h" +#include "wireshark_application.h" + +const int min_edit_width_ = 20; // em widths +FunnelStringDialog::FunnelStringDialog(const QString title, const QStringList field_name_list, funnel_dlg_cb_t dialog_cb, void *dialog_cb_data) : + QDialog(NULL), + ui(new Ui::FunnelStringDialog), + dialog_cb_(dialog_cb), + dialog_cb_data_(dialog_cb_data) +{ + ui->setupUi(this); + setWindowTitle(wsApp->windowTitleString(title)); + int one_em = fontMetrics().height(); + + int row = 0; + foreach (QString field_name, field_name_list) { + QLabel *field_label = new QLabel(field_name, this); + ui->stringGridLayout->addWidget(field_label, row, 0); + QLineEdit *field_edit = new QLineEdit(this); + field_edit->setMinimumWidth(one_em * min_edit_width_); + field_edits_ << field_edit; + ui->stringGridLayout->addWidget(field_edit, row, 1); + row++; + } +} + +FunnelStringDialog::~FunnelStringDialog() +{ + delete ui; +} + +void FunnelStringDialog::on_buttonBox_accepted() +{ + if (!dialog_cb_) return; + + GPtrArray* returns = g_ptr_array_new(); + + foreach (QLineEdit *field_edit, field_edits_) { + g_ptr_array_add(returns, qstring_strdup(field_edit->text())); + } + g_ptr_array_add(returns, NULL); + + dialog_cb_((gchar**)returns->pdata, dialog_cb_data_); + + g_ptr_array_free(returns, FALSE); +} + +void FunnelStringDialog::stringDialogNew(const QString title, const QStringList field_name_list, funnel_dlg_cb_t dialog_cb, void *dialog_cb_data) +{ + FunnelStringDialog *fsd = new FunnelStringDialog(title, field_name_list, dialog_cb, dialog_cb_data); + fsd->show(); +} + +void string_dialog_new(const gchar *title, const gchar **fieldnames, funnel_dlg_cb_t dialog_cb, void *dialog_cb_data) +{ + QStringList field_name_list; + for (int i = 0; fieldnames[i]; i++) { + field_name_list << fieldnames[i]; + } + FunnelStringDialog::stringDialogNew(title, field_name_list, dialog_cb, dialog_cb_data); +} + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/qt/funnel_string_dialog.h b/ui/qt/funnel_string_dialog.h new file mode 100644 index 0000000000..1f4dd9ae30 --- /dev/null +++ b/ui/qt/funnel_string_dialog.h @@ -0,0 +1,75 @@ +/* funnel_string_dialog.h + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FUNNEL_STRING_DIALOG_H +#define FUNNEL_STRING_DIALOG_H + +#include + +#include "epan/funnel.h" + +#include + +class QLineEdit; + +namespace Ui { +class FunnelStringDialog; +} + +class FunnelStringDialog : public QDialog +{ + Q_OBJECT + +public: + explicit FunnelStringDialog(const QString title, const QStringList field_name_list, funnel_dlg_cb_t dialog_cb, void *dialog_cb_data); + ~FunnelStringDialog(); + + // Funnel ops + static void stringDialogNew(const QString title, const QStringList field_name_list, funnel_dlg_cb_t dialog_cb, void* dialog_cb_data); + +private slots: + void on_buttonBox_accepted(); + +private: + Ui::FunnelStringDialog *ui; + funnel_dlg_cb_t dialog_cb_; + void *dialog_cb_data_; + QList field_edits_; +}; + +extern "C" { +void string_dialog_new(const gchar* title, const gchar** fieldnames, funnel_dlg_cb_t dialog_cb, void* dialog_cb_data); +} + +#endif // FUNNEL_STRING_DIALOG_H + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/qt/funnel_string_dialog.ui b/ui/qt/funnel_string_dialog.ui new file mode 100644 index 0000000000..c6ba7e2d10 --- /dev/null +++ b/ui/qt/funnel_string_dialog.ui @@ -0,0 +1,67 @@ + + + FunnelStringDialog + + + + 0 + 0 + 176 + 66 + + + + Dialog + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + FunnelStringDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + FunnelStringDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ui/qt/funnel_text_dialog.cpp b/ui/qt/funnel_text_dialog.cpp new file mode 100644 index 0000000000..7aee7d165b --- /dev/null +++ b/ui/qt/funnel_text_dialog.cpp @@ -0,0 +1,239 @@ +/* funnel_text_dialog.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "funnel_text_dialog.h" +#include "ui_funnel_text_dialog.h" + +#include +#include +#include +#include + +#include "qt_ui_utils.h" +#include "wireshark_application.h" + +// To do: +// - Add "Find next" to highlighting. +// - Add rich text support? +// - Zoom text? + +static QHash text_button_to_funnel_button_; + +FunnelTextDialog::FunnelTextDialog() : + QDialog(NULL), + ui(new Ui::FunnelTextDialog), + close_cb_(NULL), + close_cb_data_(NULL) +{ + ui->setupUi(this); + + funnel_text_window_.funnel_text_dialog = this; + + ui->textEdit->setFont(wsApp->monospaceFont()); + ui->textEdit->setReadOnly(true); + ui->textEdit->setAcceptRichText(false); +} + +FunnelTextDialog::~FunnelTextDialog() +{ + delete ui; + + if (close_cb_) { + close_cb_(close_cb_data_); + } +} + +struct _funnel_text_window_t *FunnelTextDialog::textWindowNew(const QString title) +{ + FunnelTextDialog *ftd = new FunnelTextDialog(); + ftd->setWindowTitle(wsApp->windowTitleString(title)); + ftd->show(); + return &ftd->funnel_text_window_; +} + +void FunnelTextDialog::setText(const QString text) +{ + ui->textEdit->setText(text); +} + +void FunnelTextDialog::appendText(const QString text) +{ + ui->textEdit->moveCursor(QTextCursor::Start); + ui->textEdit->insertPlainText(text); +} + +void FunnelTextDialog::prependText(const QString text) +{ + ui->textEdit->moveCursor(QTextCursor::End); + ui->textEdit->insertPlainText(text); +} + +void FunnelTextDialog::clearText() +{ + ui->textEdit->clear(); +} + +const char *FunnelTextDialog::getText() +{ + return qstring_strdup(ui->textEdit->toPlainText()); +} + +void FunnelTextDialog::setCloseCallback(text_win_close_cb_t close_cb, void *close_cb_data) +{ + close_cb_ = close_cb; + close_cb_data_ = close_cb_data; +} + +void FunnelTextDialog::setTextEditable(gboolean editable) +{ + ui->textEdit->setReadOnly(!editable); +} + +void FunnelTextDialog::addButton(funnel_bt_t *funnel_button, const QString label) +{ + QPushButton *button = new QPushButton(label); + ui->buttonBox->addButton(button, QDialogButtonBox::ActionRole); + text_button_to_funnel_button_[button] = funnel_button; + connect(button, SIGNAL(clicked(bool)), this, SLOT(buttonClicked())); +} + +void FunnelTextDialog::buttonClicked() +{ + if (text_button_to_funnel_button_.contains(sender())) { + funnel_bt_t *funnel_button = text_button_to_funnel_button_[sender()]; + if (funnel_button) { + funnel_button->func(&funnel_text_window_, funnel_button->data); + } + } +} + +void FunnelTextDialog::on_findLineEdit_textChanged(const QString &pattern) +{ + QRegExp re(pattern, Qt::CaseInsensitive); + QTextCharFormat plain_fmt, highlight_fmt; + highlight_fmt.setBackground(Qt::yellow); + QTextCursor csr(ui->textEdit->document()); + int position = csr.position(); + + setUpdatesEnabled(false); + + // Reset highlighting + csr.movePosition(QTextCursor::Start); + csr.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + csr.setCharFormat(plain_fmt); + + // Apply new highlighting + if (!pattern.isEmpty()) { + int match_pos = 0; + while ((match_pos = re.indexIn(ui->textEdit->toPlainText(), match_pos)) > -1) { + csr.setPosition(match_pos, QTextCursor::MoveAnchor); + csr.setPosition(match_pos + re.matchedLength(), QTextCursor::KeepAnchor); + csr.setCharFormat(highlight_fmt); + match_pos += re.matchedLength(); + } + } + + // Restore cursor and anchor + csr.setPosition(position, QTextCursor::MoveAnchor); + setUpdatesEnabled(true); +} + +struct _funnel_text_window_t* text_window_new(const char* title) +{ + return FunnelTextDialog::textWindowNew(title); +} + +void text_window_set_text(funnel_text_window_t *ftw, const char* text) +{ + if (ftw) { + ftw->funnel_text_dialog->setText(text); + } +} + +void text_window_append(funnel_text_window_t* ftw, const char* text) +{ + if (ftw) { + ftw->funnel_text_dialog->appendText(text); + } +} + +void text_window_prepend(funnel_text_window_t *ftw, const char* text) +{ + if (ftw) { + ftw->funnel_text_dialog->prependText(text); + } +} + +void text_window_clear(funnel_text_window_t* ftw) +{ + if (ftw) { + ftw->funnel_text_dialog->clearText(); + } +} + +const char *text_window_get_text(funnel_text_window_t *ftw) +{ + if (ftw) { + return ftw->funnel_text_dialog->getText(); + } + return NULL; +} + +void text_window_set_close_cb(funnel_text_window_t *ftw, text_win_close_cb_t close_cb, void *close_cb_data) +{ + if (ftw) { + ftw->funnel_text_dialog->setCloseCallback(close_cb, close_cb_data); + } +} + +void text_window_set_editable(funnel_text_window_t *ftw, gboolean editable) +{ + if (ftw) { + ftw->funnel_text_dialog->setTextEditable(editable); + } +} + +void text_window_destroy(funnel_text_window_t *ftw) +{ + if (ftw) { + ftw->funnel_text_dialog->close(); + } +} + +void text_window_add_button(funnel_text_window_t *ftw, funnel_bt_t *funnel_button, const char *label) +{ + if (ftw) { + ftw->funnel_text_dialog->addButton(funnel_button, label); + } +} + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/qt/funnel_text_dialog.h b/ui/qt/funnel_text_dialog.h new file mode 100644 index 0000000000..0ee9be5edf --- /dev/null +++ b/ui/qt/funnel_text_dialog.h @@ -0,0 +1,98 @@ +/* funnel_text_dialog.h + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FUNNEL_TEXT_DIALOG_H +#define FUNNEL_TEXT_DIALOG_H + +#include + +#include "epan/funnel.h" + +#include + +namespace Ui { +class FunnelTextDialog; +} + +class FunnelTextDialog; +struct _funnel_text_window_t { + FunnelTextDialog* funnel_text_dialog; +}; + +class FunnelTextDialog : public QDialog +{ + Q_OBJECT + +public: + explicit FunnelTextDialog(); + ~FunnelTextDialog(); + + // Funnel ops + static struct _funnel_text_window_t *textWindowNew(const QString title); + void setText(const QString text); + void appendText(const QString text); + void prependText(const QString text); + void clearText(); + const char *getText(); + void setCloseCallback(text_win_close_cb_t close_cb, void* close_cb_data); + void setTextEditable(gboolean editable); + void addButton(funnel_bt_t *button_cb, const QString label); + +private slots: + void buttonClicked(); + void on_findLineEdit_textChanged(const QString &pattern); + +private: + Ui::FunnelTextDialog *ui; + + struct _funnel_text_window_t funnel_text_window_; + text_win_close_cb_t close_cb_; + void *close_cb_data_; +}; + +extern "C" { +struct _funnel_text_window_t* text_window_new(const char* title); +void text_window_set_text(funnel_text_window_t* ftw, const char* text); +void text_window_append(funnel_text_window_t *ftw, const char* text); +void text_window_prepend(funnel_text_window_t* ftw, const char* text); +void text_window_clear(funnel_text_window_t *ftw); +const char *text_window_get_text(funnel_text_window_t* ftw); +void text_window_set_close_cb(funnel_text_window_t *ftw, text_win_close_cb_t close_cb, void* close_cb_data); +void text_window_set_editable(funnel_text_window_t* ftw, gboolean editable); +void text_window_destroy(funnel_text_window_t* ftw); +void text_window_add_button(funnel_text_window_t* ftw, funnel_bt_t* funnel_button, const char* label); +} + + +#endif // FUNNEL_TEXT_DIALOG_H + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/qt/funnel_text_dialog.ui b/ui/qt/funnel_text_dialog.ui new file mode 100644 index 0000000000..80bb02f371 --- /dev/null +++ b/ui/qt/funnel_text_dialog.ui @@ -0,0 +1,88 @@ + + + FunnelTextDialog + + + + 0 + 0 + 620 + 450 + + + + Dialog + + + + + + + + + + + <html><head/><body><p>Enter some text or a regular expression. It will be highlighted above.</p></body></html> + + + Highlight: + + + + + + + <html><head/><body><p>Enter some text or a regular expression. It will be highlighted above.</p></body></html> + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + buttonBox + accepted() + FunnelTextDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + FunnelTextDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp index 737aadc511..312769829d 100644 --- a/ui/qt/main_window.cpp +++ b/ui/qt/main_window.cpp @@ -47,6 +47,7 @@ #include "byte_view_tab.h" #include "display_filter_edit.h" #include "export_dissection_dialog.h" +#include "funnel_statistics.h" #include "import_text_dialog.h" #include "packet_list.h" #include "proto_tree.h" @@ -202,6 +203,7 @@ MainWindow::MainWindow(QWidget *parent) : show_hide_actions_(NULL), time_display_actions_(NULL), time_precision_actions_(NULL), + funnel_statistics_(new FunnelStatistics(this, capture_file_)), capture_stopping_(false), capture_filter_valid_(false), #ifdef _WIN32 @@ -239,6 +241,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(wsApp, SIGNAL(appInitialized()), this, SLOT(addStatsPluginsToMenu())); connect(wsApp, SIGNAL(appInitialized()), this, SLOT(addStatisticsMenus())); connect(wsApp, SIGNAL(appInitialized()), this, SLOT(addExternalMenus())); + connect(wsApp, SIGNAL(appInitialized()), this, SLOT(addFunnelMenus())); connect(wsApp, SIGNAL(profileChanging()), this, SLOT(saveWindowGeometry())); connect(wsApp, SIGNAL(preferencesChanged()), this, SLOT(layoutPanes())); @@ -262,6 +265,11 @@ MainWindow::MainWindow(QWidget *parent) : main_ui_->statusBar, SLOT(pushTemporaryStatus(const QString&))); connect(df_edit, SIGNAL(filterPackets(QString&,bool)), this, SLOT(filterPackets(QString&,bool))); connect(df_edit, SIGNAL(addBookmark(QString)), this, SLOT(addDisplayFilterButton(QString))); + connect(df_edit, SIGNAL(textChanged(QString)), funnel_statistics_, SLOT(displayFilterTextChanged(QString))); + connect(funnel_statistics_, SIGNAL(setDisplayFilter(QString)), df_edit, SLOT(setText(QString))); + connect(funnel_statistics_, SIGNAL(applyDisplayFilter()), df_combo_box_, SLOT(applyDisplayFilter())); + connect(funnel_statistics_, SIGNAL(openCaptureFile(QString&,QString&)), + this, SLOT(openCaptureFile(QString&,QString&))); connect(this, SIGNAL(displayFilterSuccess(bool)), df_edit, SLOT(displayFilterSuccess(bool))); initMainToolbarIcons(); @@ -1971,8 +1979,6 @@ void MainWindow::setForCaptureInProgress(gboolean capture_in_progress) void MainWindow::addStatisticsMenus() { - - // Unsorted // actionStatistics_REGISTER_STAT_GROUP_UNSORTED should exist and be. // invisible. QListunsorted_actions = wsApp->statisticsGroupItems(REGISTER_STAT_GROUP_UNSORTED); @@ -2066,6 +2072,43 @@ void MainWindow::addExternalMenus() } } +void MainWindow::addFunnelMenus() +{ + // XXX Add support for MENU_STAT_UNSORTED, MENU_STAT_GENERIC, etc. We + // should probably add a common routine that we can use in + // addStatisticsMenus as well. + QListfunnel_actions = wsApp->funnelGroupItems(REGISTER_TOOLS_GROUP_UNSORTED); + + // Empty menus don't show up: https://bugreports.qt.io/browse/QTBUG-33728 + // We've added a placeholder in order to make sure the "Tools" menu is + // visible. Hide it as needed. + if (funnel_actions.length() > 0) { + main_ui_->actionToolsPlaceholder->setVisible(false); + } + + foreach (QAction *tools_action, funnel_actions) { + QStringList menu_path = tools_action->text().split('/'); + QMenu *cur_menu = main_ui_->menuTools; + while (menu_path.length() > 1) { + QString menu_title = menu_path.takeFirst(); +#if (QT_VERSION > QT_VERSION_CHECK(5, 0, 0)) + QMenu *submenu = cur_menu->findChild(menu_title.toLower(), Qt::FindDirectChildrenOnly); +#else + QMenu *submenu = cur_menu->findChild(menu_title.toLower()); + if (submenu && submenu->parent() != cur_menu) submenu = NULL; +#endif + if (!submenu) { + submenu = cur_menu->addMenu(menu_title); + submenu->setObjectName(menu_title.toLower()); + } + cur_menu = submenu; + } + tools_action->setText(menu_path.last()); + cur_menu->addAction(tools_action); + connect(tools_action, SIGNAL(triggered(bool)), funnel_statistics_, SLOT(funnelActionTriggered())); + } +} + /* * Editor modelines * diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h index ea53ad115a..0bc10938bc 100644 --- a/ui/qt/main_window.h +++ b/ui/qt/main_window.h @@ -61,6 +61,7 @@ class AccordionFrame; class ByteViewTab; +class FunnelStatistics; class MainWelcome; class PacketList; class ProtoTree; @@ -136,6 +137,7 @@ private: QActionGroup *show_hide_actions_; QActionGroup *time_display_actions_; QActionGroup *time_precision_actions_; + FunnelStatistics *funnel_statistics_; bool capture_stopping_; bool capture_filter_valid_; @@ -207,7 +209,8 @@ public slots: * @return True on success, false on failure. */ // XXX We might want to return a cf_read_status_t or a CaptureFile. - bool openCaptureFile(QString& cf_path = *new QString(), QString& display_filter = *new QString(), unsigned int type = WTAP_TYPE_AUTO); + bool openCaptureFile(QString& cf_path, QString& display_filter, unsigned int type); + bool openCaptureFile(QString& cf_path = *new QString(), QString& display_filter = *new QString()) { return openCaptureFile(cf_path, display_filter, WTAP_TYPE_AUTO); } void filterPackets(QString& new_filter = *new QString(), bool force = false); void updateForUnsavedChanges(); void layoutPanes(); @@ -261,6 +264,7 @@ private slots: void addStatsPluginsToMenu(); void addStatisticsMenus(); void addExternalMenus(); + void addFunnelMenus(); void startInterfaceCapture(bool valid); diff --git a/ui/qt/main_window.ui b/ui/qt/main_window.ui index 50cef78629..72f163c7e9 100644 --- a/ui/qt/main_window.ui +++ b/ui/qt/main_window.ui @@ -539,6 +539,12 @@ + + + Tools + + + @@ -547,6 +553,7 @@ + @@ -2369,6 +2376,20 @@ QAction::NoRole + + + false + + + No tools registered + + + No tools have been registered. + + + QAction::NoRole + + diff --git a/ui/qt/wireshark_application.cpp b/ui/qt/wireshark_application.cpp index e34c1ae3dc..1439c72f0f 100644 --- a/ui/qt/wireshark_application.cpp +++ b/ui/qt/wireshark_application.cpp @@ -90,6 +90,7 @@ static char *last_open_dir = NULL; static bool updated_last_open_dir = FALSE; static QList recent_items_; static QHash > statistics_groups_; +static QHash > funnel_groups_; QString WiresharkApplication::window_title_separator_ = QString::fromUtf8(" " UTF8_MIDDLE_DOT " "); @@ -571,6 +572,7 @@ void WiresharkApplication::emitTapParameterSignal(const QString cfg_abbr, const emit openTapParameterDialog(cfg_abbr, arg, userdata); } +// XXX Combine statistics and funnel routines into addGroupItem + groupItems? void WiresharkApplication::addStatisticsGroupItem(int group, QAction *sg_action) { if (!statistics_groups_.contains(group)) { @@ -590,6 +592,25 @@ QList WiresharkApplication::statisticsGroupItems(int group) return sgi_list; } +void WiresharkApplication::addFunnelGroupItem(int group, QAction *fg_action) +{ + if (!funnel_groups_.contains(group)) { + funnel_groups_[group] = QList(); + } + funnel_groups_[group] << fg_action; +} + +QList WiresharkApplication::funnelGroupItems(int group) +{ + if (!funnel_groups_.contains(group)) { + return QList(); + } + + QList fgi_list = funnel_groups_[group]; + std::sort(fgi_list.begin(), fgi_list.end(), qActionLessThan); + return fgi_list; +} + #ifdef HAVE_LIBPCAP static void diff --git a/ui/qt/wireshark_application.h b/ui/qt/wireshark_application.h index 5cfd5ee032..1b7941e8e8 100644 --- a/ui/qt/wireshark_application.h +++ b/ui/qt/wireshark_application.h @@ -77,6 +77,8 @@ public: // Map a register_stat_group_t to a list of stat_tap_ui.title void addStatisticsGroupItem(int group, QAction *sg_action); QListstatisticsGroupItems(int group); + void addFunnelGroupItem(int group, QAction *fg_action); + QList funnelGroupItems(int group); void allSystemsGo(); void refreshLocalInterfaces(); -- cgit v1.2.3