aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerald Combs <gerald@wireshark.org>2015-06-05 13:17:13 -0700
committerMichael Mann <mmann78@netscape.net>2015-07-03 23:09:13 +0000
commitfdb85029fd9b22b221f7123905f1bad66c04ce91 (patch)
tree4e57f253ece70c5c19ad543608b3be48bbdf2329
parent7fdc534cf967320fce4d560969385d6f19798b8d (diff)
Add ServiceResponseTimeDialog.
Add ServiceResponseTimeDialog as a subclass of TapParameterDialog, similar to StatsTreeDialog. Add initial plumbing for statistics menu items and command line invocation. Don't append "..." to menu item names. Don't add menu icons. In each case this avoids repetitive UI clutter. Change-Id: I463b95c93090160bb81d2e80b16aad389dc0bd6c Reviewed-on: https://code.wireshark.org/review/8864 Reviewed-by: Gerald Combs <gerald@wireshark.org> Reviewed-by: Michael Mann <mmann78@netscape.net>
-rw-r--r--doc/tshark.pod6
-rw-r--r--doc/wireshark.pod.template12
-rw-r--r--epan/srt_table.h7
-rw-r--r--epan/stat_groups.h4
-rw-r--r--epan/stat_tap_ui.h3
-rw-r--r--epan/stats_tree.c3
-rw-r--r--epan/stats_tree.h8
-rw-r--r--epan/timestats.h14
-rw-r--r--ui/CMakeLists.txt1
-rw-r--r--ui/Makefile.common2
-rw-r--r--ui/gtk/service_response_time_table.c32
-rw-r--r--ui/gtk/service_response_time_table.h4
-rw-r--r--ui/qt/CMakeLists.txt3
-rw-r--r--ui/qt/Makefile.common2
-rw-r--r--ui/qt/Wireshark.pro3
-rw-r--r--ui/qt/expert_info_dialog.cpp3
-rw-r--r--ui/qt/expert_info_dialog.h6
-rw-r--r--ui/qt/filter_action.cpp15
-rw-r--r--ui/qt/filter_action.h2
-rw-r--r--ui/qt/main_window.cpp27
-rw-r--r--ui/qt/main_window.h21
-rw-r--r--ui/qt/main_window.ui26
-rw-r--r--ui/qt/main_window_slots.cpp34
-rw-r--r--ui/qt/qt_ui_utils.cpp5
-rw-r--r--ui/qt/qt_ui_utils.h10
-rw-r--r--ui/qt/service_response_time_dialog.cpp411
-rw-r--r--ui/qt/service_response_time_dialog.h88
-rw-r--r--ui/qt/stats_tree_dialog.cpp24
-rw-r--r--ui/qt/stats_tree_dialog.h2
-rw-r--r--ui/qt/tap_parameter_dialog.cpp320
-rw-r--r--ui/qt/tap_parameter_dialog.h30
-rw-r--r--ui/qt/traffic_table_dialog.cpp1
-rw-r--r--ui/qt/wireshark_application.cpp26
-rw-r--r--ui/qt/wireshark_application.h7
-rw-r--r--ui/qt/wireshark_dialog.h2
-rw-r--r--ui/service_response_time.c47
-rw-r--r--ui/service_response_time.h58
-rw-r--r--wireshark-qt.cpp43
38 files changed, 1214 insertions, 98 deletions
diff --git a/doc/tshark.pod b/doc/tshark.pod
index f50211987e..8278425246 100644
--- a/doc/tshark.pod
+++ b/doc/tshark.pod
@@ -860,6 +860,8 @@ Display all possible values for B<-z>.
=item B<-z> afp,srt[,I<filter>]
+Show Apple Filing Protocol service response time statistics.
+
=item B<-z> camel,srt
=item B<-z> compare,I<start>,I<stop>,I<ttl[0|1]>,I<order[0|1]>,I<variance>[,I<filter>]
@@ -915,6 +917,10 @@ on those calls that match that filter.
Example: S<B<-z dcerpc,srt,12345778-1234-abcd-ef00-0123456789ac,1.0,ip.addr==1.2.3.4>> will collect SAMR
SRT statistics for a specific host.
+=item B<-z> bootp,stat[,I<filter>]
+
+Show DHCP (BOOTP) statistics.
+
=item B<-z> diameter,avp[,I<cmd.code>,I<field>,I<field>,I<...>]
This option enables extraction of most important diameter fields from large capture files.
diff --git a/doc/wireshark.pod.template b/doc/wireshark.pod.template
index b3ba46386c..ee398dd477 100644
--- a/doc/wireshark.pod.template
+++ b/doc/wireshark.pod.template
@@ -643,6 +643,14 @@ Currently implemented statistics are:
=over 4
+=item B<-z help>
+
+Display all possible values for B<-z>.
+
+=item B<-z> afp,srt[,I<filter>]
+
+Show Apple Filing Protocol service response time statistics.
+
=item B<-z> conv,I<type>[,I<filter>]
Create a table that lists all conversations that could be seen in the
@@ -687,6 +695,10 @@ on those calls that match that filter.
Example: S<B<-z dcerpc,srt,12345778-1234-abcd-ef00-0123456789ac,1.0,ip.addr==1.2.3.4>> will collect SAMR
SRT statistics for a specific host.
+=item B<-z> bootp,stat[,I<filter>]
+
+Show DHCP (BOOTP) statistics.
+
=item B<-z> fc,srt[,I<filter>]
Collect call/reply SRT (Service Response Time) data for FC. Data collected
diff --git a/epan/srt_table.h b/epan/srt_table.h
index 3b8905218b..2910e86ce3 100644
--- a/epan/srt_table.h
+++ b/epan/srt_table.h
@@ -49,12 +49,11 @@ typedef struct _srt_stat_table {
void* table_specific_data; /** any dissector/table specific data needed for packet filtering */
} srt_stat_table;
-
struct register_srt;
struct _srt_data_t;
-typedef void (*srt_gui_init_cb)(srt_stat_table* rst, void* gui_data);
-typedef void (*srt_gui_reset_cb)(srt_stat_table* rst, void* gui_data);
-typedef void (*srt_gui_free_cb)(srt_stat_table* rst, void* gui_data);
+typedef void (*srt_gui_init_cb)(srt_stat_table* rst, void* gui_data); /* GTK+ only? */
+typedef void (*srt_gui_reset_cb)(srt_stat_table* rst, void* gui_data); /* GTK+ only? */
+typedef void (*srt_gui_free_cb)(srt_stat_table* rst, void* gui_data); /* GTK+ only? */
typedef void (*srt_proc_table_cb)(srt_stat_table* rst, int indx, struct _srt_data_t* gui_data);
typedef void (*srt_init_cb)(struct register_srt* srt, GArray* srt_array, srt_gui_init_cb gui_callback, void* gui_data);
typedef guint (*srt_param_handler_cb)(struct register_srt* srt, const char* opt_arg, char** err);
diff --git a/epan/stat_groups.h b/epan/stat_groups.h
index 0afdc57f2a..6f603325fc 100644
--- a/epan/stat_groups.h
+++ b/epan/stat_groups.h
@@ -32,8 +32,8 @@ extern "C" {
*/
/*
- * XXX - defines stuff usable regardless of the GUI toolkit. Right now,
- * that's only the menu group, which is used by tap_param_dlg.h.
+ * Menu statistics group definitions. Used by ui/qt/tap_parameter_dialog.h
+ * and ui/gtk/tap_param_dlg.h.
*
* XXX - stats should be able to register additional menu groups, although
* the question then would be "in what order should they appear in the menu?"
diff --git a/epan/stat_tap_ui.h b/epan/stat_tap_ui.h
index 1bdae9d50c..3877a5aa9e 100644
--- a/epan/stat_tap_ui.h
+++ b/epan/stat_tap_ui.h
@@ -57,11 +57,12 @@ typedef struct _tap_param {
/*
* UI information for a tap.
*/
+typedef void (* stat_tap_init_cb)(const char *, void*);
typedef struct _stat_tap_ui {
register_stat_group_t group; /* group to which statistic belongs */
const char *title; /* title of statistic */
const char *cli_string; /* initial part of the "-z" argument for statistic */
- void (* tap_init_cb)(const char *, void*); /* callback to init function of the tap */
+ stat_tap_init_cb tap_init_cb; /* callback to init function of the tap */
size_t nparams; /* number of parameters */
tap_param *params; /* pointer to table of parameter info */
} stat_tap_ui;
diff --git a/epan/stats_tree.c b/epan/stats_tree.c
index e3600a38b5..aaad74e344 100644
--- a/epan/stats_tree.c
+++ b/epan/stats_tree.c
@@ -364,6 +364,7 @@ stats_tree_packet(void *p, packet_info *pinfo, epan_dissect_t *edt, const void *
extern stats_tree_cfg*
stats_tree_get_cfg_by_abbr(const char *abbr)
{
+ if (!abbr) return NULL;
return (stats_tree_cfg *)g_hash_table_lookup(registry,abbr);
}
@@ -1106,7 +1107,7 @@ stats_tree_format_as_str(const stats_tree* st, st_format_type format_type,
s = g_string_new("---\n");
break;
case ST_FORMAT_XML:
- s = g_string_new("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
+ s = g_string_new("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
break;
case ST_FORMAT_CSV:
s = g_string_new("\"level\",\"parent\",");
diff --git a/epan/stats_tree.h b/epan/stats_tree.h
index d732c390db..ed88fbaa03 100644
--- a/epan/stats_tree.h
+++ b/epan/stats_tree.h
@@ -31,6 +31,10 @@
#include "../register.h"
#include "ws_symbol_export.h"
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
#define STAT_TREE_ROOT "root"
#define ST_FLG_AVERAGE 0x10000000 /* Calculate averages for nodes, rather than totals */
@@ -233,6 +237,10 @@ WS_DLL_PUBLIC int stats_tree_manip_node(manip_node_mode mode,
#define stat_node_clear_flags(st,name,parent_id,with_children,flags) \
(stats_tree_manip_node(MN_CLEAR_FLAGS,(st),(name),(parent_id),(with_children),flags))
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
#endif /* __STATS_TREE_H */
/*
diff --git a/epan/timestats.h b/epan/timestats.h
index 884fb5b94f..37e45ebe56 100644
--- a/epan/timestats.h
+++ b/epan/timestats.h
@@ -21,13 +21,17 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef _time_stat
-#define _time_stat
+#ifndef __TIMESTATS_H__
+#define __TIMESTATS_H__
#include <glib.h>
#include "epan/packet_info.h"
#include "wsutil/nstime.h"
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
/* Summary of time statistics*/
typedef struct _timestat_t {
guint32 num; /* number of samples */
@@ -49,4 +53,8 @@ WS_DLL_PUBLIC void time_stat_update(timestat_t *stats, const nstime_t *delta, pa
WS_DLL_PUBLIC gdouble get_average(const nstime_t *sum, guint32 num);
-#endif
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIMESTATS_H__ */
diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt
index 123d8ca241..f611c7da16 100644
--- a/ui/CMakeLists.txt
+++ b/ui/CMakeLists.txt
@@ -45,6 +45,7 @@ set(COMMON_UI_SRC
proto_hier_stats.c
recent.c
rtp_stream.c
+ service_response_time.c
software_update.c
ssl_key_export.c
tap_export_pdu.c
diff --git a/ui/Makefile.common b/ui/Makefile.common
index 25cbdc63eb..3f215d112d 100644
--- a/ui/Makefile.common
+++ b/ui/Makefile.common
@@ -66,6 +66,7 @@ WIRESHARK_UI_SRC = \
proto_hier_stats.c \
recent.c \
rtp_stream.c \
+ service_response_time.c \
software_update.c \
ssl_key_export.c \
tap_export_pdu.c \
@@ -107,6 +108,7 @@ noinst_HEADERS = \
recent_utils.h \
rtp_analysis.h \
rtp_stream.h \
+ service_response_time.h \
simple_dialog.h \
software_update.h \
ssl_key_export.h \
diff --git a/ui/gtk/service_response_time_table.c b/ui/gtk/service_response_time_table.c
index c9de7b30ff..3284c06b2c 100644
--- a/ui/gtk/service_response_time_table.c
+++ b/ui/gtk/service_response_time_table.c
@@ -86,7 +86,7 @@ srt_select_filter_cb(GtkWidget *widget _U_, gpointer callback_data, guint callba
if (!gtk_tree_selection_get_selected(sel, &model, &iter))
return;
- gtk_tree_model_get (model, &iter, INDEX_COLUMN, &selection, -1);
+ gtk_tree_model_get (model, &iter, SRT_COLUMN_INDEX, &selection, -1);
if(selection>=(int)rst->num_procs){
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "No procedure selected");
return;
@@ -471,8 +471,6 @@ init_gtk_srt_table(srt_stat_table* rst, void* gui_data)
GtkTreeSelection *sel;
gtk_srt_table_t *gtk_table_data = g_new0(gtk_srt_table_t, 1);
- static const char *default_titles[] = { "Index", "Procedure", "Calls", "Min SRT (s)", "Max SRT (s)", "Avg SRT (s)", "Sum SRT (s)" };
-
/* Create GTK data for the table here */
gtk_table_data->rst = rst;
g_array_insert_val(ss->gtk_srt_array, ss->gtk_srt_array->len, gtk_table_data);
@@ -493,7 +491,7 @@ init_gtk_srt_table(srt_stat_table* rst, void* gui_data)
}
/* Create the store */
- store = gtk_list_store_new (N_COLUMNS, /* Total number of columns */
+ store = gtk_list_store_new (NUM_SRT_COLUMNS, /* Total number of columns */
G_TYPE_INT, /* Index */
G_TYPE_STRING, /* Procedure */
G_TYPE_UINT, /* Calls */
@@ -510,38 +508,38 @@ init_gtk_srt_table(srt_stat_table* rst, void* gui_data)
/* The view now holds a reference. We can get rid of our own reference */
g_object_unref (G_OBJECT (store));
- for (i = 0; i < N_COLUMNS; i++) {
+ for (i = 0; i < NUM_SRT_COLUMNS; i++) {
renderer = gtk_cell_renderer_text_new ();
- if (i != PROCEDURE_COLUMN) {
+ if (i != SRT_COLUMN_PROCEDURE) {
/* right align numbers */
g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
}
g_object_set(renderer, "ypad", 0, NULL);
switch (i) {
- case MIN_SRT_COLUMN:
- case MAX_SRT_COLUMN:
- column = gtk_tree_view_column_new_with_attributes (default_titles[i], renderer, NULL);
+ case SRT_COLUMN_MIN:
+ case SRT_COLUMN_MAX:
+ column = gtk_tree_view_column_new_with_attributes (service_response_time_get_column_name(i), renderer, NULL);
gtk_tree_view_column_set_cell_data_func(column, renderer, srt_time_func, GINT_TO_POINTER(i), NULL);
gtk_tree_sortable_set_sort_func(sortable, i, srt_time_sort_func, GINT_TO_POINTER(i), NULL);
break;
- case AVG_SRT_COLUMN:
- case SUM_SRT_COLUMN:
- column = gtk_tree_view_column_new_with_attributes (default_titles[i], renderer, NULL);
+ case SRT_COLUMN_AVG:
+ case SRT_COLUMN_SUM:
+ column = gtk_tree_view_column_new_with_attributes (service_response_time_get_column_name(i), renderer, NULL);
gtk_tree_view_column_set_cell_data_func(column, renderer, srt_avg_func, GINT_TO_POINTER(i), NULL);
break;
case PROCEDURE_COLUMN:
- column = gtk_tree_view_column_new_with_attributes (((rst->proc_column_name != NULL) ? rst->proc_column_name : default_titles[i]), renderer, "text",
+ column = gtk_tree_view_column_new_with_attributes ((rst->proc_column_name != NULL) ? rst->proc_column_name : service_response_time_get_column_name(i), renderer, "text",
i, NULL);
break;
default:
- column = gtk_tree_view_column_new_with_attributes (default_titles[i], renderer, "text", i, NULL);
+ column = gtk_tree_view_column_new_with_attributes (service_response_time_get_column_name(i), renderer, "text", i, NULL);
break;
}
gtk_tree_view_column_set_sort_column_id(column, i);
gtk_tree_view_column_set_resizable(column, TRUE);
gtk_tree_view_append_column (gtk_table_data->table, column);
- if (i == CALLS_COLUMN) {
+ if (i == SRT_COLUMN_CALLS) {
/* XXX revert order sort */
gtk_tree_view_column_clicked(column);
gtk_tree_view_column_clicked(column);
@@ -713,7 +711,7 @@ init_srt_tables(register_srt_t* srt, const char *filter)
gtk_window_set_destroy_with_parent (GTK_WINDOW(ss->gtk_data.win), TRUE);
gtk_window_set_default_size(GTK_WINDOW(ss->gtk_data.win), SRT_PREFERRED_WIDTH, 600);
- str = g_strdup_printf("%s Service Response Time statistics", proto_get_protocol_short_name(find_protocol_by_id(get_srt_proto_id(srt))));
+ str = g_strdup_printf("%s Service Response Time Statistics", proto_get_protocol_short_name(find_protocol_by_id(get_srt_proto_id(srt))));
set_window_title(ss->gtk_data.win, str);
ss->gtk_data.vbox=ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
@@ -737,7 +735,7 @@ init_srt_tables(register_srt_t* srt, const char *filter)
label=gtk_label_new(filter_string);
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
- gtk_widget_set_tooltip_text (label, filter ? filter : "");
+ gtk_widget_set_tooltip_text (label, filter ? filter : "");
g_free(filter_string);
gtk_box_pack_start(GTK_BOX(ss->gtk_data.vbox), label, FALSE, FALSE, 0);
diff --git a/ui/gtk/service_response_time_table.h b/ui/gtk/service_response_time_table.h
index 3b8e5915a9..c30ee72fec 100644
--- a/ui/gtk/service_response_time_table.h
+++ b/ui/gtk/service_response_time_table.h
@@ -27,7 +27,7 @@
#include <gtk/gtk.h>
#include "wsutil/nstime.h"
-#include "epan/srt_table.h"
+#include "ui/service_response_time.h"
/** Suggested width of SRT window */
#define SRT_PREFERRED_WIDTH 650
@@ -39,7 +39,7 @@
#define MAX_FILTER_STRING_LENGTH 1000
/** @file
- * Helper routines common to all service response time statistics tap.
+ * Helper routines common to all service response time statistics taps.
*/
/** Statistics table */
diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt
index b317bfb3a9..dbd57ad3c0 100644
--- a/ui/qt/CMakeLists.txt
+++ b/ui/qt/CMakeLists.txt
@@ -23,6 +23,7 @@
# need to go here.
set(WIRESHARK_QT_HEADERS
about_dialog.h
+ accordion_frame.h
bluetooth_att_server_attributes_dialog.h
bluetooth_devices_dialog.h
accordion_frame.h
@@ -106,6 +107,7 @@ set(WIRESHARK_QT_HEADERS
simple_dialog.h
splash_overlay.h
stats_tree_dialog.h
+ service_response_time_dialog.h
syntax_line_edit.h
tap_parameter_dialog.h
tcp_stream_dialog.h
@@ -223,6 +225,7 @@ set(WIRESHARK_QT_SRC
search_frame.cpp
sequence_diagram.cpp
sequence_dialog.cpp
+ service_response_time_dialog.cpp
simple_dialog.cpp
splash_overlay.cpp
sparkline_delegate.cpp
diff --git a/ui/qt/Makefile.common b/ui/qt/Makefile.common
index ee46e60bfa..9536d983ca 100644
--- a/ui/qt/Makefile.common
+++ b/ui/qt/Makefile.common
@@ -211,6 +211,7 @@ MOC_HDRS = \
sctp_graph_byte_dialog.h \
sequence_diagram.h \
sequence_dialog.h \
+ service_response_time_dialog.h \
simple_dialog.h \
sparkline_delegate.h \
splash_overlay.h \
@@ -432,6 +433,7 @@ WIRESHARK_QT_SRC = \
search_frame.cpp \
sequence_diagram.cpp \
sequence_dialog.cpp \
+ service_response_time_dialog.cpp \
simple_dialog.cpp \
sparkline_delegate.cpp \
splash_overlay.cpp \
diff --git a/ui/qt/Wireshark.pro b/ui/qt/Wireshark.pro
index 92e3ae19eb..f9d6a2b689 100644
--- a/ui/qt/Wireshark.pro
+++ b/ui/qt/Wireshark.pro
@@ -326,6 +326,7 @@ HEADERS += $$HEADERS_WS_C \
sctp_graph_arwnd_dialog.h \
sctp_graph_byte_dialog.h \
search_frame.h \
+ service_response_time_dialog.h \
splash_overlay.h \
stats_tree_dialog.h \
tango_colors.h \
@@ -612,6 +613,7 @@ HEADERS += \
simple_dialog.h \
sparkline_delegate.h \
syntax_line_edit.h \
+ tap_parameter_dialog.h \
time_shift_dialog.h \
wireshark_application.h \
wireshark_dialog.h \
@@ -706,6 +708,7 @@ SOURCES += \
search_frame.cpp \
sequence_diagram.cpp \
sequence_dialog.cpp \
+ service_response_time_dialog.cpp \
simple_dialog.cpp \
sparkline_delegate.cpp \
splash_overlay.cpp \
diff --git a/ui/qt/expert_info_dialog.cpp b/ui/qt/expert_info_dialog.cpp
index f3359ba133..2d7ecfc96a 100644
--- a/ui/qt/expert_info_dialog.cpp
+++ b/ui/qt/expert_info_dialog.cpp
@@ -24,6 +24,7 @@
#include "file.h"
+#include <epan/epan_dissect.h>
#include <epan/expert.h>
#include <epan/stat_tap_ui.h>
#include <epan/tap.h>
@@ -338,7 +339,7 @@ void ExpertInfoDialog::tapReset(void *eid_ptr)
eid->clearAllData();
}
-gboolean ExpertInfoDialog::tapPacket(void *eid_ptr, packet_info *pinfo, epan_dissect_t *, const void *data)
+gboolean ExpertInfoDialog::tapPacket(void *eid_ptr, struct _packet_info *pinfo, struct epan_dissect *, const void *data)
{
ExpertInfoDialog *eid = static_cast<ExpertInfoDialog *>(eid_ptr);
expert_info_t *expert_info = (expert_info_t *) data;
diff --git a/ui/qt/expert_info_dialog.h b/ui/qt/expert_info_dialog.h
index 13dcd2c084..802b52dcde 100644
--- a/ui/qt/expert_info_dialog.h
+++ b/ui/qt/expert_info_dialog.h
@@ -26,15 +26,15 @@
#include <glib.h>
-#include "epan/epan_dissect.h"
-
#include "filter_action.h"
#include "wireshark_dialog.h"
#include <QMenu>
#include <QTreeWidgetItem>
+struct epan_dissect;
struct expert_info_s;
+struct _packet_info;
namespace Ui {
class ExpertInfoDialog;
@@ -83,7 +83,7 @@ private:
// Callbacks for register_tap_listener
static void tapReset(void *eid_ptr);
- static gboolean tapPacket(void *eid_ptr, packet_info *pinfo, epan_dissect_t *, const void *data);
+ static gboolean tapPacket(void *eid_ptr, struct _packet_info *pinfo, struct epan_dissect *, const void *data);
static void tapDraw(void *eid_ptr);
private slots:
diff --git a/ui/qt/filter_action.cpp b/ui/qt/filter_action.cpp
index e720b0e1b9..2c00a5ab7f 100644
--- a/ui/qt/filter_action.cpp
+++ b/ui/qt/filter_action.cpp
@@ -91,7 +91,7 @@ const QString FilterAction::actionName(Action action) {
}
-const QList<FilterAction::ActionType> FilterAction::actionTypes()
+const QList<FilterAction::ActionType> FilterAction::actionTypes(Action filter_action)
{
static const QList<ActionType> action_types_ = QList<ActionType>()
<< ActionTypePlain
@@ -100,6 +100,19 @@ const QList<FilterAction::ActionType> FilterAction::actionTypes()
<< ActionTypeOr
<< ActionTypeAndNot
<< ActionTypeOrNot;
+
+ static const QList<ActionType> simple_action_types_ = QList<ActionType>()
+ << ActionTypePlain
+ << ActionTypeNot;
+
+ switch (filter_action) {
+ case ActionFind:
+ case ActionColorize:
+ return simple_action_types_;
+ default:
+ break;
+ }
+
return action_types_;
}
diff --git a/ui/qt/filter_action.h b/ui/qt/filter_action.h
index c9c2086273..5fdd09e4e9 100644
--- a/ui/qt/filter_action.h
+++ b/ui/qt/filter_action.h
@@ -75,7 +75,7 @@ public:
static const QString actionName(Action action);
ActionType actionType() { return type_; }
- static const QList<ActionType> actionTypes();
+ static const QList<ActionType> actionTypes(Action filter_action = ActionApply);
static const QString actionTypeName(ActionType type);
ActionDirection actionDirection() { return direction_; }
diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp
index 7af4370ac1..737aadc511 100644
--- a/ui/qt/main_window.cpp
+++ b/ui/qt/main_window.cpp
@@ -213,6 +213,8 @@ MainWindow::MainWindow(QWidget *parent) :
if (!gbl_cur_main_window_) {
connect(wsApp, SIGNAL(openStatCommandDialog(QString,const char*,void*)),
this, SLOT(openStatCommandDialog(QString,const char*,void*)));
+ connect(wsApp, SIGNAL(openTapParameterDialog(QString,const QString,void*)),
+ this, SLOT(openTapParameterDialog(QString,const QString,void*)));
}
gbl_cur_main_window_ = this;
#ifdef HAVE_LIBPCAP
@@ -235,6 +237,7 @@ MainWindow::MainWindow(QWidget *parent) :
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(setFeaturesEnabled()));
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(zoomText()));
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(addStatsPluginsToMenu()));
+ connect(wsApp, SIGNAL(appInitialized()), this, SLOT(addStatisticsMenus()));
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(addExternalMenus()));
connect(wsApp, SIGNAL(profileChanging()), this, SLOT(saveWindowGeometry()));
@@ -1966,6 +1969,30 @@ void MainWindow::setForCaptureInProgress(gboolean capture_in_progress)
#endif
}
+void MainWindow::addStatisticsMenus()
+{
+
+ // Unsorted
+ // actionStatistics_REGISTER_STAT_GROUP_UNSORTED should exist and be.
+ // invisible.
+ QList<QAction *>unsorted_actions = wsApp->statisticsGroupItems(REGISTER_STAT_GROUP_UNSORTED);
+
+ foreach (QAction *unsorted_action, unsorted_actions) {
+ main_ui_->menuStatistics->insertAction(
+ main_ui_->actionStatistics_REGISTER_STAT_GROUP_UNSORTED,
+ unsorted_action);
+ connect(unsorted_action, SIGNAL(triggered(bool)), this, SLOT(openTapParameterDialog()));
+ }
+
+ // Response time
+ QList<QAction *>sg_actions = wsApp->statisticsGroupItems(REGISTER_STAT_GROUP_RESPONSE_TIME);
+
+ foreach (QAction *sg_action, sg_actions) {
+ main_ui_->menuServiceResponseTime->addAction(sg_action);
+ connect(sg_action, SIGNAL(triggered(bool)), this, SLOT(openTapParameterDialog()));
+ }
+}
+
void MainWindow::externalMenuHelper(ext_menu_t * menu, QMenu * subMenu, gint depth)
{
QAction * itemAction = NULL;
diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h
index dbb85847aa..ea53ad115a 100644
--- a/ui/qt/main_window.h
+++ b/ui/qt/main_window.h
@@ -199,7 +199,15 @@ signals:
public slots:
// in main_window_slots.cpp
- void openCaptureFile(QString& cf_path = *new QString(), QString& display_filter = *new QString(), unsigned int type = WTAP_TYPE_AUTO);
+ /**
+ * Open a capture file.
+ * @param cf_path Path to the file.
+ * @param display_filter Display filter to apply. May be empty.
+ * @param type File type.
+ * @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);
void filterPackets(QString& new_filter = *new QString(), bool force = false);
void updateForUnsavedChanges();
void layoutPanes();
@@ -251,6 +259,7 @@ private slots:
void showColumnEditor(int column);
void showPreferenceEditor(); // module_t *, pref *
void addStatsPluginsToMenu();
+ void addStatisticsMenus();
void addExternalMenus();
void startInterfaceCapture(bool valid);
@@ -271,6 +280,14 @@ private slots:
*/
void openStatCommandDialog(const QString &menu_path, const char *arg, void *userdata);
+ /** Pass tap parameter arguments to a slot.
+ * @param menu_path slot Partial slot name, e.g. "StatisticsAFPSrt".
+ * @param arg "-z" argument, e.g. "afp,srt".
+ * @param userdata Optional user data.
+ */
+ void openTapParameterDialog(const QString cfg_str, const QString arg, void *userdata);
+ void openTapParameterDialog();
+
// Automatically connected slots ("on_<object>_<signal>").
//
// The slots below follow the naming conventaion described in
@@ -472,7 +489,7 @@ private slots:
void on_actionStatisticsHTTPPacketCounter_triggered();
void on_actionStatisticsHTTPRequests_triggered();
void on_actionStatisticsHTTPLoadDistribution_triggered();
- void on_actionStatisticsPacketLen_triggered();
+ void on_actionStatisticsPacketLengths_triggered();
void statCommandIOGraph(const char *, void *);
void on_actionStatisticsIOGraph_triggered();
void on_actionStatisticsSametime_triggered();
diff --git a/ui/qt/main_window.ui b/ui/qt/main_window.ui
index 60b53fe48d..50cef78629 100644
--- a/ui/qt/main_window.ui
+++ b/ui/qt/main_window.ui
@@ -438,14 +438,20 @@
<addaction name="actionStatistics29WestLBTRM"/>
<addaction name="actionStatistics29WestLBTRU"/>
</widget>
+ <widget class="QMenu" name="menuServiceResponseTime">
+ <property name="title">
+ <string>Service Response Time</string>
+ </property>
+ </widget>
<addaction name="actionStatisticsCaptureFileProperties"/>
<addaction name="actionStatisticsProtocolHierarchy"/>
<addaction name="actionStatisticsConversations"/>
<addaction name="actionStatisticsEndpoints"/>
- <addaction name="actionStatisticsPacketLen"/>
+ <addaction name="actionStatisticsPacketLengths"/>
<addaction name="actionStatisticsIOGraph"/>
+ <addaction name="menuServiceResponseTime"/>
<addaction name="separator"/>
- <addaction name="separator"/>
+ <addaction name="actionStatistics_REGISTER_STAT_GROUP_UNSORTED"/>
<addaction name="menu29West"/>
<addaction name="actionStatisticsANCP"/>
<addaction name="menuBACnet"/>
@@ -1675,7 +1681,7 @@
<string>HTTP load distribution</string>
</property>
</action>
- <action name="actionStatisticsPacketLen">
+ <action name="actionStatisticsPacketLengths">
<property name="text">
<string>Packet Lengths</string>
</property>
@@ -2349,6 +2355,20 @@
<string>Add an expression to the display filter.</string>
</property>
</action>
+ <action name="actionStatistics_REGISTER_STAT_GROUP_UNSORTED">
+ <property name="text">
+ <string>REGISTER_STAT_GROUP_UNSORTED</string>
+ </property>
+ <property name="toolTip">
+ <string>Start of &quot;REGISTER_STAT_GROUP_UNSORTED&quot;</string>
+ </property>
+ <property name="visible">
+ <bool>false</bool>
+ </property>
+ <property name="menuRole">
+ <enum>QAction::NoRole</enum>
+ </property>
+ </action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp
index d2f960af6e..59f290ed48 100644
--- a/ui/qt/main_window_slots.cpp
+++ b/ui/qt/main_window_slots.cpp
@@ -110,6 +110,7 @@
#include "sctp_graph_dialog.h"
#include "sequence_dialog.h"
#include "stats_tree_dialog.h"
+#include "tap_parameter_dialog.h"
#include "tcp_stream_dialog.h"
#include "time_shift_dialog.h"
#include "voip_calls_dialog.h"
@@ -131,7 +132,7 @@
const char *dfe_property_ = "display filter expression"; //TODO : Fix Translate
-void MainWindow::openCaptureFile(QString& cf_path, QString& read_filter, unsigned int type)
+bool MainWindow::openCaptureFile(QString& cf_path, QString& read_filter, unsigned int type)
{
QString file_name = "";
dfilter_t *rfcode = NULL;
@@ -170,12 +171,12 @@ void MainWindow::openCaptureFile(QString& cf_path, QString& read_filter, unsigne
if (open_dlg.open(file_name, type)) {
cf_path = file_name;
} else {
- return;
+ return false;
}
}
if (!testCaptureFileClose(false)) {
- return;
+ return false;
}
if (dfilter_compile(read_filter.toUtf8().constData(), &rfcode, &err_msg)) {
@@ -228,7 +229,7 @@ void MainWindow::openCaptureFile(QString& cf_path, QString& read_filter, unsigne
string and return (without changing the last containing
directory). */
capture_file_.setCapFile(NULL);
- return;
+ return false;
}
break;
}
@@ -236,6 +237,8 @@ void MainWindow::openCaptureFile(QString& cf_path, QString& read_filter, unsigne
wsApp->setLastOpenDir(get_dirname(cf_path.toUtf8().data()));
main_ui_->statusBar->showExpert();
+
+ return true;
}
void MainWindow::filterPackets(QString& new_filter, bool force)
@@ -1528,6 +1531,27 @@ void MainWindow::openStatCommandDialog(const QString &menu_path, const char *arg
QMetaObject::invokeMethod(this, slot.toLatin1().constData(), Q_ARG(const char *, arg), Q_ARG(void *, userdata));
}
+void MainWindow::openTapParameterDialog(const QString cfg_str, const QString arg, void *userdata)
+{
+ TapParameterDialog *tp_dialog = TapParameterDialog::showTapParameterStatistics(*this, capture_file_, cfg_str, arg, userdata);
+ if (!tp_dialog) return;
+
+ connect(tp_dialog, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
+ this, SLOT(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
+ connect(tp_dialog, SIGNAL(updateFilter(QString&, bool)),
+ this, SLOT(filterPackets(QString&, bool)));
+ tp_dialog->show();
+}
+
+void MainWindow::openTapParameterDialog()
+{
+ QAction *tpa = qobject_cast<QAction *>(QObject::sender());
+ if (!tpa) return;
+
+ const QString cfg_str = tpa->data().toString();
+ openTapParameterDialog(cfg_str, NULL, NULL);
+}
+
// File Menu
void MainWindow::on_actionFileOpen_triggered()
@@ -2710,7 +2734,7 @@ void MainWindow::on_actionStatisticsHTTPLoadDistribution_triggered()
openStatisticsTreeDialog("http_srv");
}
-void MainWindow::on_actionStatisticsPacketLen_triggered()
+void MainWindow::on_actionStatisticsPacketLengths_triggered()
{
openStatisticsTreeDialog("plen");
}
diff --git a/ui/qt/qt_ui_utils.cpp b/ui/qt/qt_ui_utils.cpp
index de59926253..c1841c9f80 100644
--- a/ui/qt/qt_ui_utils.cpp
+++ b/ui/qt/qt_ui_utils.cpp
@@ -35,6 +35,7 @@
#include <wsutil/str_util.h>
+#include <QAction>
#include <QFontDatabase>
/* Make the format_size_flags_e enum usable in C++ */
@@ -150,6 +151,10 @@ void smooth_font_size(QFont &font) {
}
}
+bool qActionLessThan(const QAction * a1, const QAction * a2) {
+ return a1->text().compare(a2->text()) < 0;
+}
+
/*
* Editor modelines
*
diff --git a/ui/qt/qt_ui_utils.h b/ui/qt/qt_ui_utils.h
index 175f5daaef..102f599fbf 100644
--- a/ui/qt/qt_ui_utils.h
+++ b/ui/qt/qt_ui_utils.h
@@ -148,6 +148,16 @@ const QString file_size_to_qstring(const gint64 size);
*/
void smooth_font_size(QFont &font);
+/**
+ * Compare the text of two QActions. Useful for passing to std::sort.
+ *
+ * @param a1 First action
+ * @param a2 Second action
+ * @return
+ */
+class QAction;
+bool qActionLessThan(const QAction * a1, const QAction * a2);
+
#endif /* __QT_UI_UTILS__H__ */
// XXX Add a routine to fetch the HWND corresponding to a widget using QPlatformIntegration
diff --git a/ui/qt/service_response_time_dialog.cpp b/ui/qt/service_response_time_dialog.cpp
new file mode 100644
index 0000000000..33f0323f70
--- /dev/null
+++ b/ui/qt/service_response_time_dialog.cpp
@@ -0,0 +1,411 @@
+/* service_response_time_dialog.cpp
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "service_response_time_dialog.h"
+
+#include "file.h"
+
+#include <epan/timestats.h>
+#include <epan/tap.h>
+
+#include <ui/service_response_time.h>
+
+#include "wireshark_application.h"
+
+#include <QMessageBox>
+#include <QTreeWidget>
+#include <QTreeWidgetItemIterator>
+
+// To do:
+
+static QHash<const QString, register_srt_t *> cfg_str_to_srt_;
+
+extern "C" {
+// XXX Need to handle filters.
+static void
+srt_init(const char *args, void*) {
+ QStringList args_l = QString(args).split(',');
+ if (args_l.length() > 1) {
+ QString srt = QString("%1,%2").arg(args_l[0]).arg(args_l[1]);
+ QString filter;
+ if (args_l.length() > 2) {
+ filter = QStringList(args_l.mid(2)).join(",");
+ }
+ wsApp->emitTapParameterSignal(srt, filter, NULL);
+ }
+}
+}
+
+void register_service_response_tables(gpointer data, gpointer)
+{
+ register_srt_t *srt = (register_srt_t*)data;
+ const char* short_name = proto_get_protocol_short_name(find_protocol_by_id(get_srt_proto_id(srt)));
+ const char *cfg_abbr = srt_table_get_tap_string(srt);
+
+ /* XXX - These dissectors haven't been converted over to due to an "interactive input dialog" for their
+ tap data. Let those specific dialogs register for themselves */
+ if ((strcmp(short_name, "RPC") == 0) ||
+ (strcmp(short_name, "DCERPC") == 0))
+ return;
+
+ cfg_str_to_srt_[cfg_abbr] = srt;
+ TapParameterDialog::registerDialog(
+ short_name,
+ cfg_abbr,
+ REGISTER_STAT_GROUP_RESPONSE_TIME,
+ srt_init,
+ ServiceResponseTimeDialog::createSrtDialog);
+}
+
+enum {
+ srt_table_type_ = 1000,
+ srt_row_type_
+};
+
+class SrtRowTreeWidgetItem : public QTreeWidgetItem
+{
+public:
+ SrtRowTreeWidgetItem(QTreeWidgetItem *parent, const srt_procedure_t *procedure) :
+ QTreeWidgetItem (parent, srt_row_type_),
+ procedure_(procedure)
+ {
+ setText(SRT_COLUMN_PROCEDURE, procedure_->procedure);
+ setHidden(true);
+ }
+
+ void draw() {
+ setText(SRT_COLUMN_INDEX, QString::number(procedure_->index));
+ setText(SRT_COLUMN_CALLS, QString::number(procedure_->stats.num));
+ setText(SRT_COLUMN_MIN, QString::number(nstime_to_sec(&procedure_->stats.min), 'f', 6));
+ setText(SRT_COLUMN_MAX, QString::number(nstime_to_sec(&procedure_->stats.max), 'f', 6));
+ double avg_time = 0.0;
+ if (procedure_->stats.num) {
+ avg_time = nstime_to_sec(&procedure_->stats.min) / procedure_->stats.num;
+ }
+ setText(SRT_COLUMN_AVG, QString::number(avg_time, 'f', 6));
+ setText(SRT_COLUMN_SUM, QString::number(nstime_to_sec(&procedure_->stats.tot), 'f', 6));
+
+ for (int col = 0; col < columnCount(); col++) {
+ if (col == SRT_COLUMN_PROCEDURE) continue;
+ setTextAlignment(col, Qt::AlignRight);
+ }
+
+ setHidden(procedure_->stats.num < 1);
+ }
+
+ bool operator< (const QTreeWidgetItem &other) const
+ {
+ if (other.type() != srt_row_type_) return QTreeWidgetItem::operator< (other);
+ const SrtRowTreeWidgetItem *other_row = static_cast<const SrtRowTreeWidgetItem *>(&other);
+
+ switch (treeWidget()->sortColumn()) {
+ case SRT_COLUMN_INDEX:
+ return procedure_->index < other_row->procedure_->index;
+ case SRT_COLUMN_CALLS:
+ return procedure_->stats.num < other_row->procedure_->stats.num;
+ case SRT_COLUMN_MIN:
+ return nstime_cmp(&procedure_->stats.min, &other_row->procedure_->stats.min) < 0;
+ case SRT_COLUMN_MAX:
+ return nstime_cmp(&procedure_->stats.max, &other_row->procedure_->stats.max) < 0;
+ case SRT_COLUMN_AVG:
+ {
+ double our_avg = nstime_to_msec(&procedure_->stats.tot) / procedure_->stats.num;
+ double other_avg = nstime_to_msec(&other_row->procedure_->stats.tot) / other_row->procedure_->stats.num;
+ return our_avg < other_avg;
+ }
+ case SRT_COLUMN_SUM:
+ return nstime_cmp(&procedure_->stats.tot, &other_row->procedure_->stats.tot) < 0;
+ default:
+ break;
+ }
+
+ return QTreeWidgetItem::operator< (other);
+ }
+ QList<QVariant> rowData() {
+ double avg_time = 0.0;
+ if (procedure_->stats.num) {
+ avg_time = nstime_to_sec(&procedure_->stats.min) / procedure_->stats.num;
+ }
+ return QList<QVariant>() << QString(procedure_->procedure) << procedure_->index << procedure_->stats.num
+ << nstime_to_sec(&procedure_->stats.min) << nstime_to_sec(&procedure_->stats.max)
+ << avg_time << nstime_to_sec(&procedure_->stats.tot);
+ }
+private:
+ const srt_procedure_t *procedure_;
+};
+
+class SrtTableTreeWidgetItem : public QTreeWidgetItem
+{
+public:
+ SrtTableTreeWidgetItem(QTreeWidget *parent, const srt_stat_table *srt_table) :
+ QTreeWidgetItem (parent, srt_table_type_),
+ srt_table_(srt_table)
+ {
+ setText(0, srt_table_->name);
+ setFirstColumnSpanned(true);
+ setExpanded(true);
+
+ for (int i = 0; i < srt_table_->num_procs; i++) {
+ new SrtRowTreeWidgetItem(this, &srt_table_->procedures[i]);
+ }
+ }
+ const QString columnTitle() { return srt_table_->proc_column_name; }
+
+ QList<QVariant> rowData() {
+ return QList<QVariant>() << srt_table_->name;
+ }
+ const QString filterField() { return srt_table_->filter_string; }
+
+private:
+ const srt_stat_table *srt_table_;
+};
+
+
+ServiceResponseTimeDialog::ServiceResponseTimeDialog(QWidget &parent, CaptureFile &cf, register_srt *srt, const QString filter, int help_topic) :
+ TapParameterDialog(parent, cf, help_topic),
+ srt_(srt)
+{
+ QString subtitle = QString("%1 Service Response Time Statistics")
+ .arg(proto_get_protocol_short_name(find_protocol_by_id(get_srt_proto_id(srt))));
+ setWindowSubtitle(subtitle);
+
+ // Add number of columns for this stats_tree
+ QStringList header_labels;
+ for (int col = 0; col < NUM_SRT_COLUMNS; col++) {
+ header_labels.push_back(service_response_time_get_column_name(col));
+ }
+ statsTreeWidget()->setColumnCount(header_labels.count());
+ statsTreeWidget()->setHeaderLabels(header_labels);
+
+ for (int col = 0; col < statsTreeWidget()->columnCount(); col++) {
+ if (col == SRT_COLUMN_PROCEDURE) continue;
+ statsTreeWidget()->headerItem()->setTextAlignment(col, Qt::AlignRight);
+ }
+
+ QMenu *submenu;
+ QAction *insert_action = ctx_menu_.actions().first();
+
+ FilterAction::Action cur_action = FilterAction::ActionApply;
+ submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
+ foreach (FilterAction::ActionType at, FilterAction::actionTypes()) {
+ FilterAction *fa = new FilterAction(submenu, cur_action, at);
+ submenu->addAction(fa);
+ connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
+ filter_actions_ << fa;
+ }
+ ctx_menu_.insertMenu(insert_action, submenu);
+
+ cur_action = FilterAction::ActionPrepare;
+ submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
+ foreach (FilterAction::ActionType at, FilterAction::actionTypes()) {
+ FilterAction *fa = new FilterAction(submenu, cur_action, at);
+ submenu->addAction(fa);
+ connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
+ filter_actions_ << fa;
+ }
+ ctx_menu_.insertMenu(insert_action, submenu);
+
+ cur_action = FilterAction::ActionFind;
+ submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
+ foreach (FilterAction::ActionType at, FilterAction::actionTypes(cur_action)) {
+ FilterAction *fa = new FilterAction(submenu, cur_action, at);
+ submenu->addAction(fa);
+ connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
+ filter_actions_ << fa;
+ }
+ ctx_menu_.insertMenu(insert_action, submenu);
+
+ cur_action = FilterAction::ActionColorize;
+ submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
+ foreach (FilterAction::ActionType at, FilterAction::actionTypes(cur_action)) {
+ FilterAction *fa = new FilterAction(submenu, cur_action, at);
+ submenu->addAction(fa);
+ connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
+ filter_actions_ << fa;
+ }
+ ctx_menu_.insertMenu(insert_action, submenu);
+ ctx_menu_.insertSeparator(insert_action);
+
+ if (!filter.isEmpty()) {
+ setDisplayFilter(filter);
+ }
+
+ connect(statsTreeWidget(), SIGNAL(itemChanged(QTreeWidgetItem*,int)),
+ this, SLOT(statsTreeWidgetItemChanged()));
+}
+
+TapParameterDialog *ServiceResponseTimeDialog::createSrtDialog(QWidget &parent, const QString cfg_str, const QString filter, CaptureFile &cf)
+{
+ if (!cfg_str_to_srt_.contains(cfg_str)) {
+ // XXX MessageBox?
+ return NULL;
+ }
+
+ register_srt_t *srt = cfg_str_to_srt_[cfg_str];
+
+ return new ServiceResponseTimeDialog(parent, cf, srt, filter);
+}
+
+QTreeWidgetItem *ServiceResponseTimeDialog::addSrtTable(const struct _srt_stat_table *srt_table)
+{
+ SrtTableTreeWidgetItem *srtt_ti = new SrtTableTreeWidgetItem(statsTreeWidget(), srt_table);
+ return srtt_ti;
+}
+
+void ServiceResponseTimeDialog::tapReset(void *srtd_ptr)
+{
+ srt_data_t *srtd = (srt_data_t*) srtd_ptr;
+ ServiceResponseTimeDialog *srt_dlg = static_cast<ServiceResponseTimeDialog *>(srtd->user_data);
+ if (!srt_dlg) return;
+
+ reset_srt_table(srtd->srt_array, NULL, NULL);
+
+ srt_dlg->statsTreeWidget()->clear();
+ for (guint i = 0; i < srtd->srt_array->len; i++) {
+ srt_stat_table *srt_table = g_array_index(srtd->srt_array, srt_stat_table*, i);
+ srt_dlg->addSrtTable(srt_table);
+ }
+}
+
+void ServiceResponseTimeDialog::tapDraw(void *srtd_ptr)
+{
+ srt_data_t *srtd = (srt_data_t*) srtd_ptr;
+ ServiceResponseTimeDialog *srt_dlg = static_cast<ServiceResponseTimeDialog *>(srtd->user_data);
+ if (!srt_dlg || !srt_dlg->statsTreeWidget()) return;
+
+ QTreeWidgetItemIterator it(srt_dlg->statsTreeWidget());
+ while (*it) {
+ if ((*it)->type() == srt_row_type_) {
+ SrtRowTreeWidgetItem *srtr_ti = static_cast<SrtRowTreeWidgetItem *>((*it));
+ srtr_ti->draw();
+ }
+ ++it;
+ }
+
+ for (int i = 0; i < srt_dlg->statsTreeWidget()->columnCount() - 1; i++) {
+ srt_dlg->statsTreeWidget()->resizeColumnToContents(i);
+ }
+}
+
+void ServiceResponseTimeDialog::fillTree()
+{
+ srt_data_t srt_data;
+ srt_data.srt_array = g_array_new(FALSE, TRUE, sizeof(srt_stat_table*));
+ srt_data.user_data = this;
+
+ srt_table_dissector_init(srt_, srt_data.srt_array, NULL, NULL);
+
+ GString *error_string = register_tap_listener(get_srt_tap_listener_name(srt_),
+ &srt_data,
+ displayFilter(),
+ 0,
+ tapReset,
+ get_srt_packet_func(srt_),
+ tapDraw);
+ if (error_string) {
+ QMessageBox::critical(this, tr("Failed to attach to tap \"%1\"").arg(get_srt_tap_listener_name(srt_)),
+ error_string->str);
+ g_string_free(error_string, TRUE);
+ reject();
+ }
+
+ statsTreeWidget()->setSortingEnabled(false);
+
+ cf_retap_packets(cap_file_.capFile());
+
+ // We only have one table. Move its tree items up one level.
+ if (statsTreeWidget()->invisibleRootItem()->childCount() == 1) {
+ statsTreeWidget()->setRootIndex(statsTreeWidget()->model()->index(0, 0));
+ }
+
+ tapDraw(&srt_data);
+
+ statsTreeWidget()->sortItems(SRT_COLUMN_PROCEDURE, Qt::AscendingOrder);
+ statsTreeWidget()->setSortingEnabled(true);
+
+ remove_tap_listener(&srt_data);
+}
+
+QList<QVariant> ServiceResponseTimeDialog::treeItemData(QTreeWidgetItem *ti) const
+{
+ QList<QVariant> tid;
+ if (ti->type() == srt_table_type_) {
+ SrtTableTreeWidgetItem *srtt_ti = static_cast<SrtTableTreeWidgetItem *>(ti);
+ if (srtt_ti) {
+ tid << srtt_ti->rowData();
+ }
+ } else if (ti->type() == srt_row_type_) {
+ SrtRowTreeWidgetItem *srtr_ti = static_cast<SrtRowTreeWidgetItem *>(ti);
+ if (srtr_ti) {
+ tid << srtr_ti->rowData();
+ }
+ }
+ return tid;
+}
+
+const QString ServiceResponseTimeDialog::filterExpression()
+{
+ QString filter_expr;
+ if (statsTreeWidget()->selectedItems().count() > 0) {
+ QTreeWidgetItem *ti = statsTreeWidget()->selectedItems()[0];
+ if (ti->type() == srt_row_type_) {
+ SrtTableTreeWidgetItem *srtt_ti = static_cast<SrtTableTreeWidgetItem *>(ti->parent());
+ QString field = srtt_ti->filterField();
+ QString value = ti->text(SRT_COLUMN_INDEX);
+ if (srtt_ti && !field.isEmpty() && !value.isEmpty()) {
+ filter_expr = QString("%1==%2").arg(srtt_ti->filterField()).arg(value);
+ }
+ }
+ }
+ return filter_expr;
+}
+
+void ServiceResponseTimeDialog::statsTreeWidgetItemChanged()
+{
+ QString procedure_title = service_response_time_get_column_name(SRT_COLUMN_PROCEDURE);
+
+ if (statsTreeWidget()->selectedItems().count() > 0) {
+ QTreeWidgetItem *ti = statsTreeWidget()->selectedItems()[0];
+ SrtTableTreeWidgetItem *srtt_ti = NULL;
+ if (ti->type() == srt_row_type_) {
+ srtt_ti = static_cast<SrtTableTreeWidgetItem *>(ti->parent());
+ } else {
+ srtt_ti = static_cast<SrtTableTreeWidgetItem *>(ti);
+ }
+ if (srtt_ti) {
+ procedure_title = srtt_ti->columnTitle();
+ }
+ }
+ statsTreeWidget()->headerItem()->setText(SRT_COLUMN_PROCEDURE, procedure_title);
+}
+
+/*
+ * 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/service_response_time_dialog.h b/ui/qt/service_response_time_dialog.h
new file mode 100644
index 0000000000..b7c7569bd3
--- /dev/null
+++ b/ui/qt/service_response_time_dialog.h
@@ -0,0 +1,88 @@
+/* service_response_time_dialog.h
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __SERVICE_RESPONSE_TIME_DIALOG_H__
+#define __SERVICE_RESPONSE_TIME_DIALOG_H__
+
+#include "tap_parameter_dialog.h"
+
+struct register_srt;
+struct _srt_stat_table;
+
+class QTreeWidgetItem;
+
+class ServiceResponseTimeDialog : public TapParameterDialog
+{
+ Q_OBJECT
+
+public:
+ ServiceResponseTimeDialog(QWidget &parent, CaptureFile &cf, struct register_srt *srt, const QString filter, int help_topic = 0);
+ static TapParameterDialog *createSrtDialog(QWidget &parent, const QString cfg_str, const QString arg, CaptureFile &cf);
+
+protected:
+ /** Add service response time table.
+ *
+ * In the GTK+ UI "tables" are separate, tabbed widgets. In the Qt UI they are
+ * separate groups of QTreeWidgetItems.
+ *
+ * @param title The table title (not shown if only one table).
+ * @param num_procs Number of procedures.
+ * @param filter_string filter string or QString().
+ */
+ // gtk:service_response_table.h:init_srt_table
+ QTreeWidgetItem *addSrtTable(const struct _srt_stat_table *srt_table);
+
+private:
+ struct register_srt *srt_;
+
+ // Callbacks for register_tap_listener
+ static void tapReset(void *srtd_ptr);
+ static void tapDraw(void *srtd_ptr);
+
+ virtual void fillTree();
+ virtual QList<QVariant> treeItemData(QTreeWidgetItem *ti) const;
+ virtual const QString filterExpression();
+
+private slots:
+ void statsTreeWidgetItemChanged();
+};
+
+/** Register function to register dissectors that support SRT for GTK.
+ *
+ * @param data register_srt_t* representing dissetor SRT table
+ * @param user_data is unused
+ */
+void register_service_response_tables(gpointer data, gpointer user_data);
+
+#endif // __SERVICE_RESPONSE_TIME_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/stats_tree_dialog.cpp b/ui/qt/stats_tree_dialog.cpp
index 2152058bd3..6a06632a41 100644
--- a/ui/qt/stats_tree_dialog.cpp
+++ b/ui/qt/stats_tree_dialog.cpp
@@ -36,10 +36,16 @@ const int item_col_ = 0;
Q_DECLARE_METATYPE(stat_node *)
+const int sn_type_ = 1000;
class StatsTreeWidgetItem : public QTreeWidgetItem
{
public:
- StatsTreeWidgetItem(int type = Type) : QTreeWidgetItem (type) {}
+ StatsTreeWidgetItem(int type = sn_type_) : QTreeWidgetItem (type)
+ {
+ for (int col = 1; col < columnCount(); col++) {
+ setTextAlignment(col, Qt::AlignRight);
+ }
+ }
bool operator< (const QTreeWidgetItem &other) const
{
stat_node *thisnode = data(item_col_, Qt::UserRole).value<stat_node *>();
@@ -56,7 +62,6 @@ public:
}
};
-
StatsTreeDialog::StatsTreeDialog(QWidget &parent, CaptureFile &cf, const char *cfg_abbr) :
TapParameterDialog(parent, cf),
st_(NULL),
@@ -109,9 +114,7 @@ void StatsTreeDialog::fillTree()
GString *error_string;
if (!st_cfg_ || file_closed_) return;
- gchar* display_name_temp = stats_tree_get_displayname(st_cfg_->name);
- QString display_name(display_name_temp);
- g_free(display_name_temp);
+ QString display_name = gchar_free_to_qstring(stats_tree_get_displayname(st_cfg_->name));
// The GTK+ UI appends "Stats Tree" to the window title. If we do the same
// here we should expand the name completely, e.g. to "Statistics Tree".
@@ -126,16 +129,13 @@ void StatsTreeDialog::fillTree()
st_ = stats_tree_new(st_cfg_, NULL, displayFilter());
// Add number of columns for this stats_tree
- QStringList headerLabels;
+ QStringList header_labels;
for (int count = 0; count<st_->num_columns; count++) {
- headerLabels.push_back(stats_tree_get_column_name(count));
+ header_labels.push_back(stats_tree_get_column_name(count));
}
- statsTreeWidget()->setColumnCount(headerLabels.count());
- statsTreeWidget()->setHeaderLabels(headerLabels);
+ statsTreeWidget()->setColumnCount(header_labels.count());
+ statsTreeWidget()->setHeaderLabels(header_labels);
resize(st_->num_columns*80+80, height());
- for (int count = 0; count<st_->num_columns; count++) {
- headerLabels.push_back(stats_tree_get_column_name(count));
- }
statsTreeWidget()->setSortingEnabled(false);
error_string = register_tap_listener(st_cfg_->tapname,
diff --git a/ui/qt/stats_tree_dialog.h b/ui/qt/stats_tree_dialog.h
index 59cf812a15..0e810eb23c 100644
--- a/ui/qt/stats_tree_dialog.h
+++ b/ui/qt/stats_tree_dialog.h
@@ -39,7 +39,7 @@ class StatsTreeDialog : public TapParameterDialog
Q_OBJECT
public:
- explicit StatsTreeDialog(QWidget &parent, CaptureFile &cf, const char *cfg_abbr = NULL);
+ explicit StatsTreeDialog(QWidget &parent, CaptureFile &cf, const char *cfg_abbr);
~StatsTreeDialog();
static void setupNode(stat_node* node);
diff --git a/ui/qt/tap_parameter_dialog.cpp b/ui/qt/tap_parameter_dialog.cpp
index 13027a9e67..b5038d9a13 100644
--- a/ui/qt/tap_parameter_dialog.cpp
+++ b/ui/qt/tap_parameter_dialog.cpp
@@ -26,7 +26,11 @@
* - fillTree. Called when the dialog is first displayed and when a display
* filter is applied. In most cases the subclass should clear the tree and
* retap packets here.
- * - getTreeAsString.
+ * - filterExpression. If the subclass supports filtering context menu items
+ * ("Apply As Filter", etc.) it should fill in ctx_menu_ and implement
+ * filterExpression.
+ * - getTreeAsString or treeItemData. Used for "Copy" and "Save As...".
+ * -
*/
#include "tap_parameter_dialog.h"
@@ -34,6 +38,8 @@
#include <errno.h>
+#include "epan/stat_tap_ui.h"
+
#include "ui/last_open_dir.h"
#include "ui/utf8_entities.h"
@@ -42,19 +48,29 @@
#include "wireshark_application.h"
#include <QClipboard>
+#include <QContextMenuEvent>
#include <QMessageBox>
#include <QFileDialog>
+#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
+// Qt::escape
+#include <QTextDocument>
+#endif
// The GTK+ counterpart uses tap_param_dlg, which we don't use. If we
// need tap parameters we should probably create a TapParameterDialog
// class based on WiresharkDialog and subclass it here.
// To do:
-// - Add help
-// - Update to match bug 9452 / r53657
+// - Add tap parameters? SCSI SRT uses PARAM_ENUM. Everything appears to use
+// PARAM_FILTER. Nothing uses _UINT, _STRING, or _UUID.
+// - Update to match bug 9452 / r53657.
+// - Create a TapParameterTreeWidgetItem class?
+// - Better / more usable XML output.
const int expand_all_threshold_ = 100; // Arbitrary
+static QHash<const QString, tpdCreator> cfg_str_to_creator_;
+
TapParameterDialog::TapParameterDialog(QWidget &parent, CaptureFile &cf, int help_topic) :
WiresharkDialog(parent, cf),
ui(new Ui::TapParameterDialog),
@@ -63,11 +79,10 @@ TapParameterDialog::TapParameterDialog(QWidget &parent, CaptureFile &cf, int hel
ui->setupUi(this);
// XXX Use recent settings instead
- resize(parent.width(), parent.height() * 3 / 4);
+ resize(parent.width() * 2 / 3, parent.height() * 3 / 4);
- ui->statsTreeWidget->addAction(ui->actionCopyToClipboard);
- ui->statsTreeWidget->addAction(ui->actionSaveAs);
- ui->statsTreeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
+ ctx_menu_.addAction(ui->actionCopyToClipboard);
+ ctx_menu_.addAction(ui->actionSaveAs);
QPushButton *button;
button = ui->buttonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
@@ -86,6 +101,35 @@ TapParameterDialog::~TapParameterDialog()
delete ui;
}
+void TapParameterDialog::registerDialog(const QString title, const char *cfg_abbr, register_stat_group_t group, stat_tap_init_cb tap_init_cb, tpdCreator creator)
+{
+ stat_tap_ui ui_info;
+
+ ui_info.group = group;
+ ui_info.title = title.toUtf8().constData();
+ ui_info.cli_string = cfg_abbr;
+ ui_info.tap_init_cb = tap_init_cb;
+ ui_info.nparams = 0; // We'll need this for SCSI SRT
+ ui_info.params = NULL;
+ register_stat_tap_ui(&ui_info, NULL);
+
+ QString cfg_str = cfg_abbr;
+ cfg_str_to_creator_[cfg_str] = creator;
+
+ QAction *tpd_action = new QAction(title, NULL);
+ tpd_action->setData(cfg_str);
+ wsApp->addStatisticsGroupItem(group, tpd_action);
+}
+
+TapParameterDialog *TapParameterDialog::showTapParameterStatistics(QWidget &parent, CaptureFile &cf, const QString cfg_str, const QString arg, void *)
+{
+ if (cfg_str_to_creator_.contains(cfg_str)) {
+ TapParameterDialog *tpd = cfg_str_to_creator_[cfg_str](parent, cfg_str, arg, cf);
+ return tpd;
+ }
+ return NULL;
+}
+
QTreeWidget *TapParameterDialog::statsTreeWidget()
{
return ui->statsTreeWidget;
@@ -96,10 +140,237 @@ const char *TapParameterDialog::displayFilter()
return ui->displayFilterLineEdit->text().toUtf8().constData();
}
-//QByteArray TapParameterDialog::getTreeAsString(st_format_type format)
-//{
-// // XXX Iterate over the tree and build a QByteArray
-//}
+// This assumes that we're called before signals are connected or show()
+// is called.
+void TapParameterDialog::setDisplayFilter(const QString &filter)
+{
+ ui->displayFilterLineEdit->setText(filter);
+}
+
+void TapParameterDialog::filterActionTriggered()
+{
+ FilterAction *fa = qobject_cast<FilterAction *>(QObject::sender());
+ QString filter_expr = filterExpression();
+
+ if (!fa || filter_expr.isEmpty()) {
+ return;
+ }
+
+ emit filterAction(filter_expr, fa->action(), fa->actionType());
+}
+
+QString TapParameterDialog::itemDataToPlain(QVariant var, int width)
+{
+ QString plain_str;
+ int align_mul = 1;
+
+ switch (var.type()) {
+ case QVariant::String:
+ align_mul = -1;
+ // Fall through
+ case QVariant::Int:
+ case QVariant::UInt:
+ plain_str = var.toString();
+ break;
+ case QVariant::Double:
+ plain_str = QString::number(var.toDouble(), 'f', 6);
+ break;
+ default:
+ break;
+ }
+
+ if (plain_str.length() < width) {
+ plain_str = QString("%1").arg(plain_str, width * align_mul);
+ }
+ return plain_str;
+}
+
+QList<QVariant> TapParameterDialog::treeItemData(QTreeWidgetItem *) const
+{
+ return QList<QVariant>();
+}
+
+const QString plain_sep_ = " ";
+QByteArray TapParameterDialog::getTreeAsString(st_format_type format)
+{
+ QByteArray ba;
+ QTreeWidgetItemIterator it(ui->statsTreeWidget, QTreeWidgetItemIterator::NotHidden);
+
+ QList<int> col_widths;
+ QByteArray footer;
+
+ // Title + header
+ switch (format) {
+ case ST_FORMAT_PLAIN:
+ {
+ QTreeWidgetItemIterator width_it(it);
+ QString plain_header;
+ while (*width_it) {
+ QList<QVariant> tid = treeItemData((*width_it));
+ int col = 0;
+ foreach (QVariant var, tid) {
+ if (col_widths.size() <= col) {
+ col_widths.append(ui->statsTreeWidget->headerItem()->text(col).length());
+ }
+ if (var.type() == QVariant::String) {
+ col_widths[col] = qMax(col_widths[col], itemDataToPlain(var).length());
+ }
+ col++;
+ }
+ ++width_it;
+ }
+ QStringList ph_parts;
+ for (int col = 0; col < ui->statsTreeWidget->columnCount() && col < col_widths.length(); col++) {
+ ph_parts << ui->statsTreeWidget->headerItem()->text(col);
+ }
+ plain_header = ph_parts.join(plain_sep_);
+
+ QByteArray top_separator;
+ top_separator.fill('=', plain_header.length());
+ top_separator.append('\n');
+ QString file_header = QString("%1 - %2:\n").arg(windowSubtitle(), cap_file_.fileName());
+ footer.fill('-', plain_header.length());
+ footer.append('\n');
+ plain_header.append('\n');
+
+ ba.append(top_separator);
+ ba.append(file_header);
+ ba.append(plain_header);
+ ba.append(footer);
+ break;
+ }
+ case ST_FORMAT_CSV:
+ {
+ QString csv_header;
+ QStringList ch_parts;
+ for (int col = 0; col < ui->statsTreeWidget->columnCount(); col++) {
+ ch_parts << QString("\"%1\"").arg(ui->statsTreeWidget->headerItem()->text(col));
+ }
+ csv_header = ch_parts.join(",");
+ csv_header.append('\n');
+ ba.append(csv_header.toUtf8().constData());
+ break;
+ }
+ case ST_FORMAT_XML:
+ {
+ // XXX What's a useful format? This mostly conforms to DocBook.
+ ba.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ QString title;
+#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
+ title = Qt::escape(windowSubtitle());
+#else
+ title = QString(windowSubtitle()).toHtmlEscaped();
+#endif
+ QString xml_header = QString("<table>\n<title>%1</title>\n").arg(title);
+ ba.append(xml_header.toUtf8());
+ ba.append("<thead>\n<row>\n");
+ for (int col = 0; col < ui->statsTreeWidget->columnCount(); col++) {
+ title = ui->statsTreeWidget->headerItem()->text(col);
+#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
+ title = Qt::escape(title);
+#else
+ title = title.toHtmlEscaped();
+#endif
+ title = QString(" <entry>%1</entry>\n").arg(title);
+ ba.append(title.toUtf8());
+ }
+ ba.append("</row>\n</thead>\n");
+ ba.append("<tbody>\n");
+ footer = "</tbody>\n</table>\n";
+ break;
+ }
+ case ST_FORMAT_YAML:
+ {
+ QString yaml_header;
+ ba.append("---\n");
+ yaml_header = QString("Description: \"%1\"\nFile: \"%2\"\nItems:\n").arg(windowSubtitle()).arg(cap_file_.fileName());
+ ba.append(yaml_header.toUtf8());
+ break;
+ }
+ default:
+ break;
+ }
+
+ // Data
+ while (*it) {
+ QList<QVariant> tid = treeItemData((*it));
+ if (tid.length() < 1) continue;
+
+ if (tid.length() < ui->statsTreeWidget->columnCount()) {
+ // Assume we have a header
+ }
+
+ // Assume var length == columnCount
+ QString line;
+ QStringList parts;
+
+ switch (format) {
+ case ST_FORMAT_PLAIN:
+ {
+ int i = 0;
+ foreach (QVariant var, tid) {
+ parts << itemDataToPlain(var, col_widths[i]);
+ i++;
+ }
+ line = parts.join(plain_sep_);
+ line.append('\n');
+ break;
+ }
+ case ST_FORMAT_CSV:
+ foreach (QVariant var, tid) {
+ if (var.type() == QVariant::String) {
+ parts << QString("\"%1\"").arg(var.toString());
+ } else {
+ parts << var.toString();
+ }
+ }
+ line = parts.join(",");
+ line.append('\n');
+ break;
+ case ST_FORMAT_XML:
+ {
+ line = "<row>\n";
+ foreach (QVariant var, tid) {
+ QString entry;
+ #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
+ entry = Qt::escape(var.toString());
+ #else
+ entry = var.toString().toHtmlEscaped();
+ #endif
+ line.append(QString(" <entry>%1</entry>\n").arg(entry));
+ }
+ line.append("</row>\n");
+ break;
+ }
+ case ST_FORMAT_YAML:
+ {
+ int col = 0;
+ QString indent = "-";
+ foreach (QVariant var, tid) {
+ QString entry;
+ if (var.type() == QVariant::String) {
+ entry = QString("\"%1\"").arg(var.toString());
+ } else {
+ entry = var.toString();
+ }
+ line.append(QString(" %1 %2: %3\n").arg(indent).arg(ui->statsTreeWidget->headerItem()->text(col), entry));
+ indent = " ";
+ col++;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ ba.append(line.toUtf8());
+ ++it;
+ }
+
+ // Footer
+ ba.append(footer); // plain only?
+ return ba;
+}
void TapParameterDialog::drawTreeItems()
{
@@ -114,9 +385,24 @@ void TapParameterDialog::drawTreeItems()
void TapParameterDialog::showEvent(QShowEvent *)
{
+ if (!ui->displayFilterLineEdit->text().isEmpty()) {
+ QString filter = ui->displayFilterLineEdit->text();
+ emit updateFilter(filter, true);
+ }
fillTree();
}
+void TapParameterDialog::contextMenuEvent(QContextMenuEvent *event)
+{
+ bool enable = filterExpression().length() > 0 ? true : false;
+
+ foreach (QAction *fa, filter_actions_) {
+ fa->setEnabled(enable);
+ }
+
+ ctx_menu_.exec(event->globalPos());
+}
+
void TapParameterDialog::updateWidgets()
{
if (file_closed_) {
@@ -127,6 +413,8 @@ void TapParameterDialog::updateWidgets()
void TapParameterDialog::on_applyFilterButton_clicked()
{
+ QString filter = ui->displayFilterLineEdit->text();
+ emit updateFilter(filter, true);
fillTree();
}
@@ -182,13 +470,13 @@ void TapParameterDialog::on_actionSaveAs_triggered()
QByteArray tree_as_ba = getTreeAsString(format);
// actually save the file
- f = ws_fopen (file_name.toUtf8().constData(),"w");
- last_errno= errno;
+ f = ws_fopen (file_name.toUtf8().constData(), "w");
+ last_errno = errno;
if (f) {
- if (fputs(tree_as_ba.data(), f)!=EOF) {
- success= true;
+ if (fputs(tree_as_ba.data(), f) != EOF) {
+ success = true;
}
- last_errno= errno;
+ last_errno = errno;
fclose(f);
}
if (!success) {
diff --git a/ui/qt/tap_parameter_dialog.h b/ui/qt/tap_parameter_dialog.h
index 857c3f1006..8203fcbd7f 100644
--- a/ui/qt/tap_parameter_dialog.h
+++ b/ui/qt/tap_parameter_dialog.h
@@ -27,15 +27,23 @@
#include <glib.h>
#include <epan/stat_groups.h>
+#include <epan/stat_tap_ui.h>
+#include <QMenu>
+
+#include "filter_action.h"
#include "wireshark_dialog.h"
class QTreeWidget;
+class QTreeWidgetItem;
namespace Ui {
class TapParameterDialog;
}
+class TapParameterDialog;
+typedef TapParameterDialog* (*tpdCreator)(QWidget &parent, const QString cfg_str, const QString arg, CaptureFile &cf);
+
class TapParameterDialog : public WiresharkDialog
{
Q_OBJECT
@@ -44,14 +52,31 @@ public:
explicit TapParameterDialog(QWidget &parent, CaptureFile &cf, int help_topic = 0);
~TapParameterDialog();
+ static void registerDialog(const QString title, const char *cfg_abbr, register_stat_group_t group, stat_tap_init_cb tap_init_cb, tpdCreator creator);
+
+ static TapParameterDialog *showTapParameterStatistics(QWidget &parent, CaptureFile &cf, const QString cfg_str, const QString arg, void *);
+ // Needed by static member functions in subclasses. Should we just make
+ // "ui" available instead?
QTreeWidget *statsTreeWidget();
void drawTreeItems();
+signals:
+ void filterAction(QString& filter, FilterAction::Action action, FilterAction::ActionType type);
+ void updateFilter(QString &filter, bool force = false);
+
public slots:
protected:
+ QMenu ctx_menu_;
+ QList<QAction *> filter_actions_;
+
void showEvent(QShowEvent *);
+ void contextMenuEvent(QContextMenuEvent *event);
const char *displayFilter();
+ void setDisplayFilter(const QString &filter);
+
+protected slots:
+ void filterActionTriggered();
private:
Ui::TapParameterDialog *ui;
@@ -59,7 +84,10 @@ private:
// Called by the constructor. The subclass should tap packets here.
virtual void fillTree() = 0;
- virtual QByteArray getTreeAsString(st_format_type format) = 0;
+ virtual const QString filterExpression() { return QString(); }
+ QString itemDataToPlain(QVariant var, int width = 0);
+ virtual QList<QVariant> treeItemData(QTreeWidgetItem *) const;
+ virtual QByteArray getTreeAsString(st_format_type format);
private slots:
void updateWidgets();
diff --git a/ui/qt/traffic_table_dialog.cpp b/ui/qt/traffic_table_dialog.cpp
index 2d58a14db4..908765df14 100644
--- a/ui/qt/traffic_table_dialog.cpp
+++ b/ui/qt/traffic_table_dialog.cpp
@@ -24,7 +24,6 @@
#include <epan/addr_resolv.h>
#include <epan/prefs.h>
-#include <epan/stat_tap_ui.h>
//#include <epan/dissectors/packet-tcp.h>
diff --git a/ui/qt/wireshark_application.cpp b/ui/qt/wireshark_application.cpp
index 51627c24eb..b822cd3fc4 100644
--- a/ui/qt/wireshark_application.cpp
+++ b/ui/qt/wireshark_application.cpp
@@ -62,6 +62,7 @@
# include "ui/win32/console_win32.h"
#endif /* _WIN32 */
+#include <QAction>
#include <QDesktopServices>
#include <QDir>
#include <QEvent>
@@ -87,6 +88,7 @@ WiresharkApplication *wsApp = NULL;
static char *last_open_dir = NULL;
static bool updated_last_open_dir = FALSE;
static QList<recent_item_status *> recent_items_;
+static QHash<int, QList<QAction *> > statistics_groups_;
QString WiresharkApplication::window_title_separator_ = QString::fromUtf8(" " UTF8_MIDDLE_DOT " ");
@@ -563,6 +565,30 @@ void WiresharkApplication::emitStatCommandSignal(const QString &menu_path, const
emit openStatCommandDialog(menu_path, arg, userdata);
}
+void WiresharkApplication::emitTapParameterSignal(const QString cfg_abbr, const QString arg, void *userdata)
+{
+ emit openTapParameterDialog(cfg_abbr, arg, userdata);
+}
+
+void WiresharkApplication::addStatisticsGroupItem(int group, QAction *sg_action)
+{
+ if (!statistics_groups_.contains(group)) {
+ statistics_groups_[group] = QList<QAction *>();
+ }
+ statistics_groups_[group] << sg_action;
+}
+
+QList<QAction *> WiresharkApplication::statisticsGroupItems(int group)
+{
+ if (!statistics_groups_.contains(group)) {
+ return QList<QAction *>();
+ }
+
+ QList<QAction *> sgi_list = statistics_groups_[group];
+ std::sort(sgi_list.begin(), sgi_list.end(), qActionLessThan);
+ return sgi_list;
+}
+
#ifdef HAVE_LIBPCAP
static void
diff --git a/ui/qt/wireshark_application.h b/ui/qt/wireshark_application.h
index 2255fd5ace..5cfd5ee032 100644
--- a/ui/qt/wireshark_application.h
+++ b/ui/qt/wireshark_application.h
@@ -39,6 +39,7 @@
struct _e_prefs;
+class QAction;
class QSocketNotifier;
// Recent items:
@@ -72,6 +73,11 @@ public:
void registerUpdate(register_action_e action, const char *message);
void emitAppSignal(AppSignal signal);
void emitStatCommandSignal(const QString &menu_path, const char *arg, void *userdata);
+ void emitTapParameterSignal(const QString cfg_abbr, const QString arg, void *userdata);
+ // Map a register_stat_group_t to a list of stat_tap_ui.title
+ void addStatisticsGroupItem(int group, QAction *sg_action);
+ QList<QAction *>statisticsGroupItems(int group);
+
void allSystemsGo();
void refreshLocalInterfaces();
struct _e_prefs * readConfigurationFiles(char **gdp_path, char **dp_path);
@@ -129,6 +135,7 @@ signals:
void fieldsChanged();
void openStatCommandDialog(const QString &menu_path, const char *arg, void *userdata);
+ void openTapParameterDialog(const QString cfg_str, const QString arg, void *userdata);
public slots:
void clearRecentItems();
diff --git a/ui/qt/wireshark_dialog.h b/ui/qt/wireshark_dialog.h
index 9c5ed7d4f5..3e7e1e4334 100644
--- a/ui/qt/wireshark_dialog.h
+++ b/ui/qt/wireshark_dialog.h
@@ -41,6 +41,7 @@ public slots:
protected:
virtual void keyPressEvent(QKeyEvent *event) { QDialog::keyPressEvent(event); }
void setWindowSubtitle(const QString &subtitle);
+ const QString &windowSubtitle() { return subtitle_; }
virtual void updateWidgets();
CaptureFile &cap_file_;
@@ -50,7 +51,6 @@ protected slots:
virtual void captureFileClosing();
private:
- const QString &windowSubtitle() { return subtitle_; }
void setWindowTitleFromSubtitle();
QString subtitle_;
diff --git a/ui/service_response_time.c b/ui/service_response_time.c
new file mode 100644
index 0000000000..528675bb75
--- /dev/null
+++ b/ui/service_response_time.c
@@ -0,0 +1,47 @@
+/* service_response_time.c
+ * Copied from ui/gtk/service_response_time_table.h, 2003 Ronnie Sahlberg
+ * Helper routines and structs common to all service response time statistics
+ * taps.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "service_response_time.h"
+
+extern const char*
+service_response_time_get_column_name (int index)
+{
+ static const char *default_titles[] = { "Index", "Procedure", "Calls", "Min SRT (s)", "Max SRT (s)", "Avg SRT (s)", "Sum SRT (s)" };
+
+ if (index < 0 || index >= NUM_SRT_COLUMNS) return "(Unknown)";
+ return default_titles[index];
+}
+
+/*
+ * 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/service_response_time.h b/ui/service_response_time.h
new file mode 100644
index 0000000000..dcad54539e
--- /dev/null
+++ b/ui/service_response_time.h
@@ -0,0 +1,58 @@
+/* service_response_time.h
+ * Copied from ui/gtk/service_response_time_table.h, 2003 Ronnie Sahlberg
+ * Helper routines and structs common to all service response time statistics
+ * taps.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/** @file
+ * Helper routines common to all service response time statistics taps.
+ */
+
+#ifndef __SRT_STATS_H__
+#define __SRT_STATS_H__
+
+#include <epan/timestats.h>
+#include <epan/srt_table.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+enum
+{
+ SRT_COLUMN_INDEX,
+ SRT_COLUMN_PROCEDURE,
+ SRT_COLUMN_CALLS,
+ SRT_COLUMN_MIN,
+ SRT_COLUMN_MAX,
+ SRT_COLUMN_AVG,
+ SRT_COLUMN_SUM,
+ NUM_SRT_COLUMNS
+};
+
+/** returns the column name for a given column index */
+extern const char* service_response_time_get_column_name(int index);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __SRT_STATS_H__ */
diff --git a/wireshark-qt.cpp b/wireshark-qt.cpp
index 4640944a8c..2abae5dc95 100644
--- a/wireshark-qt.cpp
+++ b/wireshark-qt.cpp
@@ -116,6 +116,9 @@
#include "ui/qt/conversation_dialog.h"
#include "ui/qt/endpoint_dialog.h"
+#include "epan/srt_table.h"
+#include "ui/qt/service_response_time_dialog.h"
+
#if defined(HAVE_LIBPCAP) || defined(HAVE_EXTCAP)
capture_options global_capture_opts;
#endif
@@ -837,6 +840,7 @@ DIAG_ON(cast-qual)
register_all_tap_listeners();
conversation_table_set_gui_info(init_conversation_table);
hostlist_table_set_gui_info(init_endpoint_table);
+ srt_table_iterate_tables(register_service_response_tables, NULL);
if (ex_opt_count("read_format") > 0) {
in_file_type = open_info_name_to_type(ex_opt_get_next("read_format"));
@@ -1324,31 +1328,30 @@ DIAG_ON(cast-qual)
////////
#endif /* HAVE_LIBPCAP */
-// w->setEnabled(true);
wsApp->allSystemsGo();
g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Wireshark is up and ready to go");
SimpleDialog::displayQueuedMessages(main_w);
- /* user could specify filename, or display filter, or both */
+ /* User could specify filename, or display filter, or both */
if (!cf_name.isEmpty()) {
-
- /* Open stat windows; we do so after creating the main window,
- to avoid Qt warnings, and after successfully opening the
- capture file, so we know we have something to compute stats
- on, and after registering all dissectors, so that MATE will
- have registered its field array and we can have a tap filter
- with one of MATE's late-registered fields as part of the
- filter. */
- start_requested_stats();
-
- // XXX The GTK+ UI does error checking here.
- main_w->openCaptureFile(cf_name, read_filter, in_file_type);
- if (!dfilter.isEmpty())
- main_w->filterPackets(dfilter, false);
- if(go_to_packet != 0) {
- /* Jump to the specified frame number, kept for backward
- compatibility. */
- cf_goto_frame(CaptureFile::globalCapFile(), go_to_packet);
+ if (main_w->openCaptureFile(cf_name, read_filter, in_file_type)) {
+ if (!dfilter.isEmpty())
+ main_w->filterPackets(dfilter, false);
+
+ /* Open stat windows; we do so after creating the main window,
+ to avoid Qt warnings, and after successfully opening the
+ capture file, so we know we have something to compute stats
+ on, and after registering all dissectors, so that MATE will
+ have registered its field array and we can have a tap filter
+ with one of MATE's late-registered fields as part of the
+ filter. */
+ start_requested_stats();
+
+ if(go_to_packet != 0) {
+ /* Jump to the specified frame number, kept for backward
+ compatibility. */
+ cf_goto_frame(CaptureFile::globalCapFile(), go_to_packet);
+ }
}
}
#ifdef HAVE_LIBPCAP