1 /* simple_statistics_dialog.cpp
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * SPDX-License-Identifier: GPL-2.0-or-later
10 #include "simple_statistics_dialog.h"
14 #include "epan/stat_tap_ui.h"
16 #include <QTreeWidget>
18 #include "wireshark_application.h"
21 // - Hide rows with zero counts.
23 static QHash<const QString, stat_tap_table_ui *> cfg_str_to_stu_;
27 simple_stat_init(const char *args, void*) {
28 QStringList args_l = QString(args).split(',');
29 if (args_l.length() > 1) {
30 QString simple_stat = QString("%1,%2").arg(args_l[0]).arg(args_l[1]);
32 if (args_l.length() > 2) {
33 filter = QStringList(args_l.mid(2)).join(",");
35 wsApp->emitTapParameterSignal(simple_stat, filter, NULL);
40 gboolean register_simple_stat_tables(const void *key, void *value, void*) {
41 stat_tap_table_ui *stu = (stat_tap_table_ui*)value;
43 cfg_str_to_stu_[stu->cli_string] = stu;
44 TapParameterDialog::registerDialog(
49 SimpleStatisticsDialog::createSimpleStatisticsDialog);
54 simple_row_type_ = 1000
57 class SimpleStatisticsTreeWidgetItem : public QTreeWidgetItem
60 SimpleStatisticsTreeWidgetItem(QTreeWidgetItem *parent, int num_fields, const stat_tap_table_item_type *fields) :
61 QTreeWidgetItem (parent, simple_row_type_),
62 num_fields_(num_fields),
67 for (int i = 0; i < num_fields_ && i < treeWidget()->columnCount(); i++) {
68 switch (fields_[i].type) {
70 setText(i, QString::number(fields_[i].value.uint_value));
73 setText(i, QString::number(fields_[i].value.int_value));
75 case TABLE_ITEM_STRING:
76 setText(i, fields_[i].value.string_value);
78 case TABLE_ITEM_FLOAT:
79 setText(i, QString::number(fields_[i].value.float_value, 'f', 6));
82 setText(i, QString::number(fields_[i].value.enum_value));
89 bool operator< (const QTreeWidgetItem &other) const
91 int col = treeWidget()->sortColumn();
92 if (other.type() != simple_row_type_ || col >= num_fields_) {
93 return QTreeWidgetItem::operator< (other);
95 const SimpleStatisticsTreeWidgetItem *other_row = static_cast<const SimpleStatisticsTreeWidgetItem *>(&other);
96 switch (fields_[col].type) {
98 return fields_[col].value.uint_value < other_row->fields_[col].value.uint_value;
100 return fields_[col].value.int_value < other_row->fields_[col].value.int_value;
101 case TABLE_ITEM_STRING:
102 return g_strcmp0(fields_[col].value.string_value, other_row->fields_[col].value.string_value) < 0;
103 case TABLE_ITEM_FLOAT:
104 return fields_[col].value.float_value < other_row->fields_[col].value.float_value;
105 case TABLE_ITEM_ENUM:
106 return fields_[col].value.enum_value < other_row->fields_[col].value.enum_value;
111 return QTreeWidgetItem::operator< (other);
113 QList<QVariant> rowData() {
114 QList<QVariant> row_data;
116 for (int i = 0; i < num_fields_ && i < columnCount(); i++) {
117 switch (fields_[i].type) {
118 case TABLE_ITEM_UINT:
119 row_data << fields_[i].value.uint_value;
122 row_data << fields_[i].value.int_value;
124 case TABLE_ITEM_STRING:
125 row_data << fields_[i].value.string_value;
127 case TABLE_ITEM_FLOAT:
128 row_data << fields_[i].value.float_value;
130 case TABLE_ITEM_ENUM:
131 row_data << fields_[i].value.enum_value;
142 const int num_fields_;
143 const stat_tap_table_item_type *fields_;
146 SimpleStatisticsDialog::SimpleStatisticsDialog(QWidget &parent, CaptureFile &cf, struct _stat_tap_table_ui *stu, const QString filter, int help_topic) :
147 TapParameterDialog(parent, cf, help_topic),
151 setWindowSubtitle(stu_->title);
152 loadGeometry(0, 0, stu_->title);
154 QStringList header_labels;
155 for (int col = 0; col < (int) stu_->nfields; col++) {
156 header_labels << stu_->fields[col].column_name;
158 statsTreeWidget()->setHeaderLabels(header_labels);
160 for (int col = 0; col < (int) stu_->nfields; col++) {
161 if (stu_->fields[col].align == TAP_ALIGN_RIGHT) {
162 statsTreeWidget()->headerItem()->setTextAlignment(col, Qt::AlignRight);
166 setDisplayFilter(filter);
169 TapParameterDialog *SimpleStatisticsDialog::createSimpleStatisticsDialog(QWidget &parent, const QString cfg_str, const QString filter, CaptureFile &cf)
171 if (!cfg_str_to_stu_.contains(cfg_str)) {
176 stat_tap_table_ui *stu = cfg_str_to_stu_[cfg_str];
178 return new SimpleStatisticsDialog(parent, cf, stu, filter);
181 void SimpleStatisticsDialog::addMissingRows(struct _stat_data_t *stat_data)
184 // - tables (GTK+ UI only supports one currently)
185 // - elements (rows?)
186 // - fields (columns?)
187 // For multiple table support we might want to add them as subtrees, with
188 // the top-level tree item text set to the column labels for that table.
190 // Add any missing tables and rows.
191 for (guint table_idx = 0; table_idx < stat_data->stat_tap_data->tables->len; table_idx++) {
192 stat_tap_table* st_table = g_array_index(stat_data->stat_tap_data->tables, stat_tap_table*, table_idx);
193 QTreeWidgetItem *ti = NULL;
195 if ((int) table_idx >= statsTreeWidget()->topLevelItemCount()) {
196 ti = new QTreeWidgetItem(statsTreeWidget());
197 ti->setText(0, st_table->title);
198 ti->setFirstColumnSpanned(true);
199 ti->setExpanded(true);
201 ti = statsTreeWidget()->topLevelItem(table_idx);
203 for (guint element = ti->childCount(); element < st_table->num_elements; element++) {
204 stat_tap_table_item_type* fields = stat_tap_get_field_data(st_table, element, 0);
205 if (stu_->nfields > 0) {
206 SimpleStatisticsTreeWidgetItem *ss_ti = new SimpleStatisticsTreeWidgetItem(ti, st_table->num_fields, fields);
207 for (int col = 0; col < (int) stu_->nfields; col++) {
208 if (stu_->fields[col].align == TAP_ALIGN_RIGHT) {
209 ss_ti->setTextAlignment(col, Qt::AlignRight);
217 void SimpleStatisticsDialog::tapReset(void *sd_ptr)
219 stat_data_t *sd = (stat_data_t*) sd_ptr;
220 SimpleStatisticsDialog *ss_dlg = static_cast<SimpleStatisticsDialog *>(sd->user_data);
223 reset_stat_table(sd->stat_tap_data, NULL, NULL);
224 ss_dlg->statsTreeWidget()->clear();
227 void SimpleStatisticsDialog::tapDraw(void *sd_ptr)
229 stat_data_t *sd = (stat_data_t*) sd_ptr;
230 SimpleStatisticsDialog *ss_dlg = static_cast<SimpleStatisticsDialog *>(sd->user_data);
233 ss_dlg->addMissingRows(sd);
235 QTreeWidgetItemIterator it(ss_dlg->statsTreeWidget());
237 if ((*it)->type() == simple_row_type_) {
238 SimpleStatisticsTreeWidgetItem *ss_ti = static_cast<SimpleStatisticsTreeWidgetItem *>((*it));
244 for (int i = 0; i < ss_dlg->statsTreeWidget()->columnCount() - 1; i++) {
245 ss_dlg->statsTreeWidget()->resizeColumnToContents(i);
249 void SimpleStatisticsDialog::fillTree()
251 stat_data_t stat_data;
252 stat_data.stat_tap_data = stu_;
253 stat_data.user_data = this;
255 stu_->stat_tap_init_cb(stu_, NULL, NULL);
257 QString display_filter = displayFilter();
258 if (!registerTapListener(stu_->tap_name,
260 display_filter.toUtf8().constData(),
265 free_stat_tables(stu_, NULL, NULL);
266 reject(); // XXX Stay open instead?
270 cap_file_.retapPackets();
272 // We only have one table. Move its tree items up one level.
273 if (statsTreeWidget()->invisibleRootItem()->childCount() == 1) {
274 statsTreeWidget()->setRootIndex(statsTreeWidget()->model()->index(0, 0));
279 removeTapListeners();
282 // This is how an item is represented for exporting.
283 QList<QVariant> SimpleStatisticsDialog::treeItemData(QTreeWidgetItem *it) const
285 // Cast up to our type.
286 SimpleStatisticsTreeWidgetItem *rit = dynamic_cast<SimpleStatisticsTreeWidgetItem*>(it);
288 return rit->rowData();
291 return QList<QVariant>();
296 SimpleStatisticsDialog::~SimpleStatisticsDialog()
299 if (stu_->refcount == 0) {
301 free_stat_tables(stu_, NULL, NULL);
311 * indent-tabs-mode: nil
314 * ex: set shiftwidth=4 tabstop=8 expandtab:
315 * :indentSize=4:tabSize=8:noTabs=true: