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 "main_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
= QStringLiteral("%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 mainApp
->emitTapParameterSignal(simple_stat
, filter
, NULL
);
40 bool 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 (unsigned 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 (unsigned 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
);
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_
);
257 QString display_filter
= displayFilter();
258 if (!registerTapListener(stu_
->tap_name
,
260 display_filter
.toUtf8().constData(),
265 free_stat_tables(stu_
);
266 reject(); // XXX Stay open instead?
270 statsTreeWidget()->setSortingEnabled(false);
272 cap_file_
.retapPackets();
274 // We only have one table. Move its tree items up one level.
275 if (statsTreeWidget()->invisibleRootItem()->childCount() == 1) {
276 statsTreeWidget()->setRootIndex(statsTreeWidget()->model()->index(0, 0));
281 statsTreeWidget()->sortItems(0, Qt::AscendingOrder
);
282 statsTreeWidget()->setSortingEnabled(true);
284 removeTapListeners();
287 // This is how an item is represented for exporting.
288 QList
<QVariant
> SimpleStatisticsDialog::treeItemData(QTreeWidgetItem
*it
) const
290 // Cast up to our type.
291 SimpleStatisticsTreeWidgetItem
*rit
= dynamic_cast<SimpleStatisticsTreeWidgetItem
*>(it
);
293 return rit
->rowData();
296 return QList
<QVariant
>();
301 SimpleStatisticsDialog::~SimpleStatisticsDialog()
304 if (stu_
->refcount
== 0) {
306 free_stat_tables(stu_
);