forked from osmocom/wireshark
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.
This commit is contained in:
parent
f1cbc6b662
commit
a4f25e5115
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="nameResolutionCheckBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Show resolved addresses and port names rather than plain values. The corresponding name resolution preference must be enabled.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Name resolution</string>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>210</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</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><html><head/><body><p>Show resolved addresses and port names rather than plain values. The corresponding name resolution preference must be enabled.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Name resolution</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="absoluteTimeCheckBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Show absolute times in the start time column.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Absolute start time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="displayFilterCheckBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Only show conversations matching the current display filter</p></body></html></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_2">
|
||||
<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="displayFilterCheckBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Only show conversations matching the current display filter</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Limit to display filter</string>
|
||||
</property>
|
||||
</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><html><head/><body><p>Show absolute times in the start time column.</p></body></html></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>
|
||||
|
|
|
@ -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();
|
||||
QList<int> tabs = _tabs.keys();
|
||||
QList<int> remove;
|
||||
blockSignals(true);
|
||||
|
||||
/* 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++;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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, protocols)
|
||||
{
|
||||
if ( _protocols.contains(key)) {
|
||||
_protocolButtons[key]->setChecked(true);
|
||||
keys.removeAll(key);
|
||||
}
|
||||
}
|
||||
/* 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 (! tabs.contains(protocol)) {
|
||||
insertProtoTab(protocol, false);
|
||||
}
|
||||
tabs.removeAll(protocol);
|
||||
}
|
||||
|
||||
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())
|
||||
{
|
||||
_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();
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue