diff options
-rw-r--r-- | ui/gtk/proto_hier_stats_dlg.c | 3 | ||||
-rw-r--r-- | ui/proto_hier_stats.c | 31 | ||||
-rw-r--r-- | ui/proto_hier_stats.h | 16 | ||||
-rw-r--r-- | ui/qt/CMakeLists.txt | 3 | ||||
-rw-r--r-- | ui/qt/Makefile.am | 2 | ||||
-rw-r--r-- | ui/qt/Makefile.common | 4 | ||||
-rw-r--r-- | ui/qt/Wireshark.pro | 3 | ||||
-rw-r--r-- | ui/qt/filter_action.cpp | 9 | ||||
-rw-r--r-- | ui/qt/filter_action.h | 1 | ||||
-rw-r--r-- | ui/qt/main_window.cpp | 6 | ||||
-rw-r--r-- | ui/qt/main_window.h | 1 | ||||
-rw-r--r-- | ui/qt/main_window.ui | 32 | ||||
-rw-r--r-- | ui/qt/main_window_slots.cpp | 9 | ||||
-rw-r--r-- | ui/qt/protocol_hierarchy_dialog.cpp | 333 | ||||
-rw-r--r-- | ui/qt/protocol_hierarchy_dialog.h | 92 | ||||
-rw-r--r-- | ui/qt/protocol_hierarchy_dialog.ui | 126 | ||||
-rw-r--r-- | ui/qt/qt_ui_utils.cpp | 6 | ||||
-rw-r--r-- | ui/qt/qt_ui_utils.h | 8 | ||||
-rw-r--r-- | ui/utf8_entities.h | 1 |
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>&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><small><i>A hint.</i></small></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 */ |