summaryrefslogtreecommitdiff
path: root/ui/qt/service_response_time_dialog.cpp
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 /ui/qt/service_response_time_dialog.cpp
parent7fdc534cf967320fce4d560969385d6f19798b8d (diff)
downloadwireshark-fdb85029fd9b22b221f7123905f1bad66c04ce91.tar.gz
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>
Diffstat (limited to 'ui/qt/service_response_time_dialog.cpp')
-rw-r--r--ui/qt/service_response_time_dialog.cpp411
1 files changed, 411 insertions, 0 deletions
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:
+ */