aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland Knall <rknall@gmail.com>2022-06-08 14:33:51 +0200
committerRoland Knall <rknall@gmail.com>2022-06-14 09:36:30 +0000
commita4f25e51150d81a76e6cf8644b60fdd000cd15ee (patch)
tree0f94a3dc68be55a5fafbe0a9edc099f255953e0b
parentf1cbc6b6623074ad6f403993e9f0cfee9bee4300 (diff)
Qt: Redesign TrafficTree Dialogs UI
The new UI should better group functionality and as well as better showing which taps are available and can be used.
-rw-r--r--docbook/release-notes.adoc3
-rw-r--r--ui/logwolf/CMakeLists.txt2
-rw-r--r--ui/qt/CMakeLists.txt2
-rw-r--r--ui/qt/conversation_dialog.cpp12
-rw-r--r--ui/qt/endpoint_dialog.cpp12
-rw-r--r--ui/qt/models/atap_data_model.cpp46
-rw-r--r--ui/qt/models/atap_data_model.h4
-rw-r--r--ui/qt/traffic_table_dialog.cpp25
-rw-r--r--ui/qt/traffic_table_dialog.h2
-rw-r--r--ui/qt/traffic_table_dialog.ui151
-rw-r--r--ui/qt/widgets/traffic_tab.cpp240
-rw-r--r--ui/qt/widgets/traffic_tab.h21
-rw-r--r--ui/qt/widgets/traffic_tree.cpp3
-rw-r--r--ui/qt/widgets/traffic_types_list.cpp236
-rw-r--r--ui/qt/widgets/traffic_types_list.h100
15 files changed, 591 insertions, 268 deletions
diff --git a/docbook/release-notes.adoc b/docbook/release-notes.adoc
index c874ef985c..b9b56d9f3f 100644
--- a/docbook/release-notes.adoc
+++ b/docbook/release-notes.adoc
@@ -37,6 +37,9 @@ wsbuglink:17779[]
- Conversations will be sorted via second address and first port number
- Endpoints will be sorted via port numbers
- IPv6 addresses are sorted correctly after IPv4 addresses
+ - The dialog elements have been moved to make it easier to handle for new users.
+ - Selection of tap elements is done via list
+ - All configurations and options are done via a left side button row
* The PCRE2 library (https://www.pcre.org/) is now a required dependency to build Wireshark.
diff --git a/ui/logwolf/CMakeLists.txt b/ui/logwolf/CMakeLists.txt
index 0a0b002a0e..c07b516dda 100644
--- a/ui/logwolf/CMakeLists.txt
+++ b/ui/logwolf/CMakeLists.txt
@@ -52,6 +52,7 @@ set(WIRESHARK_WIDGET_HEADERS
../qt/widgets/tabnav_tree_view.h
../qt/widgets/traffic_tab.h
../qt/widgets/traffic_tree.h
+ ../qt/widgets/traffic_types_list.h
../qt/widgets/wireshark_file_dialog.h
)
@@ -279,6 +280,7 @@ set(WIRESHARK_WIDGET_SRCS
../qt/widgets/tabnav_tree_view.cpp
../qt/widgets/traffic_tab.cpp
../qt/widgets/traffic_tree.cpp
+ ../qt/widgets/traffic_types_list.cpp
../qt/widgets/wireshark_file_dialog.cpp
)
diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt
index 77d4452a62..e2a9f591bd 100644
--- a/ui/qt/CMakeLists.txt
+++ b/ui/qt/CMakeLists.txt
@@ -52,6 +52,7 @@ set(WIRESHARK_WIDGET_HEADERS
widgets/tabnav_tree_view.h
widgets/traffic_tab.h
widgets/traffic_tree.h
+ widgets/traffic_types_list.h
widgets/wireless_timeline.h
widgets/wireshark_file_dialog.h
)
@@ -304,6 +305,7 @@ set(WIRESHARK_WIDGET_SRCS
widgets/tabnav_tree_view.cpp
widgets/traffic_tab.cpp
widgets/traffic_tree.cpp
+ widgets/traffic_types_list.cpp
widgets/wireless_timeline.cpp
widgets/wireshark_file_dialog.cpp
)
diff --git a/ui/qt/conversation_dialog.cpp b/ui/qt/conversation_dialog.cpp
index 61966b37aa..1dc5f02b2a 100644
--- a/ui/qt/conversation_dialog.cpp
+++ b/ui/qt/conversation_dialog.cpp
@@ -22,6 +22,7 @@
#include <ui/qt/models/timeline_delegate.h>
#include <ui/qt/models/atap_data_model.h>
#include <ui/qt/widgets/traffic_tab.h>
+#include <ui/qt/widgets/traffic_types_list.h>
#include "main_application.h"
#include <QCheckBox>
@@ -92,7 +93,9 @@ ConversationDialog::ConversationDialog(QWidget &parent, CaptureFile &cf) :
TrafficTableDialog(parent, cf, table_name_),
tcp_graph_requested_(false)
{
- trafficTab()->setProtocolInfo(tr("Conversation"), &(recent.conversation_tabs), &createModel);
+ trafficList()->setProtocolInfo(table_name_, &(recent.conversation_tabs));
+
+ trafficTab()->setProtocolInfo(table_name_, trafficList()->protocols(), trafficList()->selectedProtocols(), &createModel);
trafficTab()->setDelegate(CONV_COLUMN_START, &createDelegate);
trafficTab()->setDelegate(CONV_COLUMN_DURATION, &createDelegate);
trafficTab()->setFilter(cf.displayFilter());
@@ -114,13 +117,6 @@ ConversationDialog::ConversationDialog(QWidget &parent, CaptureFile &cf) :
absoluteTimeCheckBox()->show();
- addProgressFrame(&parent);
-
- QPushButton *close_bt = buttonBox()->button(QDialogButtonBox::Close);
- if (close_bt) {
- close_bt->setDefault(true);
- }
-
updateWidgets();
}
diff --git a/ui/qt/endpoint_dialog.cpp b/ui/qt/endpoint_dialog.cpp
index 4fe9cf92d7..c1a81235f8 100644
--- a/ui/qt/endpoint_dialog.cpp
+++ b/ui/qt/endpoint_dialog.cpp
@@ -26,6 +26,7 @@
#include <ui/qt/utils/variant_pointer.h>
#include <ui/qt/widgets/wireshark_file_dialog.h>
#include <ui/qt/widgets/traffic_tab.h>
+#include <ui/qt/widgets/traffic_types_list.h>
#include "main_application.h"
#include <QCheckBox>
@@ -66,7 +67,9 @@ static ATapDataModel * createModel(int protoId, QString filter)
EndpointDialog::EndpointDialog(QWidget &parent, CaptureFile &cf) :
TrafficTableDialog(parent, cf, table_name_)
{
- trafficTab()->setProtocolInfo(tr("Endpoints"), &(recent.endpoint_tabs), &createModel);
+ trafficList()->setProtocolInfo(table_name_, &(recent.endpoint_tabs));
+
+ trafficTab()->setProtocolInfo(table_name_, trafficList()->protocols(), trafficList()->selectedProtocols(), &createModel);
trafficTab()->setFilter(cf.displayFilter());
displayFilterCheckBox()->setChecked(cf.displayFilter().length() > 0);
connect(trafficTab(), &TrafficTab::filterAction, this, &EndpointDialog::filterAction);
@@ -86,13 +89,6 @@ EndpointDialog::EndpointDialog(QWidget &parent, CaptureFile &cf) :
map_bt_->setMenu(map_menu_);
#endif
- addProgressFrame(&parent);
-
- QPushButton *close_bt = buttonBox()->button(QDialogButtonBox::Close);
- if (close_bt) {
- close_bt->setDefault(true);
- }
-
updateWidgets();
}
diff --git a/ui/qt/models/atap_data_model.cpp b/ui/qt/models/atap_data_model.cpp
index 9b3a0669ff..d57b877bb8 100644
--- a/ui/qt/models/atap_data_model.cpp
+++ b/ui/qt/models/atap_data_model.cpp
@@ -76,24 +76,20 @@ QString ATapDataModel::tap() const
#ifdef HAVE_MAXMINDDB
bool ATapDataModel::hasGeoIPData()
{
- QString key = QString("geoip_found_%1").arg(_protoId);
- if (! _lookUp.keys().contains(key)) {
- bool coordsFound = false;
- int row = 0;
- int count = rowCount(QModelIndex());
- while (!coordsFound && row < count)
- {
- QModelIndex idx = index(row, 0);
- if (_type == ATapDataModel::DATAMODEL_ENDPOINT)
- coordsFound = qobject_cast<EndpointDataModel *>(this)->data(idx, ATapDataModel::GEODATA_AVAILABLE).toBool();
- else if (_type == ATapDataModel::DATAMODEL_CONVERSATION)
- coordsFound = qobject_cast<ConversationDataModel *>(this)->data(idx, ATapDataModel::GEODATA_AVAILABLE).toBool();
- row++;
- }
- _lookUp.insert(key, coordsFound);
+ bool coordsFound = false;
+ int row = 0;
+ int count = rowCount();
+ while (!coordsFound && row < count)
+ {
+ QModelIndex idx = index(row, 0);
+ if (_type == ATapDataModel::DATAMODEL_ENDPOINT)
+ coordsFound = qobject_cast<EndpointDataModel *>(this)->data(idx, ATapDataModel::GEODATA_AVAILABLE).toBool();
+ else if (_type == ATapDataModel::DATAMODEL_CONVERSATION)
+ coordsFound = qobject_cast<ConversationDataModel *>(this)->data(idx, ATapDataModel::GEODATA_AVAILABLE).toBool();
+ row++;
}
- return _lookUp.value(key, false).toBool();
+ return coordsFound;
}
#endif
@@ -190,7 +186,6 @@ void ATapDataModel::resetData()
return;
beginResetModel();
- _lookUp.clear();
storage_ = nullptr;
if (_type == ATapDataModel::DATAMODEL_ENDPOINT)
reset_hostlist_table_data(&hash_);
@@ -209,7 +204,6 @@ void ATapDataModel::updateData(GArray * newData)
return;
beginResetModel();
- _lookUp.clear();
storage_ = newData;
endResetModel();
@@ -510,15 +504,15 @@ QVariant EndpointDataModel::data(const QModelIndex &idx, int role) const
if (column == EndpointDataModel::ENDP_COLUMN_ADDR)
return (int)item->myaddress.type;
return (int) AT_NONE;
- } else if (role == ATapDataModel::DATA_IPV4_INTEGER || role == ATapDataModel::DATA_IPV6_VECTOR) {
+ } else if (role == ATapDataModel::DATA_IPV4_INTEGER || role == ATapDataModel::DATA_IPV6_LIST) {
if (column == EndpointDataModel::ENDP_COLUMN_ADDR) {
if (role == ATapDataModel::DATA_IPV4_INTEGER && item->myaddress.type == AT_IPv4) {
const ws_in4_addr * ip4 = (const ws_in4_addr *) item->myaddress.data;
return (quint32) GUINT32_TO_BE(*ip4);
}
- else if (role == ATapDataModel::DATA_IPV6_VECTOR && item->myaddress.type == AT_IPv6) {
+ else if (role == ATapDataModel::DATA_IPV6_LIST && item->myaddress.type == AT_IPv6) {
const ws_in6_addr * ip6 = (const ws_in6_addr *) item->myaddress.data;
- QVector<quint8> result;
+ QList<quint8> result;
result.reserve(16);
std::copy(ip6->bytes + 0, ip6->bytes + 16, std::back_inserter(result));
return QVariant::fromValue(result);
@@ -538,7 +532,7 @@ void ConversationDataModel::doDataUpdate()
_minRelStartTime = 0;
_maxRelStopTime = 0;
- for (int row = 0; row < rowCount(QModelIndex()); row ++) {
+ for (int row = 0; row < rowCount(); row ++) {
conv_item_t *conv_item = &g_array_index(storage_, conv_item_t, row);
if (row == 0) {
@@ -801,16 +795,16 @@ QVariant ConversationDataModel::data(const QModelIndex &idx, int role) const
return (int)tst_address.type;
}
return (int) AT_NONE;
- } else if (role == ATapDataModel::DATA_IPV4_INTEGER || role == ATapDataModel::DATA_IPV6_VECTOR) {
+ } else if (role == ATapDataModel::DATA_IPV4_INTEGER || role == ATapDataModel::DATA_IPV6_LIST) {
if (column == ConversationDataModel::CONV_COLUMN_SRC_ADDR || column == ConversationDataModel::CONV_COLUMN_DST_ADDR) {
address tst_address = column == ConversationDataModel::CONV_COLUMN_SRC_ADDR ? conv_item->src_address : conv_item->dst_address;
if (role == ATapDataModel::DATA_IPV4_INTEGER && tst_address.type == AT_IPv4) {
const ws_in4_addr * ip4 = (const ws_in4_addr *) tst_address.data;
return (quint32) GUINT32_TO_BE(*ip4);
}
- else if (role == ATapDataModel::DATA_IPV6_VECTOR && tst_address.type == AT_IPv6) {
+ else if (role == ATapDataModel::DATA_IPV6_LIST && tst_address.type == AT_IPv6) {
const ws_in6_addr * ip6 = (const ws_in6_addr *) tst_address.data;
- QVector<quint8> result;
+ QList<quint8> result;
result.reserve(16);
std::copy(ip6->bytes + 0, ip6->bytes + 16, std::back_inserter(result));
return QVariant::fromValue(result);
@@ -823,7 +817,7 @@ QVariant ConversationDataModel::data(const QModelIndex &idx, int role) const
conv_item_t * ConversationDataModel::itemForRow(int row)
{
- if (row < 0 || row >= rowCount(QModelIndex()))
+ if (row < 0 || row >= rowCount())
return nullptr;
return (conv_item_t *)&g_array_index(storage_, conv_item_t, row);
}
diff --git a/ui/qt/models/atap_data_model.h b/ui/qt/models/atap_data_model.h
index 2f71646fed..63b92eded7 100644
--- a/ui/qt/models/atap_data_model.h
+++ b/ui/qt/models/atap_data_model.h
@@ -50,7 +50,7 @@ public:
ROW_IS_FILTERED,
DATA_ADDRESS_TYPE,
DATA_IPV4_INTEGER,
- DATA_IPV6_VECTOR,
+ DATA_IPV6_LIST,
};
typedef enum {
@@ -232,8 +232,6 @@ protected:
private:
int _protoId;
- QMap<QString, QVariant> _lookUp;
-
conv_hash_t hash_;
};
diff --git a/ui/qt/traffic_table_dialog.cpp b/ui/qt/traffic_table_dialog.cpp
index 5f827d109c..ee4e81b639 100644
--- a/ui/qt/traffic_table_dialog.cpp
+++ b/ui/qt/traffic_table_dialog.cpp
@@ -19,6 +19,7 @@
#include "main_application.h"
#include <ui/qt/widgets/traffic_tab.h>
+#include <ui/qt/widgets/traffic_types_list.h>
#include <QCheckBox>
#include <QClipboard>
@@ -51,20 +52,28 @@ TrafficTableDialog::TrafficTableDialog(QWidget &parent, CaptureFile &cf, const Q
ui->absoluteTimeCheckBox->hide();
setWindowSubtitle(QString("%1s").arg(table_name));
+ ui->grpSettings->setTitle(QString("%1 Settings").arg(table_name));
- copy_bt_ = ui->buttonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
+ copy_bt_ = buttonBox()->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
copy_bt_->setMenu(ui->trafficTab->createCopyMenu(copy_bt_));
ui->trafficTab->setFocus();
-
ui->trafficTab->useNanosecondTimestamps(cf.timestampPrecision() == WTAP_TSPREC_NSEC);
+ connect(ui->trafficList, &TrafficTypesList::protocolsChanged, ui->trafficTab, &TrafficTab::setOpenTabs);
+ connect(ui->trafficTab, &TrafficTab::tabsChanged, ui->trafficList, &TrafficTypesList::selectProtocols);
connect(mainApp, SIGNAL(addressResolutionChanged()), this, SLOT(currentTabChanged()));
connect(ui->trafficTab, SIGNAL(currentChanged(int)), this, SLOT(currentTabChanged()));
connect(&cap_file_, SIGNAL(captureEvent(CaptureEvent)), this, SLOT(captureEvent(CaptureEvent)));
- connect(ui->absoluteTimeCheckBox, &QCheckBox::toggled, trafficTab(), &TrafficTab::useAbsoluteTime);
- connect(trafficTab(), &TrafficTab::retapRequired, &cap_file_, &CaptureFile::delayedRetapPackets);
+ connect(ui->absoluteTimeCheckBox, &QCheckBox::toggled, ui->trafficTab, &TrafficTab::useAbsoluteTime);
+ connect(ui->trafficTab, &TrafficTab::retapRequired, &cap_file_, &CaptureFile::delayedRetapPackets);
+
+ QPushButton *close_bt = ui->buttonBox->button(QDialogButtonBox::Close);
+ if (close_bt)
+ close_bt->setDefault(true);
+
+ addProgressFrame(&parent);
}
TrafficTableDialog::~TrafficTableDialog()
@@ -79,7 +88,7 @@ void TrafficTableDialog::addProgressFrame(QObject *parent)
QDialogButtonBox *TrafficTableDialog::buttonBox() const
{
- return ui->buttonBox;
+ return ui->btnBoxSettings;
}
QCheckBox *TrafficTableDialog::displayFilterCheckBox() const
@@ -97,9 +106,15 @@ TrafficTab *TrafficTableDialog::trafficTab() const
return ui->trafficTab;
}
+TrafficTypesList *TrafficTableDialog::trafficList() const
+{
+ return ui->trafficList;
+}
+
void TrafficTableDialog::currentTabChanged()
{
bool has_resolution = ui->trafficTab->hasNameResolution();
+ copy_bt_->setMenu(ui->trafficTab->createCopyMenu(copy_bt_));
ui->nameResolutionCheckBox->setEnabled(has_resolution);
if (! has_resolution) {
diff --git a/ui/qt/traffic_table_dialog.h b/ui/qt/traffic_table_dialog.h
index 69e288dbeb..a417d59efb 100644
--- a/ui/qt/traffic_table_dialog.h
+++ b/ui/qt/traffic_table_dialog.h
@@ -31,6 +31,7 @@ class QPushButton;
class QTabWidget;
class QTreeWidget;
class TrafficTab;
+class TrafficTypesList;
namespace Ui {
class TrafficTableDialog;
@@ -69,6 +70,7 @@ protected:
QCheckBox *displayFilterCheckBox() const;
QCheckBox *absoluteTimeCheckBox() const;
TrafficTab *trafficTab() const;
+ TrafficTypesList *trafficList() const;
protected slots:
virtual void currentTabChanged();
diff --git a/ui/qt/traffic_table_dialog.ui b/ui/qt/traffic_table_dialog.ui
index 0e12d11a58..d86ce3e9ed 100644
--- a/ui/qt/traffic_table_dialog.ui
+++ b/ui/qt/traffic_table_dialog.ui
@@ -10,80 +10,94 @@
<height>475</height>
</rect>
</property>
- <layout class="QVBoxLayout" name="verticalLayout">
+ <layout class="QVBoxLayout" name="verticalLayout_3">
<item>
- <widget class="TrafficTab" name="trafficTab"/>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,0,1">
- <item>
- <widget class="QCheckBox" name="nameResolutionCheckBox">
- <property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show resolved addresses and port names rather than plain values. The corresponding name resolution preference must be enabled.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="text">
- <string>Name resolution</string>
- </property>
- </widget>
- </item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
<item>
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
+ <widget class="QWidget" name="widget" native="true">
+ <property name="maximumSize">
<size>
- <width>40</width>
- <height>20</height>
+ <width>210</width>
+ <height>16777215</height>
</size>
</property>
- </spacer>
- </item>
- <item>
- <widget class="QCheckBox" name="displayFilterCheckBox">
- <property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Only show conversations matching the current display filter&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="text">
- <string>Limit to display filter</string>
- </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QGroupBox" name="grpSettings">
+ <property name="title">
+ <string>GroupBox</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QCheckBox" name="nameResolutionCheckBox">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show resolved addresses and port names rather than plain values. The corresponding name resolution preference must be enabled.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Name resolution</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="absoluteTimeCheckBox">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show absolute times in the start time column.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Absolute start time</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="displayFilterCheckBox">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Only show conversations matching the current display filter&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Limit to display filter</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="btnBoxSettings">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::NoButton</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="TrafficTypesList" name="trafficList"/>
+ </item>
+ </layout>
</widget>
</item>
<item>
- <spacer name="horizontalSpacer_3">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QCheckBox" name="absoluteTimeCheckBox">
- <property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show absolute times in the start time column.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="text">
- <string>Absolute start time</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
+ <widget class="TrafficTab" name="trafficTab"/>
</item>
</layout>
</item>
@@ -106,6 +120,11 @@
<header>ui/qt/widgets/traffic_tab.h</header>
<container>1</container>
</customwidget>
+ <customwidget>
+ <class>TrafficTypesList</class>
+ <extends>QTreeView</extends>
+ <header>ui/qt/widgets/traffic_types_list.h</header>
+ </customwidget>
</customwidgets>
<resources/>
<connections>
diff --git a/ui/qt/widgets/traffic_tab.cpp b/ui/qt/widgets/traffic_tab.cpp
index 8cfaeb5316..d517e46529 100644
--- a/ui/qt/widgets/traffic_tab.cpp
+++ b/ui/qt/widgets/traffic_tab.cpp
@@ -16,8 +16,6 @@
#include <wsutil/utf8_entities.h>
#include <wsutil/filesystem.h>
-#include "ui/recent.h"
-
#include <ui/qt/main_application.h>
#include <ui/qt/filter_action.h>
#include <ui/qt/models/atap_data_model.h>
@@ -26,7 +24,6 @@
#include <ui/qt/widgets/traffic_tree.h>
#include <ui/qt/widgets/detachable_tabwidget.h>
-#include <QVector>
#include <QStringList>
#include <QTreeView>
#include <QList>
@@ -175,103 +172,26 @@ bool TrafficDataFilterProxy::lessThan(const QModelIndex &source_left, const QMod
}
-static gboolean iterateProtocols(const void *key, void *value, void *userdata)
-{
- QMap<int, QString> *protocols = (QMap<int, QString> *)userdata;
- register_ct_t* ct = (register_ct_t*)value;
- const QString title = (const gchar*)key;
- int proto_id = get_conversation_proto_id(ct);
- protocols->insert(proto_id, title);
-
- return FALSE;
-}
-
TrafficTab::TrafficTab(QWidget * parent) :
DetachableTabWidget(parent)
{
_createModel = nullptr;
_disableTaps = false;
_nameResolution = false;
- _recentList = nullptr;
setTabBasename(QString());
-
}
TrafficTab::~TrafficTab()
-{
- prefs_clear_string_list(*_recentList);
- *_recentList = NULL;
- _protocolButtons.clear();
-
- foreach (int protoId, _tabs.keys())
- {
- char *title = g_strdup(proto_get_protocol_short_name(find_protocol_by_id(protoId)));
- *_recentList = g_list_append(*_recentList, title);
- }
-}
+{}
-void TrafficTab::setProtocolInfo(QString tableName, GList ** recentList, ATapModelCallback createModel)
+void TrafficTab::setProtocolInfo(QString tableName, QList<int> allProtocols, QList<int> openTabs, ATapModelCallback createModel)
{
setTabBasename(tableName);
- _recentList = recentList;
+ _allProtocols = allProtocols;
if (createModel)
_createModel = createModel;
- for (GList * endTab = *_recentList; endTab; endTab = endTab->next) {
- int protoId = proto_get_id_by_short_name((const char *)endTab->data);
- if (protoId > -1 && ! _protocols.contains(protoId))
- _protocols.append(protoId);
- }
-
- if (_protocols.isEmpty()) {
- QStringList protoNames = QStringList() << "eth" << "ip" << "ipv6" << "tcp" << "udp";
- foreach(QString name, protoNames)
- _protocols << proto_get_id_by_filter_name(name.toStdString().c_str());
- }
-
- QWidget * container = new QWidget(this);
- container->setFixedHeight(tabBar()->height());
- container->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
-
- QHBoxLayout * layout = new QHBoxLayout(container);
- layout->setContentsMargins(1, 0, 1, 0);
-
- QPushButton * cornerButton = new QPushButton(tr("%1 Types").arg(tableName));
- cornerButton->setFixedHeight(tabBar()->height());
- cornerButton->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
- QMenu * cornerMenu = new QMenu();
- conversation_table_iterate_tables(iterateProtocols, &_allTaps);
- foreach (int protoId, _allTaps.keys())
- {
- QAction * endPoint = new QAction(_allTaps[protoId], this);
- endPoint->setProperty("protocol", QVariant::fromValue(protoId));
- endPoint->setCheckable(true);
- endPoint->setChecked(_protocols.contains(protoId));
- connect(endPoint, &QAction::triggered, this, &TrafficTab::toggleTab);
- _protocolButtons.insert(protoId, endPoint);
- cornerMenu->addAction(endPoint);
- }
- cornerButton->setMenu(cornerMenu);
-
- layout->addWidget(cornerButton);
- setCornerWidget(container, Qt::TopRightCorner);
-
- updateTabs();
-}
-
-void TrafficTab::toggleTab(bool checked)
-{
- QAction * orig = qobject_cast<QAction *>(sender());
- if (!orig || ! orig->property("protocol").isValid())
- return;
-
- int protocol = orig->property("protocol").toInt();
- if (!checked && _protocols.contains(protocol))
- _protocols.removeAll(protocol);
- else if (checked && ! _protocols.contains(protocol))
- _protocols.append(protocol);
-
- updateTabs();
+ setOpenTabs(openTabs);
}
void TrafficTab::setDelegate(int column, ATapCreateDelegate createDelegate)
@@ -376,61 +296,79 @@ void TrafficTab::disableTap()
emit disablingTaps();
}
-void TrafficTab::updateTabs()
+void TrafficTab::setOpenTabs(QList<int> protocols)
{
- QList<int> keys = _tabs.keys();
- QList<int> allProtocols = _allTaps.keys();
-
- /* Adding new Tabs, and keeping the same order they are in the drop-down menu */
- foreach (int proto, _protocols) {
- if (!keys.contains(proto)) {
-
- int insertIndex = -1;
- auto bIdx = allProtocols.indexOf(proto);
- int idx = 0;
- while (insertIndex < 0 && idx < keys.count())
- {
- auto aIdx = allProtocols.indexOf(keys[idx]);
- if (aIdx < 0) /* Key not in all protocols. This would be a fluke */
- break;
- if (aIdx > bIdx) /* Should never be equal, as proto is not yet in keys */
- insertIndex = _tabs[keys[idx]];
- idx++;
- }
+ QList<int> tabs = _tabs.keys();
+ QList<int> remove;
+ blockSignals(true);
- QTreeView * tree = createTree(proto);
- QString tableName = proto_get_protocol_short_name(find_protocol_by_id(proto));
- TabData tabData(tableName, proto);
- QVariant storage;
- storage.setValue(tabData);
- if (tree->model()->rowCount() > 0)
- tableName += QString(" %1 %2").arg(UTF8_MIDDLE_DOT).arg(tree->model()->rowCount());
-
- int tabId = insertTab(insertIndex, tree, tableName);
- _protocolButtons[proto]->setChecked(true);
- tabBar()->setTabData(tabId, storage);
+ foreach(int protocol, protocols)
+ {
+ if (! tabs.contains(protocol)) {
+ insertProtoTab(protocol, false);
}
+ tabs.removeAll(protocol);
}
- /* Removing tabs no longer required. First filter the key array, for all tabs which
- * are still being displayed */
- foreach(int key, keys)
+ foreach(int protocol, tabs)
+ removeProtoTab(protocol, false);
+
+ blockSignals(false);
+
+ emit tabsChanged(_tabs.keys());
+ emit retapRequired();
+}
+
+void TrafficTab::insertProtoTab(int protoId, bool emitSignals)
+{
+ QList<int> lUsed = _tabs.keys();
+
+ if (lUsed.contains(protoId) && lUsed.count() != count())
{
- if ( _protocols.contains(key)) {
- _protocolButtons[key]->setChecked(true);
- keys.removeAll(key);
+ _tabs.clear();
+ for (int idx = 0; idx < count(); idx++) {
+ TabData tabData = qvariant_cast<TabData>(tabBar()->tabData(idx));
+ _tabs.insert(tabData.protoId(), idx);
}
+ lUsed = _tabs.keys();
}
- /* Removal step 2, now actually remove all elements. Counting down, otherwise removing
- * a tab will shift the indeces */
- for(int idx = count(); idx > 0; idx--) {
- TabData tabData = qvariant_cast<TabData>(tabBar()->tabData(idx - 1));
- if (keys.contains(tabData.protoId())) {
- removeTab(idx - 1);
- _protocolButtons[tabData.protoId()]->setChecked(false);
+
+ if (protoId <= 0 || lUsed.contains(protoId))
+ return;
+
+ QList<int> lFull = _allProtocols;
+ int idx = lFull.indexOf(protoId);
+ if (idx < 0)
+ return;
+
+ QList<int> part = lFull.mid(0, idx);
+ int insertAt = 0;
+ if (part.count() > 0) {
+ for (int cnt = idx - 1; cnt >= 0; cnt--) {
+ if (lUsed.contains(part[cnt]) && part[cnt] != protoId) {
+ insertAt = lUsed.indexOf(part[cnt]) + 1;
+ break;
+ }
}
}
+ QTreeView * tree = createTree(protoId);
+ QString tableName = proto_get_protocol_short_name(find_protocol_by_id(protoId));
+ TabData tabData(tableName, protoId);
+ QVariant storage;
+ storage.setValue(tabData);
+ if (tree->model()->rowCount() > 0)
+ tableName += QString(" %1 %2").arg(UTF8_MIDDLE_DOT).arg(tree->model()->rowCount());
+
+ int tabId = -1;
+ if (insertAt > -1)
+ tabId = insertTab(insertAt, tree, tableName);
+ else
+ tabId = addTab(tree, tableName);
+ if (tabId >= 0)
+ tabBar()->setTabData(tabId, storage);
+
+
/* We reset the correct tab idxs. That operations is costly, but it is only
* called during this operation and ensures, that other operations do not
* need to iterate, but rather can lookup the indeces. */
@@ -440,7 +378,37 @@ void TrafficTab::updateTabs()
_tabs.insert(tabData.protoId(), idx);
}
- emit retapRequired();
+ if (emitSignals) {
+ emit tabsChanged(_tabs.keys());
+ emit retapRequired();
+ }
+}
+
+void TrafficTab::removeProtoTab(int protoId, bool emitSignals)
+{
+ if (_tabs.keys().contains(protoId)) {
+ for(int idx = 0; idx < count(); idx++) {
+ TabData tabData = qvariant_cast<TabData>(tabBar()->tabData(idx));
+ if (protoId == tabData.protoId()) {
+ removeTab(idx);
+ break;
+ }
+ }
+ }
+
+ /* We reset the correct tab idxs. That operations is costly, but it is only
+ * called during this operation and ensures, that other operations do not
+ * need to iterate, but rather can lookup the indeces. */
+ _tabs.clear();
+ for (int idx = 0; idx < count(); idx++) {
+ TabData tabData = qvariant_cast<TabData>(tabBar()->tabData(idx));
+ _tabs.insert(tabData.protoId(), idx);
+ }
+
+ if (emitSignals) {
+ emit tabsChanged(_tabs.keys());
+ emit retapRequired();
+ }
}
void TrafficTab::doCurrentIndexChange(const QModelIndex & cur, const QModelIndex &)
@@ -484,7 +452,7 @@ void TrafficTab::modelReset()
return;
TrafficDataFilterProxy * qsfpm = qobject_cast<TrafficDataFilterProxy *>(sender());
- if (! qobject_cast<ATapDataModel *>(qsfpm->sourceModel()))
+ if (!qsfpm || ! qobject_cast<ATapDataModel *>(qsfpm->sourceModel()))
return;
ATapDataModel * atdm = qobject_cast<ATapDataModel *>(qsfpm->sourceModel());
@@ -519,7 +487,7 @@ ATapDataModel * TrafficTab::modelForWidget(QWidget * searchWidget)
QTreeView * tree = qobject_cast<QTreeView *>(searchWidget);
if (qobject_cast<TrafficDataFilterProxy *>(tree->model())) {
TrafficDataFilterProxy * qsfpm = qobject_cast<TrafficDataFilterProxy *>(tree->model());
- if (qobject_cast<ATapDataModel *>(qsfpm->sourceModel())) {
+ if (qsfpm && qobject_cast<ATapDataModel *>(qsfpm->sourceModel())) {
return qobject_cast<ATapDataModel *>(qsfpm->sourceModel());
}
}
@@ -736,9 +704,6 @@ void TrafficTab::detachTab(int tabIdx, QPoint pos) {
if (!model)
return;
- int protocol = model->protoId();
- _protocols.removeAll(protocol);
-
TrafficTree * tree = qobject_cast<TrafficTree *>(widget(tabIdx));
if (!tree)
return;
@@ -746,7 +711,7 @@ void TrafficTab::detachTab(int tabIdx, QPoint pos) {
connect(this, &TrafficTab::disablingTaps ,tree , &TrafficTree::disableTap);
DetachableTabWidget::detachTab(tabIdx, pos);
- updateTabs();
+ removeProtoTab(model->protoId());
}
void TrafficTab::attachTab(QWidget * content, QString name)
@@ -757,8 +722,5 @@ void TrafficTab::attachTab(QWidget * content, QString name)
return;
}
- int protocol = model->protoId();
- _protocols.append(protocol);
-
- updateTabs();
+ insertProtoTab(model->protoId());
}
diff --git a/ui/qt/widgets/traffic_tab.h b/ui/qt/widgets/traffic_tab.h
index 6a47984fec..c58a7ed592 100644
--- a/ui/qt/widgets/traffic_tab.h
+++ b/ui/qt/widgets/traffic_tab.h
@@ -12,8 +12,6 @@
#include "config.h"
-#include <ui/recent.h>
-
#include <ui/qt/models/atap_data_model.h>
#include <ui/qt/filter_action.h>
#include <ui/qt/widgets/detachable_tabwidget.h>
@@ -99,12 +97,13 @@ public:
* without having to removing the predefined object during setup of the UI.
*
* @param tableName The name for the table. Used for the protocol selection button
- * @param recentList The list to store the selected protocols in
+ * @param allProtocols a list of all possible protocols. It's order will set the tab oder
+ * @param openTabs a list of protocol ids to open at start of dialog
* @param createModel A callback, which will create the correct model for the trees
*
* @see ATapModelCallback
*/
- void setProtocolInfo(QString tableName, GList ** recentList, ATapModelCallback createModel);
+ void setProtocolInfo(QString tableName, QList<int> allProtocols, QList<int> openTabs, ATapModelCallback createModel);
/**
* @brief Set the Delegate object for a specific column
@@ -212,11 +211,14 @@ public slots:
*/
void useAbsoluteTime(bool absolute);
+ void setOpenTabs(QList<int> protocols);
+
signals:
void filterAction(QString filter, FilterAction::Action action, FilterAction::ActionType type);
void tabDataChanged(int idx);
void retapRequired();
void disablingTaps();
+ void tabsChanged(QList<int> protocols);
protected slots:
@@ -224,29 +226,26 @@ protected slots:
virtual void attachTab(QWidget * content, QString name) override;
private:
- QVector<int> _protocols;
- QMap<int, QString> _allTaps;
- QMap<int, QAction *> _protocolButtons;
+ QList<int> _allProtocols;
QMap<int, int> _tabs;
- GList ** _recentList;
ATapModelCallback _createModel;
QMap<int, ATapCreateDelegate> _createDelegates;
bool _disableTaps;
bool _nameResolution;
- void updateTabs();
QTreeView * createTree(int protoId);
ATapDataModel * modelForTabIndex(int tabIdx = -1);
ATapDataModel * modelForWidget(QWidget * widget);
+ void insertProtoTab(int protoId, bool emitSignals = true);
+ void removeProtoTab(int protoId, bool emitSignals = true);
+
#ifdef HAVE_MAXMINDDB
bool writeGeoIPMapFile(QFile * fp, bool json_only, ATapDataModel * dataModel);
#endif
private slots:
- void toggleTab(bool checked = false);
-
void modelReset();
void doCurrentIndexChange(const QModelIndex & cur, const QModelIndex & prev);
diff --git a/ui/qt/widgets/traffic_tree.cpp b/ui/qt/widgets/traffic_tree.cpp
index 31a1ab2bc6..3e370da83c 100644
--- a/ui/qt/widgets/traffic_tree.cpp
+++ b/ui/qt/widgets/traffic_tree.cpp
@@ -27,7 +27,6 @@
#include <ui/qt/utils/variant_pointer.h>
#include <ui/qt/widgets/traffic_tree.h>
-#include <QVector>
#include <QStringList>
#include <QTreeView>
#include <QList>
@@ -53,7 +52,7 @@ TrafficTree::TrafficTree(QString baseName, QWidget *parent) :
setRootIsDecorated(false);
setSortingEnabled(true);
setContextMenuPolicy(Qt::CustomContextMenu);
-
+
connect(this, &QTreeView::customContextMenuRequested, this, &TrafficTree::customContextMenu);
}
diff --git a/ui/qt/widgets/traffic_types_list.cpp b/ui/qt/widgets/traffic_types_list.cpp
new file mode 100644
index 0000000000..031f8c0295
--- /dev/null
+++ b/ui/qt/widgets/traffic_types_list.cpp
@@ -0,0 +1,236 @@
+/** @file
+ *
+ * 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 <glib.h>
+
+#include <epan/conversation_table.h>
+
+#include <ui/qt/widgets/traffic_types_list.h>
+
+#include <QStringList>
+
+TrafficTypesRowData::TrafficTypesRowData(int protocol, QString name) :
+ _protocol(protocol),
+ _name(name),
+ _checked(false)
+{}
+
+int TrafficTypesRowData::protocol() const
+{
+ return _protocol;
+}
+
+QString TrafficTypesRowData::name() const
+{
+ return _name;
+}
+
+bool TrafficTypesRowData::checked() const
+{
+ return _checked;
+}
+
+void TrafficTypesRowData::setChecked(bool checked)
+{
+ _checked = checked;
+}
+
+static gboolean iterateProtocols(const void *key, void *value, void *userdata)
+{
+ QList<TrafficTypesRowData> * protocols = (QList<TrafficTypesRowData> *)userdata;
+
+ register_ct_t* ct = (register_ct_t*)value;
+ const QString title = (const gchar*)key;
+ int proto_id = get_conversation_proto_id(ct);
+ TrafficTypesRowData entry(proto_id, title);
+ protocols->append(entry);
+
+ return FALSE;
+}
+
+TrafficTypesModel::TrafficTypesModel(GList ** recentList, QObject *parent) :
+ QAbstractListModel(parent),
+ _recentList(recentList)
+{
+ conversation_table_iterate_tables(iterateProtocols, &_allTaps);
+
+ QList<int> _protocols;
+
+ for (GList * endTab = *_recentList; endTab; endTab = endTab->next) {
+ int protoId = proto_get_id_by_short_name((const char *)endTab->data);
+ if (protoId > -1 && ! _protocols.contains(protoId))
+ _protocols.append(protoId);
+ }
+
+ if (_protocols.isEmpty()) {
+ QStringList protoNames = QStringList() << "eth" << "ip" << "ipv6" << "tcp" << "udp";
+ foreach(QString name, protoNames)
+ _protocols << proto_get_id_by_filter_name(name.toStdString().c_str());
+ }
+
+ for(int cnt = 0; cnt < _allTaps.count(); cnt++)
+ {
+ _allTaps[cnt].setChecked(false);
+ if (_protocols.contains(_allTaps[cnt].protocol()))
+ _allTaps[cnt].setChecked(true);
+ }
+
+}
+
+int TrafficTypesModel::rowCount(const QModelIndex &) const
+{
+ return _allTaps.count();
+}
+
+int TrafficTypesModel::columnCount(const QModelIndex &) const
+{
+ return TrafficTypesModel::COL_NUM;
+}
+
+QVariant TrafficTypesModel::data(const QModelIndex &idx, int role) const
+{
+ if (!idx.isValid())
+ return QVariant();
+
+ TrafficTypesRowData data = _allTaps[idx.row()];
+ if (role == Qt::DisplayRole)
+ {
+ switch(idx.column())
+ {
+ case(TrafficTypesModel::COL_NAME):
+ return data.name();
+ case(TrafficTypesModel::COL_PROTOCOL):
+ return data.protocol();
+ }
+ } else if (role == Qt::CheckStateRole && idx.column() == TrafficTypesModel::COL_CHECKED) {
+ return data.checked() ? Qt::Checked : Qt::Unchecked;
+ } else if (role == TrafficTypesModel::TRAFFIC_PROTOCOL) {
+ return data.protocol();
+ } else if (role == TrafficTypesModel::TRAFFIC_IS_CHECKED) {
+ return (bool)data.checked();
+ }
+
+ return QVariant();
+}
+
+QVariant TrafficTypesModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (section < 0 || role != Qt::DisplayRole || orientation != Qt::Horizontal)
+ return QVariant();
+
+ if (section == TrafficTypesModel::COL_NAME)
+ return tr("Protocol");
+ return QVariant();
+}
+
+Qt::ItemFlags TrafficTypesModel::flags (const QModelIndex & idx) const
+{
+ Qt::ItemFlags defaultFlags = QAbstractListModel::flags(idx);
+ if (idx.isValid())
+ return defaultFlags | Qt::ItemIsUserCheckable;
+
+ return defaultFlags;
+}
+
+bool TrafficTypesModel::setData(const QModelIndex &idx, const QVariant &value, int role)
+{
+ if(!idx.isValid() || role != Qt::CheckStateRole)
+ return false;
+
+ if (_allTaps.count() <= idx.row())
+ return false;
+
+ _allTaps[idx.row()].setChecked(value == Qt::Checked);
+
+ QList<int> selected;
+ prefs_clear_string_list(*_recentList);
+ *_recentList = NULL;
+
+ for (int cnt = 0; cnt < _allTaps.count(); cnt++) {
+ if (_allTaps[cnt].checked()) {
+ int protoId = _allTaps[cnt].protocol();
+ selected.append(protoId);
+ char *title = g_strdup(proto_get_protocol_short_name(find_protocol_by_id(protoId)));
+ *_recentList = g_list_append(*_recentList, title);
+ }
+ }
+
+ emit protocolsChanged(selected);
+
+ emit dataChanged(idx, idx);
+ return true;
+}
+
+void TrafficTypesModel::selectProtocols(QList<int> protocols)
+{
+ beginResetModel();
+ for (int cnt = 0; cnt < _allTaps.count(); cnt++) {
+ _allTaps[cnt].setChecked(false);
+ if (protocols.contains(_allTaps[cnt].protocol()))
+ _allTaps[cnt].setChecked(true);
+ }
+ endResetModel();
+}
+
+TrafficTypesList::TrafficTypesList(QWidget *parent) :
+ QTreeView(parent)
+{
+ _name = QString();
+ _model = nullptr;
+
+ setAlternatingRowColors(true);
+ setRootIsDecorated(false);
+}
+
+void TrafficTypesList::setProtocolInfo(QString name, GList ** recentList)
+{
+ _name = name;
+
+ _model = new TrafficTypesModel(recentList);
+ setModel(_model);
+
+ connect(_model, &TrafficTypesModel::protocolsChanged, this, &TrafficTypesList::protocolsChanged);
+
+ resizeColumnToContents(0);
+ resizeColumnToContents(1);
+}
+
+void TrafficTypesList::selectProtocols(QList<int> protocols)
+{
+ if (_model)
+ _model->selectProtocols(protocols);
+}
+
+QList<int> TrafficTypesList::protocols() const
+{
+ QList<int> entries;
+ for (int cnt = 0; cnt < _model->rowCount(); cnt++) {
+ QModelIndex idx = _model->index(cnt, TrafficTypesModel::COL_CHECKED);
+ int protoId = _model->data(idx, TrafficTypesModel::TRAFFIC_PROTOCOL).toInt();
+ if (protoId > 0 && ! entries.contains(protoId))
+ entries.append(protoId);
+ }
+
+ return entries;
+}
+
+QList<int> TrafficTypesList::selectedProtocols() const
+{
+ QList<int> entries;
+ for (int cnt = 0; cnt < _model->rowCount(); cnt++) {
+ QModelIndex idx = _model->index(cnt, TrafficTypesModel::COL_CHECKED);
+ int protoId = _model->data(idx, TrafficTypesModel::TRAFFIC_PROTOCOL).toInt();
+ if (protoId > 0 && ! entries.contains(protoId) && _model->data(idx, TrafficTypesModel::TRAFFIC_IS_CHECKED).toBool())
+ entries.append(protoId);
+ }
+
+ return entries;
+}
diff --git a/ui/qt/widgets/traffic_types_list.h b/ui/qt/widgets/traffic_types_list.h
new file mode 100644
index 0000000000..fece2ef86a
--- /dev/null
+++ b/ui/qt/widgets/traffic_types_list.h
@@ -0,0 +1,100 @@
+/** @file
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef TRAFFIC_TYPES_LIST_H
+#define TRAFFIC_TYPES_LIST_H
+
+#include "config.h"
+
+#include <QTreeView>
+#include <QAbstractListModel>
+#include <QMap>
+#include <QString>
+
+class TrafficTypesRowData
+{
+
+public:
+ TrafficTypesRowData(int protocol, QString name);
+
+ int protocol() const;
+ QString name() const;
+ bool checked() const;
+ void setChecked(bool checked);
+
+private:
+ int _protocol;
+ QString _name;
+ bool _checked;
+};
+
+class TrafficTypesModel : public QAbstractListModel
+{
+ Q_OBJECT
+public:
+
+ enum {
+ TRAFFIC_PROTOCOL = Qt::UserRole,
+ TRAFFIC_IS_CHECKED,
+ } eTrafficUserData;
+
+ enum {
+ COL_CHECKED,
+ COL_NAME,
+ COL_NUM,
+ COL_PROTOCOL,
+ } eTrafficColumnNames;
+
+ TrafficTypesModel(GList ** recentList, QObject *parent = nullptr);
+
+ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;
+ virtual QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
+ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
+
+ virtual bool setData(const QModelIndex &idx, const QVariant &value, int role) override;
+ virtual Qt::ItemFlags flags (const QModelIndex & idx) const override;
+
+ QList<int> protocols() const;
+
+public slots:
+ void selectProtocols(QList<int> protocols);
+
+signals:
+ void protocolsChanged(QList<int> protocols);
+
+private:
+ QList<TrafficTypesRowData> _allTaps;
+ GList ** _recentList;
+
+};
+
+class TrafficTypesList : public QTreeView
+{
+ Q_OBJECT
+public:
+
+ TrafficTypesList(QWidget *parent = nullptr);
+
+ void setProtocolInfo(QString name, GList ** recentList);
+ QList<int> protocols() const;
+ QList<int> selectedProtocols() const;
+
+public slots:
+ void selectProtocols(QList<int> protocols);
+
+signals:
+ void protocolsChanged(QList<int> protocols);
+
+private:
+ QString _name;
+ TrafficTypesModel * _model;
+};
+
+#endif // TRAFFIC_TYPES_LIST_H \ No newline at end of file