summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ui/gtk/proto_hier_stats_dlg.c3
-rw-r--r--ui/proto_hier_stats.c31
-rw-r--r--ui/proto_hier_stats.h16
-rw-r--r--ui/qt/CMakeLists.txt3
-rw-r--r--ui/qt/Makefile.am2
-rw-r--r--ui/qt/Makefile.common4
-rw-r--r--ui/qt/Wireshark.pro3
-rw-r--r--ui/qt/filter_action.cpp9
-rw-r--r--ui/qt/filter_action.h1
-rw-r--r--ui/qt/main_window.cpp6
-rw-r--r--ui/qt/main_window.h1
-rw-r--r--ui/qt/main_window.ui32
-rw-r--r--ui/qt/main_window_slots.cpp9
-rw-r--r--ui/qt/protocol_hierarchy_dialog.cpp333
-rw-r--r--ui/qt/protocol_hierarchy_dialog.h92
-rw-r--r--ui/qt/protocol_hierarchy_dialog.ui126
-rw-r--r--ui/qt/qt_ui_utils.cpp6
-rw-r--r--ui/qt/qt_ui_utils.h8
-rw-r--r--ui/utf8_entities.h1
19 files changed, 654 insertions, 32 deletions
diff --git a/ui/gtk/proto_hier_stats_dlg.c b/ui/gtk/proto_hier_stats_dlg.c
index 87892e472d..4842d1f337 100644
--- a/ui/gtk/proto_hier_stats_dlg.c
+++ b/ui/gtk/proto_hier_stats_dlg.c
@@ -21,6 +21,7 @@
#include "config.h"
+#include "globals.h"
#include <string.h>
@@ -548,7 +549,7 @@ proto_hier_stats_cb(GtkWidget *w _U_, gpointer d _U_)
const char *current_filter;
/* Get the statistics. */
- ps = ph_stats_new();
+ ps = ph_stats_new(&cfile);
if (ps == NULL) {
/* The user gave up before we finished; don't pop up
a statistics window. */
diff --git a/ui/proto_hier_stats.c b/ui/proto_hier_stats.c
index 56376426a3..4857052496 100644
--- a/ui/proto_hier_stats.c
+++ b/ui/proto_hier_stats.c
@@ -22,8 +22,7 @@
#include "config.h"
-
-#include "globals.h"
+#include "file.h"
#include "frame_tvbuff.h"
#include "ui/proto_hier_stats.h"
#include "ui/progress_dlg.h"
@@ -132,7 +131,7 @@ process_tree(proto_tree *protocol_tree, ph_stats_t* ps, guint pkt_len)
}
static gboolean
-process_record(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
+process_record(capture_file *cf, frame_data *frame, column_info *cinfo, ph_stats_t* ps)
{
epan_dissect_t edt;
struct wtap_pkthdr phdr;
@@ -143,14 +142,14 @@ process_record(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
/* Load the record from the capture file */
ws_buffer_init(&buf, 1500);
- if (!cf_read_record_r(&cfile, frame, &phdr, &buf))
+ if (!cf_read_record_r(cf, frame, &phdr, &buf))
return FALSE; /* failure */
/* Dissect the record tree not visible */
- epan_dissect_init(&edt, cfile.epan, TRUE, FALSE);
+ epan_dissect_init(&edt, cf->epan, TRUE, FALSE);
/* Don't fake protocols. We need them for the protocol hierarchy */
epan_dissect_fake_protocols(&edt, FALSE);
- epan_dissect_run(&edt, cfile.cd_t, &phdr, frame_tvbuff_new_buffer(frame, &buf), frame, cinfo);
+ epan_dissect_run(&edt, cf->cd_t, &phdr, frame_tvbuff_new_buffer(frame, &buf), frame, cinfo);
/* Get stats from this protocol tree */
process_tree(edt.tree, ps, frame->pkt_len);
@@ -173,7 +172,7 @@ process_record(frame_data *frame, column_info *cinfo, ph_stats_t* ps)
}
ph_stats_t*
-ph_stats_new(void)
+ph_stats_new(capture_file *cf)
{
ph_stats_t *ps;
guint32 framenum;
@@ -188,6 +187,8 @@ ph_stats_new(void)
int progbar_nextstep;
int progbar_quantum;
+ if (!cf) return NULL;
+
/* Initialize the data */
ps = g_new(ph_stats_t, 1);
ps->tot_packets = 0;
@@ -200,7 +201,7 @@ ph_stats_new(void)
progbar_nextstep = 0;
/* When we reach the value that triggers a progress bar update,
bump that value by this amount. */
- progbar_quantum = cfile.count/N_PROGBAR_UPDATES;
+ progbar_quantum = cf->count/N_PROGBAR_UPDATES;
/* Count of packets at which we've looked. */
count = 0;
/* Progress so far. */
@@ -212,8 +213,8 @@ ph_stats_new(void)
tot_packets = 0;
tot_bytes = 0;
- for (framenum = 1; framenum <= cfile.count; framenum++) {
- frame = frame_data_sequence_find(cfile.frames, framenum);
+ for (framenum = 1; framenum <= cf->count; framenum++) {
+ frame = frame_data_sequence_find(cf->frames, framenum);
/* Create the progress bar if necessary.
We check on every iteration of the loop, so that
@@ -223,7 +224,7 @@ ph_stats_new(void)
to get to the next progress bar step). */
if (progbar == NULL)
progbar = delayed_create_progress_dlg(
- cfile.window, "Computing",
+ cf->window, "Computing",
"protocol hierarchy statistics",
TRUE, &stop_flag, &start_time, progbar_val);
@@ -237,13 +238,13 @@ ph_stats_new(void)
/* let's not divide by zero. I should never be started
* with count == 0, so let's assert that
*/
- g_assert(cfile.count > 0);
+ g_assert(cf->count > 0);
- progbar_val = (gfloat) count / cfile.count;
+ progbar_val = (gfloat) count / cf->count;
if (progbar != NULL) {
g_snprintf(status_str, sizeof(status_str),
- "%4u of %u frames", count, cfile.count);
+ "%4u of %u frames", count, cf->count);
update_progress_dlg(progbar, progbar_val, status_str);
}
@@ -272,7 +273,7 @@ ph_stats_new(void)
}
/* we don't care about colinfo */
- if (!process_record(frame, NULL, ps)) {
+ if (!process_record(cf, frame, NULL, ps)) {
/*
* Give up, and set "stop_flag" so we
* just abort rather than popping up
diff --git a/ui/proto_hier_stats.h b/ui/proto_hier_stats.h
index c3ba23b8a0..6bfdadb540 100644
--- a/ui/proto_hier_stats.h
+++ b/ui/proto_hier_stats.h
@@ -22,6 +22,14 @@
#ifndef __UI_PROTO_HIER_STATS_H__
#define __UI_PROTO_HIER_STATS_H__
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @file
+ * Protocol Hierarchy Statistics
+ */
+
#include <epan/proto.h>
typedef struct {
@@ -41,11 +49,15 @@ typedef struct {
double last_time; /* seconds (msec resolution) of last packet */
} ph_stats_t;
-
-ph_stats_t *ph_stats_new(void);
+struct _capture_file;
+ph_stats_t *ph_stats_new(struct _capture_file *cf);
void ph_stats_free(ph_stats_t *ps);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
#endif /* __UI_PROTO_HIER_STATS_H__ */
/*
diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt
index 822d81ad90..0de0e9550f 100644
--- a/ui/qt/CMakeLists.txt
+++ b/ui/qt/CMakeLists.txt
@@ -80,6 +80,7 @@ set(WIRESHARK_QT_HEADERS
profile_dialog.h
progress_bar.h
proto_tree.h
+ protocol_hierarchy_dialog.h
qcustomplot.h
recent_file_status.h
rtp_stream_dialog.h
@@ -179,6 +180,7 @@ set(WIRESHARK_QT_SRC
profile_dialog.cpp
progress_bar.cpp
proto_tree.cpp
+ protocol_hierarchy_dialog.cpp
qt_ui_utils.cpp
recent_file_status.cpp
related_packet_delegate.cpp
@@ -263,6 +265,7 @@ set(WIRESHARK_QT_UI
preferences_dialog.ui
print_dialog.ui
profile_dialog.ui
+ protocol_hierarchy_dialog.ui
rtp_stream_dialog.ui
sctp_all_assocs_dialog.ui
sctp_assoc_analyse_dialog.ui
diff --git a/ui/qt/Makefile.am b/ui/qt/Makefile.am
index 07879dc839..cf17a2f4f3 100644
--- a/ui/qt/Makefile.am
+++ b/ui/qt/Makefile.am
@@ -184,6 +184,8 @@ print_dialog.cpp print_dialog.h: ui_print_dialog.h
profile_dialog.cpp profile_dialog.h: ui_profile_dialog.h
+protocol_hierarchy_dialog.cpp protocol_hierarchy_dialog.h: ui_protocol_hierarchy_dialog.h
+
remote_capture_dialog.cpp remote_capture_dialog.h: ui_remote_capture_dialog.h
remote_settings_dialog.cpp remote_settings_dialog.h: ui_remote_settings_dialog.h
diff --git a/ui/qt/Makefile.common b/ui/qt/Makefile.common
index 93a9ca25a6..e7e5927cc7 100644
--- a/ui/qt/Makefile.common
+++ b/ui/qt/Makefile.common
@@ -61,6 +61,7 @@ NODIST_GENERATED_HEADER_FILES = \
ui_preferences_dialog.h \
ui_print_dialog.h \
ui_profile_dialog.h \
+ ui_protocol_hierarchy_dialog.h \
ui_remote_capture_dialog.h \
ui_remote_settings_dialog.h \
ui_rtp_stream_dialog.h \
@@ -172,6 +173,7 @@ MOC_HDRS = \
profile_dialog.h \
progress_bar.h \
proto_tree.h \
+ protocol_hierarchy_dialog.h \
qcustomplot.h \
recent_file_status.h \
related_packet_delegate.h \
@@ -237,6 +239,7 @@ UI_FILES = \
preferences_dialog.ui \
print_dialog.ui \
profile_dialog.ui \
+ protocol_hierarchy_dialog.ui \
remote_capture_dialog.ui \
remote_settings_dialog.ui \
rtp_stream_dialog.ui \
@@ -373,6 +376,7 @@ WIRESHARK_QT_SRC = \
profile_dialog.cpp \
progress_bar.cpp \
proto_tree.cpp \
+ protocol_hierarchy_dialog.cpp \
qcustomplot.cpp \
qt_ui_utils.cpp \
recent_file_status.cpp \
diff --git a/ui/qt/Wireshark.pro b/ui/qt/Wireshark.pro
index aa49c0481a..bb5c21390b 100644
--- a/ui/qt/Wireshark.pro
+++ b/ui/qt/Wireshark.pro
@@ -237,6 +237,7 @@ FORMS += \
preferences_dialog.ui \
print_dialog.ui \
profile_dialog.ui \
+ protocol_hierarchy_dialog.ui \
remote_capture_dialog.ui \
remote_settings_dialog.ui \
rtp_stream_dialog.ui \
@@ -291,6 +292,7 @@ HEADERS += $$HEADERS_WS_C \
preferences_dialog.h \
print_dialog.h \
profile_dialog.h \
+ protocol_hierarchy_dialog.h \
remote_capture_dialog.h \
remote_settings_dialog.h \
rtp_stream_dialog.h \
@@ -650,6 +652,7 @@ SOURCES += \
profile_dialog.cpp \
progress_bar.cpp \
proto_tree.cpp \
+ protocol_hierarchy_dialog.cpp \
qcustomplot.cpp \
qt_ui_utils.cpp \
recent_file_status.cpp \
diff --git a/ui/qt/filter_action.cpp b/ui/qt/filter_action.cpp
index 5911911603..dfb36e1593 100644
--- a/ui/qt/filter_action.cpp
+++ b/ui/qt/filter_action.cpp
@@ -39,6 +39,15 @@ FilterAction::FilterAction(QObject *parent, FilterAction::Action action, FilterA
setText(actionTypeName(type));
}
+FilterAction::FilterAction(QObject *parent, FilterAction::Action action) :
+ QAction(parent),
+ action_(action),
+ type_(ActionTypePlain),
+ direction_(ActionDirectionAToAny)
+{
+ setText(actionName(action));
+}
+
const QList<FilterAction::Action> FilterAction::actions() {
static const QList<Action> actions_ = QList<Action>()
diff --git a/ui/qt/filter_action.h b/ui/qt/filter_action.h
index ae7afd2341..65b12e7cda 100644
--- a/ui/qt/filter_action.h
+++ b/ui/qt/filter_action.h
@@ -67,6 +67,7 @@ public:
explicit FilterAction(QObject *parent, Action action, ActionType type, ActionDirection direction);
explicit FilterAction(QObject *parent, Action action, ActionType type);
+ explicit FilterAction(QObject *parent, Action action);
Action action() { return action_; }
static const QList<Action> actions();
diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp
index 3defe4b8d0..5cf4ac2fa5 100644
--- a/ui/qt/main_window.cpp
+++ b/ui/qt/main_window.cpp
@@ -1786,10 +1786,8 @@ void MainWindow::setForCapturedPackets(bool have_captured_packets)
// have_captured_packets);
// set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/GoMenu/NextPacketInConversation",
// have_captured_packets);
-// set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/StatisticsMenu/Summary",
-// have_captured_packets);
-// set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/StatisticsMenu/ProtocolHierarchy",
-// have_captured_packets);
+ main_ui_->actionStatisticsCaptureFileProperties->setEnabled(have_captured_packets);
+ main_ui_->actionStatisticsProtocolHierarchy->setEnabled(have_captured_packets);
main_ui_->actionStatisticsIOGraph->setEnabled(have_captured_packets);
}
diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h
index 28dd1af301..f64979d4b4 100644
--- a/ui/qt/main_window.h
+++ b/ui/qt/main_window.h
@@ -375,6 +375,7 @@ private slots:
void on_actionCaptureStop_triggered();
void on_actionStatisticsCaptureFileProperties_triggered();
+ void on_actionStatisticsProtocolHierarchy_triggered();
void on_actionStatisticsFlowGraph_triggered();
void openTcpStreamDialog(int graph_type);
void on_actionStatisticsTcpStreamStevens_triggered();
diff --git a/ui/qt/main_window.ui b/ui/qt/main_window.ui
index b03092f5df..f61360bb60 100644
--- a/ui/qt/main_window.ui
+++ b/ui/qt/main_window.ui
@@ -27,7 +27,16 @@
<property name="spacing">
<number>0</number>
</property>
- <property name="margin">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -55,7 +64,7 @@
<item>
<widget class="QLineEdit" name="goToLineEdit">
<property name="inputMask">
- <string>900000000; </string>
+ <string>900000000</string>
</property>
</widget>
</item>
@@ -99,7 +108,7 @@
<x>0</x>
<y>0</y>
<width>960</width>
- <height>27</height>
+ <height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@@ -413,7 +422,7 @@
<addaction name="actionStatistics29WestLBTRU"/>
</widget>
<addaction name="actionStatisticsCaptureFileProperties"/>
- <addaction name="actionProtocol_Hierarchy"/>
+ <addaction name="actionStatisticsProtocolHierarchy"/>
<addaction name="actionStatisticsConversations"/>
<addaction name="actionStatisticsEndpoints"/>
<addaction name="actionStatisticsPacketLen"/>
@@ -1413,12 +1422,15 @@
<string>Capture file properties</string>
</property>
</action>
- <action name="actionProtocol_Hierarchy">
+ <action name="actionStatisticsProtocolHierarchy">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
- <string>Protocol Hierarchy</string>
+ <string>&amp;Protocol Hierarchy</string>
+ </property>
+ <property name="toolTip">
+ <string>Show a summary of protocols present in the capture file.</string>
</property>
</action>
<action name="actionHelpMPCapinfos">
@@ -1578,12 +1590,12 @@
</property>
</action>
<action name="actionStatisticsHpfeeds">
- <property name="text">
+ <property name="text">
<string>HPFEEDS</string>
- </property>
- <property name="toolTip">
+ </property>
+ <property name="toolTip">
<string>hpfeeds statistics</string>
- </property>
+ </property>
</action>
<action name="actionStatisticsHTTPPacketCounter">
<property name="text">
diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp
index 1df80ab575..99988aaaa6 100644
--- a/ui/qt/main_window_slots.cpp
+++ b/ui/qt/main_window_slots.cpp
@@ -87,6 +87,7 @@
#include "preferences_dialog.h"
#include "print_dialog.h"
#include "profile_dialog.h"
+#include "protocol_hierarchy_dialog.h"
#include "qt_ui_utils.h"
#include "rtp_stream_dialog.h"
#include "sctp_all_assocs_dialog.h"
@@ -2703,6 +2704,14 @@ void MainWindow::on_actionStatisticsCaptureFileProperties_triggered()
capture_file_properties_dialog->show();
}
+void MainWindow::on_actionStatisticsProtocolHierarchy_triggered()
+{
+ ProtocolHierarchyDialog *phd = new ProtocolHierarchyDialog(*this, capture_file_);
+ connect(phd, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
+ this, SLOT(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
+ phd->show();
+}
+
#ifdef HAVE_LIBPCAP
void MainWindow::on_actionCaptureOptions_triggered()
{
diff --git a/ui/qt/protocol_hierarchy_dialog.cpp b/ui/qt/protocol_hierarchy_dialog.cpp
new file mode 100644
index 0000000000..86c828b600
--- /dev/null
+++ b/ui/qt/protocol_hierarchy_dialog.cpp
@@ -0,0 +1,333 @@
+/* protocol_hierarchy_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 "protocol_hierarchy_dialog.h"
+#include "ui_protocol_hierarchy_dialog.h"
+
+#include "ui/proto_hier_stats.h"
+#include "ui/utf8_entities.h"
+
+#include "color_utils.h"
+#include "qt_ui_utils.h"
+#include "wireshark_application.h"
+
+#include <QRect>
+#include <QPainter>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+
+/*
+ * @file Protocol Hierarchy Statistics dialog
+ *
+ * Displays tree of protocols with various statistics
+ * Allows filtering on tree items
+ */
+
+// To do:
+// - Copy as... YAML?
+// - Add time series data to ph_stats_node_t and draw sparklines.
+
+const int protocol_col_ = 0;
+const int pct_packets_col_ = 1;
+const int packets_col_ = 2;
+const int pct_bytes_col_ = 3;
+const int bytes_col_ = 4;
+const int bandwidth_col_ = 5;
+const int end_packets_col_ = 6;
+const int end_bytes_col_ = 7;
+const int end_bandwidth_col_ = 8;
+
+#include <QDebug>
+
+const int bar_em_width_ = 8;
+const double bar_blend_ = 0.15;
+void PercentBarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ QStyleOptionViewItemV4 optv4 = option;
+ QStyledItemDelegate::initStyleOption(&optv4, index);
+ double value = index.data(Qt::UserRole).toDouble();
+
+ QStyledItemDelegate::paint(painter, option, index);
+
+ painter->save();
+
+ if (QApplication::style()->objectName().contains("vista")) {
+ // QWindowsVistaStyle::drawControl does this internally. Unfortunately there
+ // doesn't appear to be a more general way to do this.
+ optv4.palette.setColor(QPalette::All, QPalette::HighlightedText,
+ optv4.palette.color(QPalette::Active, QPalette::Text));
+ }
+
+ QColor bar_color = ColorUtils::alphaBlend(optv4.palette.windowText(),
+ optv4.palette.window(), bar_blend_);
+ QPalette::ColorGroup cg = optv4.state & QStyle::State_Enabled
+ ? QPalette::Normal : QPalette::Disabled;
+ if (cg == QPalette::Normal && !(optv4.state & QStyle::State_Active))
+ cg = QPalette::Inactive;
+ if (optv4.state & QStyle::State_Selected) {
+ painter->setPen(optv4.palette.color(cg, QPalette::HighlightedText));
+ bar_color = ColorUtils::alphaBlend(optv4.palette.color(cg, QPalette::HighlightedText),
+ optv4.palette.color(cg, QPalette::Highlight),
+ bar_blend_);
+ } else {
+ painter->setPen(optv4.palette.color(cg, QPalette::Text));
+ }
+
+ QRect pct_rect = option.rect;
+ pct_rect.adjust(1, 1, -1, -1);
+ pct_rect.setWidth(((pct_rect.width() * value) / 100.0) + 0.5);
+ painter->fillRect(pct_rect, bar_color);
+
+ QString pct_str = QString::number(value, 'f', 1);
+ painter->drawText(option.rect, Qt::AlignCenter, pct_str);
+
+ painter->restore();
+}
+
+QSize PercentBarDelegate::sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ return QSize(option.fontMetrics.height() * bar_em_width_,
+ QStyledItemDelegate::sizeHint(option, index).height());
+}
+
+Q_DECLARE_METATYPE(ph_stats_t*)
+
+class ProtocolHierarchyTreeWidgetItem : public QTreeWidgetItem
+{
+public:
+ ProtocolHierarchyTreeWidgetItem(QTreeWidgetItem *parent, ph_stats_node_t *ph_stats_node) :
+ QTreeWidgetItem(parent),
+ bits_s_(0.0),
+ end_bits_s_(0.0)
+ {
+ if (!ph_stats_node) return;
+
+ filter_name_ = ph_stats_node->hfinfo->abbrev;
+ total_packets_ = ph_stats_node->num_pkts_total;
+ last_packets_ = ph_stats_node->num_pkts_last;
+ total_bytes_ = ph_stats_node->num_bytes_total;
+ last_bytes_ = ph_stats_node->num_bytes_last;
+
+ if (!parent) return;
+ ph_stats_t *ph_stats = parent->treeWidget()->invisibleRootItem()->data(0, Qt::UserRole).value<ph_stats_t*>();
+
+ if (!ph_stats || ph_stats->tot_packets < 1) return;
+ percent_packets_ = total_packets_ * 100.0 / ph_stats->tot_packets;
+ percent_bytes_ = total_bytes_ * 100.0 / ph_stats->tot_bytes;
+
+ double seconds = ph_stats->last_time - ph_stats->first_time;
+
+ if (seconds > 0.0) {
+ bits_s_ = total_bytes_ * 8.0 / seconds;
+ end_bits_s_ = last_bytes_ * 8.0 / seconds;
+ }
+
+ setText(protocol_col_, ph_stats_node->hfinfo->name);
+ setData(pct_packets_col_, Qt::UserRole, percent_packets_);
+ setText(packets_col_, QString::number(ph_stats_node->num_pkts_total));
+ setData(pct_bytes_col_, Qt::UserRole, percent_bytes_);
+ setText(bytes_col_, QString::number(ph_stats_node->num_bytes_total));
+ setText(bandwidth_col_, seconds > 0.0 ? bits_s_to_qstring(bits_s_) : UTF8_EM_DASH);
+ setText(end_packets_col_, QString::number(last_packets_));
+ setText(end_bytes_col_, QString::number(last_bytes_));
+ setText(end_bandwidth_col_, seconds > 0.0 ? bits_s_to_qstring(end_bits_s_) : UTF8_EM_DASH);
+ }
+
+ bool operator< (const QTreeWidgetItem &other) const
+ {
+ const ProtocolHierarchyTreeWidgetItem &other_phtwi = dynamic_cast<const ProtocolHierarchyTreeWidgetItem&>(other);
+
+ switch (treeWidget()->sortColumn()) {
+ case pct_packets_col_:
+ return percent_packets_ < other_phtwi.percent_packets_;
+ case packets_col_:
+ return total_packets_ < other_phtwi.total_packets_;
+ case pct_bytes_col_:
+ return percent_packets_ < other_phtwi.percent_packets_;
+ case bytes_col_:
+ return total_bytes_ < other_phtwi.total_bytes_;
+ case bandwidth_col_:
+ return bits_s_ < other_phtwi.bits_s_;
+ case end_packets_col_:
+ return last_packets_ < other_phtwi.last_packets_;
+ case end_bytes_col_:
+ return last_bytes_ < other_phtwi.last_bytes_;
+ case end_bandwidth_col_:
+ return end_bits_s_ < other_phtwi.end_bits_s_;
+ default:
+ break;
+ }
+
+ // Fall back to string comparison
+ return QTreeWidgetItem::operator <(other);
+ }
+
+ const QString filterName(void) { return filter_name_; }
+
+private:
+ QString filter_name_;
+ unsigned total_packets_;
+ unsigned last_packets_;
+ unsigned total_bytes_;
+ unsigned last_bytes_;
+
+ double percent_packets_;
+ double percent_bytes_;
+ double bits_s_;
+ double end_bits_s_;
+};
+
+ProtocolHierarchyDialog::ProtocolHierarchyDialog(QWidget &parent, CaptureFile &cf) :
+ WiresharkDialog(parent, cf),
+ ui(new Ui::ProtocolHierarchyDialog)
+{
+ ui->setupUi(this);
+ setWindowSubtitle(tr("Protocol Hierarchy Statistics"));
+
+ // XXX Use recent settings instead
+ resize(parent.width() * 4 / 5, parent.height() * 4 / 5);
+
+ ui->hierStatsTreeWidget->setItemDelegateForColumn(pct_packets_col_, &percent_bar_delegate_);
+ ui->hierStatsTreeWidget->setItemDelegateForColumn(pct_bytes_col_, &percent_bar_delegate_);
+ ph_stats_t *ph_stats = ph_stats_new(cap_file_.capFile());
+ if (ph_stats) {
+ ui->hierStatsTreeWidget->invisibleRootItem()->setData(0, Qt::UserRole, qVariantFromValue(ph_stats));
+ g_node_children_foreach(ph_stats->stats_tree, G_TRAVERSE_ALL, addTreeNode, ui->hierStatsTreeWidget->invisibleRootItem());
+ ph_stats_free(ph_stats);
+ }
+
+ ui->hierStatsTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(ui->hierStatsTreeWidget, SIGNAL(customContextMenuRequested(QPoint)),
+ SLOT(showProtoHierMenu(QPoint)));
+
+ ui->hierStatsTreeWidget->setSortingEnabled(true);
+ ui->hierStatsTreeWidget->expandAll();
+
+ for (int i = 0; i < ui->hierStatsTreeWidget->columnCount(); i++) {
+ ui->hierStatsTreeWidget->resizeColumnToContents(i);
+ }
+
+ QMenu *submenu;
+
+ 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()));
+ }
+
+ 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()));
+ }
+
+ FilterAction *fa = new FilterAction(&ctx_menu_, FilterAction::ActionFind);
+ ctx_menu_.addAction(fa);
+ connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
+
+ fa = new FilterAction(&ctx_menu_, FilterAction::ActionColorize);
+ ctx_menu_.addAction(fa);
+
+ display_filter_ = cap_file_.capFile()->dfilter;
+ updateWidgets();
+}
+
+ProtocolHierarchyDialog::~ProtocolHierarchyDialog()
+{
+ delete ui;
+}
+
+void ProtocolHierarchyDialog::showProtoHierMenu(QPoint pos)
+{
+ bool enable = ui->hierStatsTreeWidget->currentItem() != NULL && !file_closed_ ? true : false;
+
+ foreach (QMenu *submenu, ctx_menu_.findChildren<QMenu*>()) {
+ submenu->setEnabled(enable);
+ }
+ foreach (QAction *action, ctx_menu_.actions()) {
+ action->setEnabled(enable);
+ }
+
+ ctx_menu_.popup(ui->hierStatsTreeWidget->viewport()->mapToGlobal(pos));
+}
+
+void ProtocolHierarchyDialog::filterActionTriggered()
+{
+ ProtocolHierarchyTreeWidgetItem *phti = static_cast<ProtocolHierarchyTreeWidgetItem *>(ui->hierStatsTreeWidget->currentItem());
+ FilterAction *fa = qobject_cast<FilterAction *>(QObject::sender());
+
+ if (!fa || !phti) {
+ return;
+ }
+ QString filter_name(phti->filterName());
+
+ emit filterAction(filter_name, fa->action(), fa->actionType());
+}
+
+void ProtocolHierarchyDialog::addTreeNode(GNode *node, gpointer data)
+{
+ ph_stats_node_t *stats = (ph_stats_node_t *)node->data;
+ if (!stats) return;
+
+ QTreeWidgetItem *parent_ti = static_cast<QTreeWidgetItem *>(data);
+ if (!parent_ti) return;
+
+ ProtocolHierarchyTreeWidgetItem *phti = new ProtocolHierarchyTreeWidgetItem(parent_ti, stats);
+
+ g_node_children_foreach(node, G_TRAVERSE_ALL, addTreeNode, phti);
+
+}
+
+void ProtocolHierarchyDialog::updateWidgets()
+{
+ QString hint = "<small><i>";
+ if (display_filter_.isEmpty()) {
+ hint += tr("No display filter.");
+ } else {
+ hint += tr("Display filter: %1").arg(display_filter_);
+ }
+ hint += "</i></small>";
+ ui->hintLabel->setText(hint);
+}
+
+void ProtocolHierarchyDialog::on_buttonBox_helpRequested()
+{
+ wsApp->helpTopicAction(HELP_STATS_PROTO_HIERARCHY_DIALOG);
+}
+
+/*
+ * 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/protocol_hierarchy_dialog.h b/ui/qt/protocol_hierarchy_dialog.h
new file mode 100644
index 0000000000..e7d6e7aced
--- /dev/null
+++ b/ui/qt/protocol_hierarchy_dialog.h
@@ -0,0 +1,92 @@
+/* protocol_hierarchy_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 PROTOCOL_HIERARCHY_DIALOG_H
+#define PROTOCOL_HIERARCHY_DIALOG_H
+
+#include "filter_action.h"
+#include "wireshark_dialog.h"
+
+#include <QMenu>
+
+namespace Ui {
+class ProtocolHierarchyDialog;
+}
+
+#include <QStyledItemDelegate>
+
+class PercentBarDelegate : public QStyledItemDelegate
+{
+public:
+ PercentBarDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent) { }
+// void clear();
+// void addRelatedFrame(int frame_num);
+// void setConversationSpan(int first_frame, int last_frame);
+protected:
+ void paint(QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const;
+ QSize sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const;
+
+private:
+};
+
+class ProtocolHierarchyDialog : public WiresharkDialog
+{
+ Q_OBJECT
+
+public:
+ explicit ProtocolHierarchyDialog(QWidget &parent, CaptureFile &cf);
+ ~ProtocolHierarchyDialog();
+
+signals:
+ void filterAction(QString& filter, FilterAction::Action action, FilterAction::ActionType type);
+
+private slots:
+ void showProtoHierMenu(QPoint pos);
+ void filterActionTriggered();
+ void on_buttonBox_helpRequested();
+
+private:
+ Ui::ProtocolHierarchyDialog *ui;
+ QMenu ctx_menu_;
+ PercentBarDelegate percent_bar_delegate_;
+ QString display_filter_;
+
+ // Callback for g_node_children_foreach
+ static void addTreeNode(GNode *node, gpointer data);
+ void updateWidgets();
+};
+
+#endif // PROTOCOL_HIERARCHY_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/protocol_hierarchy_dialog.ui b/ui/qt/protocol_hierarchy_dialog.ui
new file mode 100644
index 0000000000..ea066ce916
--- /dev/null
+++ b/ui/qt/protocol_hierarchy_dialog.ui
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProtocolHierarchyDialog</class>
+ <widget class="QDialog" name="ProtocolHierarchyDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>620</width>
+ <height>480</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTreeWidget" name="hierStatsTreeWidget">
+ <attribute name="headerDefaultSectionSize">
+ <number>50</number>
+ </attribute>
+ <attribute name="headerShowSortIndicator" stdset="0">
+ <bool>false</bool>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>Protocol</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Percent Packets</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Packets</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Percent Bytes</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Bytes</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Bits/s</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>End Packets</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>End Bytes</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>End Bits/s</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="hintLabel">
+ <property name="text">
+ <string>&lt;small&gt;&lt;i&gt;A hint.&lt;/i&gt;&lt;/small&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Close|QDialogButtonBox::Help</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ProtocolHierarchyDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ProtocolHierarchyDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/ui/qt/qt_ui_utils.cpp b/ui/qt/qt_ui_utils.cpp
index 7e34706536..bbf4993667 100644
--- a/ui/qt/qt_ui_utils.cpp
+++ b/ui/qt/qt_ui_utils.cpp
@@ -97,6 +97,12 @@ const QString val_ext_to_qstring(const guint32 val, value_string_ext *vse, const
return val_qstr;
}
+const QString bits_s_to_qstring(const double val)
+{
+ return gchar_free_to_qstring(
+ format_size(val, format_size_unit_none|format_size_prefix_si));
+}
+
void smooth_font_size(QFont &font) {
QFontDatabase fdb;
#if QT_VERSION < QT_VERSION_CHECK(4, 8, 0)
diff --git a/ui/qt/qt_ui_utils.h b/ui/qt/qt_ui_utils.h
index 997e6c7dec..6eb9f70919 100644
--- a/ui/qt/qt_ui_utils.h
+++ b/ui/qt/qt_ui_utils.h
@@ -132,6 +132,14 @@ G_GNUC_PRINTF(3, 0);
const QString val_ext_to_qstring(const guint32 val, value_string_ext *vse, const char *fmt)
G_GNUC_PRINTF(3, 0);
+/** Convert bits per second value human-readable QString using format_size().
+ *
+ * @param val The value to convert to string.
+ *
+ * @return A QString representation of the data rate.
+ */
+const QString bits_s_to_qstring(const double val);
+
/**
* Round the current size of a font up to its next "smooth" size.
* If a smooth size can't be found the font is left unchanged.
diff --git a/ui/utf8_entities.h b/ui/utf8_entities.h
index d04f24d1d6..84d8bfd76e 100644
--- a/ui/utf8_entities.h
+++ b/ui/utf8_entities.h
@@ -34,6 +34,7 @@
#define UTF8_MIDDLE_DOT "\xc2\xb7" /* 183 / 0xb7 */
#define UTF8_BULLET "\xe2\x80\xa2" /* 8226 / 0x2024 */
+#define UTF8_EM_DASH "\xe2\x80\x94" /* 8212 / 0x2014 */
#define UTF8_HORIZONTAL_ELLIPSIS "\xe2\x80\xa6" /* 8230 / 0x2026 */
#define UTF8_LEFTWARDS_ARROW "\xe2\x86\x90" /* 8592 / 0x2190 */
#define UTF8_RIGHTWARDS_ARROW "\xe2\x86\x92" /* 8594 / 0x2192 */