diff options
Diffstat (limited to '')
-rw-r--r-- | ui/qt/capture_info_dialog.cpp | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/ui/qt/capture_info_dialog.cpp b/ui/qt/capture_info_dialog.cpp new file mode 100644 index 00000000..5a29652c --- /dev/null +++ b/ui/qt/capture_info_dialog.cpp @@ -0,0 +1,205 @@ +/* capture_info_dialog.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include "wireshark.h" + +#include "ui/capture_info.h" + +#include "epan/capture_dissectors.h" +#include "epan/proto.h" + +#include "ui/capture.h" + +#include "capture_info_dialog.h" +#include "ui_capture_info_dialog.h" + +#include "main_application.h" + +#include "ui/qt/models/sparkline_delegate.h" + +#include "utils/qt_ui_utils.h" + +#include <QMainWindow> +#include <QPushButton> + +// The GTK+ version of this dialog showed a list of protocols and a simple bar graph +// (progress bars) showing their portion of the total number of packets. We show a +// a time series for each protocol using a sparkline. If we wanted to show bar graphs +// instead we could do so using QProgressBars or using PercentBarDelegates. + +extern "C" { + +// Callbacks defined in ui/capture_info.h. + +/* create the capture info dialog */ +/* will keep pointers to the fields in the counts parameter */ +void capture_info_ui_create( +capture_info *cinfo, +capture_session *cap_session) +{ + // cinfo->ui should have three values: + // - The main window, set in MainWindow::startCapture. + // - This dialog, set below. + // - NULL, set in our destructor. + + if (!cinfo || !cinfo->ui) return; + if (!cap_session) return; + QMainWindow *main_window = qobject_cast<QMainWindow *>((QObject *)cinfo->ui); + if (!main_window) return; + + // ...and we take it over from here. + CaptureInfoDialog *ci_dlg = new CaptureInfoDialog(cinfo, cap_session, main_window); + cinfo->ui = ci_dlg; + ci_dlg->show(); +} + +/* update the capture info dialog */ +/* As this function is a bit time critical while capturing, */ +/* prepare everything possible in the capture_info_ui_create() function above! */ +void capture_info_ui_update( +capture_info *cinfo) +{ + CaptureInfoDialog *ci_dlg = qobject_cast<CaptureInfoDialog *>((QObject *)cinfo->ui); + if (!ci_dlg) return; + ci_dlg->updateInfo(); +} + +/* destroy the capture info dialog again */ +void capture_info_ui_destroy( +capture_info *cinfo) +{ + CaptureInfoDialog *ci_dlg = qobject_cast<CaptureInfoDialog *>((QObject *)cinfo->ui); + if (!ci_dlg) return; + cinfo->ui = NULL; + delete ci_dlg; +} + +} // extern "C" + +CaptureInfoDialog::CaptureInfoDialog(struct _capture_info *cap_info, struct _capture_session *cap_session, QWidget *parent) : + GeometryStateDialog(parent), + ui(new Ui::CaptureInfoDialog), + cap_info_(cap_info), + cap_session_(cap_session) +{ + ui->setupUi(this); + loadGeometry(); + setWindowTitle(mainApp->windowTitleString(tr("Capture Information"))); + + QPushButton *button = ui->buttonBox->button(QDialogButtonBox::Abort); + button->setText(tr("Stop Capture")); + connect(button, &QPushButton::clicked, this, &CaptureInfoDialog::stopCapture); + + ci_model_ = new CaptureInfoModel(cap_info, this); + ui->treeView->setModel(ci_model_); + + ui->treeView->setItemDelegateForColumn(1, new SparkLineDelegate(this)); + + duration_.start(); +} + +CaptureInfoDialog::~CaptureInfoDialog() +{ + delete ui; + cap_info_->ui = NULL; +} + +void CaptureInfoDialog::updateInfo() +{ + int secs = int(duration_.elapsed() / 1000); + QString duration = tr("%1 packets, %2:%3:%4") + .arg(cap_info_->counts->total) + .arg(secs / 3600, 2, 10, QChar('0')) + .arg(secs % 3600 / 60, 2, 10, QChar('0')) + .arg(secs % 60, 2, 10, QChar('0')); + ui->infoLabel->setText(duration); + + ci_model_->updateInfo(); + ui->treeView->resizeColumnToContents(0); +} + +void CaptureInfoDialog::stopCapture() +{ +#ifdef HAVE_LIBPCAP + capture_stop(cap_session_); // ...or we could connect to MainWindow::stopCapture. +#endif // HAVE_LIBPCAP +} + +CaptureInfoModel::CaptureInfoModel(struct _capture_info *cap_info, QObject *parent) : + QAbstractTableModel(parent), + cap_info_(cap_info), + samples_(0), + last_other_(0) +{ +} + +void CaptureInfoModel::updateInfo() +{ + if (!cap_info_) return; + + GHashTableIter iter; + gpointer key, value; + + samples_++; + other_points_.append(cap_info_->counts->other - last_other_); + last_other_ = cap_info_->counts->other; + + g_hash_table_iter_init (&iter, cap_info_->counts->counts_hash); + while (g_hash_table_iter_next (&iter, &key, &value)) { + int proto_id = GPOINTER_TO_INT(key); + int cur_count = (int) capture_dissector_get_count(cap_info_->counts, proto_id); + if (!points_.contains(proto_id)) { + emit beginInsertRows(QModelIndex(), rowCount(), rowCount()); + QVector<int> zeroes = QVector<int>(samples_, 0); + points_[proto_id] = zeroes.toList(); + last_count_[proto_id] = 0; + emit endInsertRows(); + } else { + points_[proto_id].append(cur_count - last_count_[proto_id]); + last_count_[proto_id] = cur_count; + } + } + emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); +} + +int CaptureInfoModel::rowCount(const QModelIndex &) const +{ + if (!cap_info_) return 0; + return static_cast<int>(points_.keys().size()) + 1; +} + +int CaptureInfoModel::columnCount(const QModelIndex &) const +{ + return 2; +} + +QVariant CaptureInfoModel::data(const QModelIndex &index, int role) const +{ + QList<int> proto_ids = points_.keys(); + int row = index.row(); + + if (role == Qt::DisplayRole && index.column() == 0) { + if (row < proto_ids.size()) { + int proto_id = proto_ids.at(row); + return QString(proto_get_protocol_short_name(find_protocol_by_id(proto_id))); + } else { + return tr("Other"); + } + } else if (role == Qt::UserRole && index.column() == 1) { + if (row < proto_ids.size()) { + int proto_id = proto_ids.at(row); + return QVariant::fromValue(points_[proto_id]); + } else { + return QVariant::fromValue(other_points_); + } + } + return QVariant(); +} |