summaryrefslogtreecommitdiffstats
path: root/ui/qt/expert_info_dialog.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /ui/qt/expert_info_dialog.cpp
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ui/qt/expert_info_dialog.cpp')
-rw-r--r--ui/qt/expert_info_dialog.cpp353
1 files changed, 353 insertions, 0 deletions
diff --git a/ui/qt/expert_info_dialog.cpp b/ui/qt/expert_info_dialog.cpp
new file mode 100644
index 0000000..38fa449
--- /dev/null
+++ b/ui/qt/expert_info_dialog.cpp
@@ -0,0 +1,353 @@
+/* expert_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 "expert_info_dialog.h"
+#include <ui_expert_info_dialog.h>
+
+#include "file.h"
+
+#include <epan/epan_dissect.h>
+#include <epan/expert.h>
+#include <epan/stat_tap_ui.h>
+#include <epan/tap.h>
+
+#include "progress_frame.h"
+#include "main_application.h"
+
+#include <QAction>
+#include <QHash>
+#include <QMenu>
+#include <QMessageBox>
+#include <QPushButton>
+
+// To do:
+// - Test with custom expert levels (Preferences -> Expert).
+// - Test with large captures.
+// - Promote to a fourth pane in the main window?
+// - Make colors configurable? In theory we could condense image/expert_indicators.svg,
+// down to one item, make sure it uses a single (or a few) base color(s), and generate
+// icons on the fly.
+
+ExpertInfoDialog::ExpertInfoDialog(QWidget &parent, CaptureFile &capture_file, QString displayFilter) :
+ WiresharkDialog(parent, capture_file),
+ ui(new Ui::ExpertInfoDialog),
+ expert_info_model_(new ExpertInfoModel(capture_file)),
+ proxyModel_(new ExpertInfoProxyModel(this)),
+ display_filter_(displayFilter)
+{
+ ui->setupUi(this);
+ ui->hintLabel->setSmallText();
+ ui->limitCheckBox->setChecked(! display_filter_.isEmpty());
+ connect(ui->limitCheckBox, &QCheckBox::toggled,
+ this, &ExpertInfoDialog::limitCheckBoxToggled);
+
+ proxyModel_->setSourceModel(expert_info_model_);
+ ui->expertInfoTreeView->setModel(proxyModel_);
+
+ setWindowSubtitle(tr("Expert Information"));
+
+ // Clicking on an item jumps to its associated packet. Make the dialog
+ // narrow so that we avoid obscuring the packet list.
+ int dlg_width = parent.width() * 3 / 5;
+ if (dlg_width < width()) dlg_width = width();
+ loadGeometry(dlg_width, parent.height());
+
+ int one_em = fontMetrics().height();
+ ui->expertInfoTreeView->setColumnWidth(ExpertInfoProxyModel::colProxySummary, one_em * 25); // Arbitrary
+
+ //Unfortunately this has to be done manually and not through .ui
+ ui->severitiesPushButton->setMenu(ui->menuShowExpert);
+
+ ui->expertInfoTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(ui->expertInfoTreeView, SIGNAL(customContextMenuRequested(QPoint)),
+ SLOT(showExpertInfoMenu(QPoint)));
+
+ 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;
+ QList<FilterAction::Action> extra_actions =
+ QList<FilterAction::Action>() << FilterAction::ActionFind
+ << FilterAction::ActionColorize
+ << FilterAction::ActionWebLookup
+ << FilterAction::ActionCopy;
+
+ foreach (FilterAction::Action extra_action, extra_actions) {
+ fa = new FilterAction(&ctx_menu_, extra_action);
+ ctx_menu_.addAction(fa);
+ connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
+ }
+
+ //Add collapse/expand all menu options
+ QAction *collapse = new QAction(tr("Collapse All"), this);
+ ctx_menu_.addAction(collapse);
+ connect(collapse, SIGNAL(triggered()), this, SLOT(collapseTree()));
+
+ QAction *expand = new QAction(tr("Expand All"), this);
+ ctx_menu_.addAction(expand);
+ connect(expand, SIGNAL(triggered()), this, SLOT(expandTree()));
+
+ connect(&cap_file_, SIGNAL(captureEvent(CaptureEvent)),
+ this, SLOT(captureEvent(CaptureEvent)));
+
+ ProgressFrame::addToButtonBox(ui->buttonBox, &parent);
+
+ updateWidgets();
+ QTimer::singleShot(0, this, SLOT(retapPackets()));
+}
+
+ExpertInfoDialog::~ExpertInfoDialog()
+{
+ delete ui;
+ delete proxyModel_;
+ delete expert_info_model_;
+}
+
+void ExpertInfoDialog::clearAllData()
+{
+ expert_info_model_->clear();
+}
+
+ExpertInfoTreeView* ExpertInfoDialog::getExpertInfoView()
+{
+ return ui->expertInfoTreeView;
+}
+
+void ExpertInfoDialog::retapPackets()
+{
+ if (file_closed_) return;
+
+ clearAllData();
+ removeTapListeners();
+
+ if (!registerTapListener("expert",
+ expert_info_model_,
+ ui->limitCheckBox->isChecked() ? display_filter_.toUtf8().constData(): NULL,
+ TL_REQUIRES_COLUMNS,
+ ExpertInfoModel::tapReset,
+ ExpertInfoModel::tapPacket,
+ ExpertInfoModel::tapDraw)) {
+ return;
+ }
+
+ cap_file_.retapPackets();
+}
+
+void ExpertInfoDialog::captureEvent(CaptureEvent e)
+{
+ if (e.captureContext() == CaptureEvent::Retap)
+ {
+ switch (e.eventType())
+ {
+ case CaptureEvent::Started:
+ ui->limitCheckBox->setEnabled(false);
+ ui->groupBySummaryCheckBox->setEnabled(false);
+ break;
+ case CaptureEvent::Finished:
+ updateWidgets();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void ExpertInfoDialog::updateWidgets()
+{
+ ui->limitCheckBox->setEnabled(! file_closed_ && ! display_filter_.isEmpty());
+
+ ui->actionShowError->setEnabled(expert_info_model_->numEvents(ExpertInfoModel::severityError) > 0);
+ ui->actionShowWarning->setEnabled(expert_info_model_->numEvents(ExpertInfoModel::severityWarn) > 0);
+ ui->actionShowNote->setEnabled(expert_info_model_->numEvents(ExpertInfoModel::severityNote) > 0);
+ ui->actionShowChat->setEnabled(expert_info_model_->numEvents(ExpertInfoModel::severityChat) > 0);
+ ui->actionShowComment->setEnabled(expert_info_model_->numEvents(ExpertInfoModel::severityComment) > 0);
+
+ QString tooltip;
+ QString hint;
+
+ if (file_closed_) {
+ tooltip = tr("Capture file closed.");
+ hint = tr("Capture file closed.");
+ } else if (display_filter_.isEmpty()) {
+ tooltip = tr("No display filter");
+ hint = tr("No display filter set.");
+ } else {
+ tooltip = tr("Limit information to \"%1\".").arg(display_filter_);
+ hint = tr("Display filter: \"%1\"").arg(display_filter_);
+ }
+
+ ui->limitCheckBox->setToolTip(tooltip);
+ ui->hintLabel->setText(hint);
+
+ ui->groupBySummaryCheckBox->setEnabled(!file_closed_);
+}
+
+void ExpertInfoDialog::on_actionShowError_toggled(bool checked)
+{
+ proxyModel_->setSeverityFilter(PI_ERROR, !checked);
+ updateWidgets();
+}
+
+void ExpertInfoDialog::on_actionShowWarning_toggled(bool checked)
+{
+ proxyModel_->setSeverityFilter(PI_WARN, !checked);
+ updateWidgets();
+}
+
+void ExpertInfoDialog::on_actionShowNote_toggled(bool checked)
+{
+ proxyModel_->setSeverityFilter(PI_NOTE, !checked);
+ updateWidgets();
+}
+
+void ExpertInfoDialog::on_actionShowChat_toggled(bool checked)
+{
+ proxyModel_->setSeverityFilter(PI_CHAT, !checked);
+ updateWidgets();
+}
+
+void ExpertInfoDialog::on_actionShowComment_toggled(bool checked)
+{
+ proxyModel_->setSeverityFilter(PI_COMMENT, !checked);
+ updateWidgets();
+}
+
+
+void ExpertInfoDialog::showExpertInfoMenu(QPoint pos)
+{
+ bool enable = true;
+ QModelIndex expertIndex = ui->expertInfoTreeView->indexAt(pos);
+ if (!expertIndex.isValid()) {
+ return;
+ }
+
+ if (proxyModel_->data(expertIndex.sibling(expertIndex.row(), ExpertInfoModel::colHf), Qt::DisplayRole).toInt() < 0) {
+ enable = false;
+ }
+
+ foreach (QMenu *submenu, ctx_menu_.findChildren<QMenu*>()) {
+ submenu->setEnabled(enable && !file_closed_);
+ }
+ foreach (QAction *action, ctx_menu_.actions()) {
+ FilterAction *fa = qobject_cast<FilterAction *>(action);
+ bool action_enable = enable && !file_closed_;
+ if (fa && (fa->action() == FilterAction::ActionWebLookup || fa->action() == FilterAction::ActionCopy)) {
+ action_enable = enable;
+ }
+ action->setEnabled(action_enable);
+ }
+
+ ctx_menu_.popup(ui->expertInfoTreeView->viewport()->mapToGlobal(pos));
+}
+
+void ExpertInfoDialog::filterActionTriggered()
+{
+ QModelIndex modelIndex = ui->expertInfoTreeView->currentIndex();
+ FilterAction *fa = qobject_cast<FilterAction *>(QObject::sender());
+
+ if (!fa || !modelIndex.isValid()) {
+ return;
+ }
+
+ int hf_index = proxyModel_->data(modelIndex.sibling(modelIndex.row(), ExpertInfoModel::colHf), Qt::DisplayRole).toInt();
+
+ if (hf_index > -1) {
+ QString filter_string;
+ if (fa->action() == FilterAction::ActionWebLookup) {
+ filter_string = QString("%1 %2")
+ .arg(proxyModel_->data(modelIndex.sibling(modelIndex.row(), ExpertInfoModel::colProtocol), Qt::DisplayRole).toString())
+ .arg(proxyModel_->data(modelIndex.sibling(modelIndex.row(), ExpertInfoModel::colSummary), Qt::DisplayRole).toString());
+ } else if (fa->action() == FilterAction::ActionCopy) {
+ filter_string = QString("%1 %2: %3")
+ .arg(proxyModel_->data(modelIndex.sibling(modelIndex.row(), ExpertInfoModel::colPacket), Qt::DisplayRole).toUInt())
+ .arg(proxyModel_->data(modelIndex.sibling(modelIndex.row(), ExpertInfoModel::colProtocol), Qt::DisplayRole).toString())
+ .arg(proxyModel_->data(modelIndex.sibling(modelIndex.row(), ExpertInfoModel::colSummary), Qt::DisplayRole).toString());
+ } else {
+ filter_string = proto_registrar_get_abbrev(hf_index);
+ }
+
+ if (! filter_string.isEmpty()) {
+ emit filterAction(filter_string, fa->action(), fa->actionType());
+ }
+ }
+}
+
+void ExpertInfoDialog::collapseTree()
+{
+ ui->expertInfoTreeView->collapseAll();
+}
+
+void ExpertInfoDialog::expandTree()
+{
+ ui->expertInfoTreeView->expandAll();
+}
+
+void ExpertInfoDialog::limitCheckBoxToggled(bool)
+{
+ retapPackets();
+}
+
+void ExpertInfoDialog::on_groupBySummaryCheckBox_toggled(bool)
+{
+ expert_info_model_->setGroupBySummary(ui->groupBySummaryCheckBox->isChecked());
+}
+
+// Show child (packet list) items that match the contents of searchLineEdit.
+void ExpertInfoDialog::on_searchLineEdit_textChanged(const QString &search_re)
+{
+ proxyModel_->setSummaryFilter(search_re);
+}
+
+void ExpertInfoDialog::on_buttonBox_helpRequested()
+{
+ mainApp->helpTopicAction(HELP_EXPERT_INFO_DIALOG);
+}
+
+// Stat command + args
+
+static void
+expert_info_init(const char *, void*) {
+ mainApp->emitStatCommandSignal("ExpertInfo", NULL, NULL);
+}
+
+static stat_tap_ui expert_info_stat_ui = {
+ REGISTER_STAT_GROUP_GENERIC,
+ NULL,
+ "expert",
+ expert_info_init,
+ 0,
+ NULL
+};
+
+extern "C" {
+
+void register_tap_listener_qt_expert_info(void);
+
+void
+register_tap_listener_qt_expert_info(void)
+{
+ register_stat_tap_ui(&expert_info_stat_ui, NULL);
+}
+
+}