Qt: Adapt sorting for traffic tables

Improve sorting for the traffic tables
This commit is contained in:
Roland Knall 2022-06-12 13:48:05 +02:00
parent 58ee7bf6ee
commit a807047b95
5 changed files with 87 additions and 24 deletions

View File

@ -357,7 +357,7 @@ WS_DLL_PUBLIC void conversation_set_port2(conversation_t *conv, const guint32 po
/**
* Set the second address in a conversation created with conversation_new.
* @param conv Conversation. Must be created with conversation_new.
* @param port The second address to set.
* @param addr The second address to set.
*/
WS_DLL_PUBLIC void conversation_set_addr2(conversation_t *conv, const address *addr);

View File

@ -15,7 +15,6 @@
#include <epan/maxmind_db.h>
#include <epan/addr_resolv.h>
#include <wsutil/str_util.h>
#include <wsutil/utf8_entities.h>
#include <wsutil/nstime.h>
@ -32,7 +31,7 @@
static QString formatString(qlonglong value)
{
return gchar_free_to_qstring(format_size(value, FORMAT_SIZE_UNIT_NONE, FORMAT_SIZE_PREFIX_SI));
return QLocale::system().formattedDataSize(value, QLocale::DataSizeSIFormat);
}
ATapDataModel::ATapDataModel(dataModelType type, int protoId, QString filter, QObject *parent):
@ -435,17 +434,17 @@ QVariant EndpointDataModel::data(const QModelIndex &idx, int role) const
case ENDP_COLUMN_PACKETS:
{
qlonglong packets = (qlonglong)(item->tx_frames + item->rx_frames);
return packets;
return role == Qt::DisplayRole ? formatString(packets) : (QVariant)packets;
}
case ENDP_COLUMN_BYTES:
return role == Qt::DisplayRole ? formatString((qlonglong)(item->tx_bytes + item->rx_bytes)) :
QVariant((qlonglong)(item->tx_bytes + item->rx_bytes));
case ENDP_COLUMN_PKT_AB:
return (qlonglong)item->tx_frames;
return role == Qt::DisplayRole ? formatString((qlonglong)item->tx_frames) : QVariant((qlonglong) item->tx_frames);
case ENDP_COLUMN_BYTES_AB:
return role == Qt::DisplayRole ? formatString((qlonglong)item->tx_bytes) : QVariant((qlonglong)item->tx_bytes);
case ENDP_COLUMN_PKT_BA:
return (qlonglong)item->rx_frames;
return role == Qt::DisplayRole ? formatString((qlonglong)item->rx_frames) : QVariant((qlonglong) item->rx_frames);
case ENDP_COLUMN_BYTES_BA:
return role == Qt::DisplayRole ? formatString((qlonglong)item->rx_bytes) : QVariant((qlonglong)item->rx_bytes);
case ENDP_COLUMN_GEO_COUNTRY:
@ -470,19 +469,21 @@ QVariant EndpointDataModel::data(const QModelIndex &idx, int role) const
return QVariant();
case 12:
{
qlonglong packets = 0;
if (showTotalColumn())
return (qlonglong)(item->tx_frames_total + item->rx_frames_total);
return QVariant();
packets = item->tx_frames_total + item->rx_frames_total;
return role == Qt::DisplayRole ? QString("%L1").arg(packets) : (QVariant)packets;
}
case 13:
{
double percent = 0;
if (showTotalColumn()) {
qlonglong totalPackets = (qlonglong)(item->tx_frames_total + item->rx_frames_total);
qlonglong packets = (qlonglong)(item->tx_frames + item->rx_frames);
double percent = totalPackets == 0 ? 0 : packets * 100 / totalPackets;
percent = totalPackets == 0 ? 0 : (double) packets * 100 / (double) totalPackets;
return QString::number(percent, 'f', 2) + "%";
}
return QVariant();
return role == Qt::DisplayRole ? QString::number(percent, 'f', 2) + "%" : (QVariant)percent;
}
default:
return QVariant();
@ -687,16 +688,25 @@ QVariant ConversationDataModel::data(const QModelIndex &idx, int role) const
return quint32(conv_item->dst_port);
}
case CONV_COLUMN_PACKETS:
return QString("%L1").arg(conv_item->tx_frames + conv_item->rx_frames);
{
qlonglong packets = conv_item->tx_frames + conv_item->rx_frames;
return role == Qt::DisplayRole ? QString("%L1").arg(packets) : (QVariant)packets;
}
case CONV_COLUMN_BYTES:
return role == Qt::DisplayRole ? formatString((qlonglong)conv_item->tx_bytes + conv_item->rx_bytes) :
QVariant((qlonglong)conv_item->tx_bytes + conv_item->rx_bytes);
case CONV_COLUMN_PKT_AB:
return QString("%L1").arg(conv_item->tx_frames);
{
qlonglong packets = conv_item->tx_frames;
return role == Qt::DisplayRole ? QString("%L1").arg(packets) : (QVariant)packets;
}
case CONV_COLUMN_BYTES_AB:
return role == Qt::DisplayRole ? formatString((qlonglong)conv_item->tx_bytes) : QVariant((qlonglong)conv_item->tx_bytes);
case CONV_COLUMN_PKT_BA:
return QString("%L1").arg(conv_item->rx_frames);
{
qlonglong packets = conv_item->rx_frames;
return role == Qt::DisplayRole ? QString("%L1").arg(packets) : (QVariant)packets;
}
case CONV_COLUMN_BYTES_BA:
return role == Qt::DisplayRole ? formatString((qlonglong)conv_item->rx_bytes) : QVariant((qlonglong)conv_item->rx_bytes);
case CONV_COLUMN_START:
@ -706,18 +716,17 @@ QVariant ConversationDataModel::data(const QModelIndex &idx, int role) const
if (_absoluteTime) {
nstime_t *abs_time = &conv_item->start_abs_time;
QDateTime abs_dt = QDateTime::fromMSecsSinceEpoch(nstime_to_msec(abs_time));
return QString("%1.%2")
// Mimic column-utils:set_abs_time as best we can
.arg(abs_dt.toString("hh:mm:ss"))
.arg(_nanoseconds ? abs_time->nsecs : abs_time->nsecs / 1000, width, 10, QChar('0'));
return role == Qt::DisplayRole ? abs_dt.toString("hh:mm:ss.zzzz") : (QVariant)abs_dt;
} else {
return QString::number(nstime_to_sec(&conv_item->start_time), 'f', width);
return role == Qt::DisplayRole ?
QString::number(nstime_to_sec(&conv_item->start_time), 'f', width) :
(QVariant)((double) nstime_to_sec(&conv_item->start_time));
}
}
case CONV_COLUMN_DURATION:
{
int width = _nanoseconds ? 6 : 4;
return QString::number(duration, 'f', width);
return role == Qt::DisplayRole ? QString::number(duration, 'f', width) : (QVariant)duration;
}
case CONV_COLUMN_BPS_AB:
return bpsCalculated ? (role == Qt::DisplayRole ? formatString(bps_ab) : QVariant((qlonglong)bps_ab)): QVariant();
@ -725,19 +734,21 @@ QVariant ConversationDataModel::data(const QModelIndex &idx, int role) const
return bpsCalculated ? (role == Qt::DisplayRole ? formatString(bps_ba) : QVariant((qlonglong)bps_ba)): QVariant();
case 14:
{
qlonglong packets = 0;
if (showTotalColumn())
return (qlonglong)(conv_item->tx_frames_total + conv_item->rx_frames_total);
return (qlonglong) 0;
packets = conv_item->tx_frames_total + conv_item->rx_frames_total;
return role == Qt::DisplayRole ? QString("%L1").arg(packets) : (QVariant)packets;
}
case 15:
{
double percent = 0;
if (showTotalColumn()) {
qlonglong totalPackets = (qlonglong)(conv_item->tx_frames_total + conv_item->rx_frames_total);
qlonglong packets = (qlonglong)(conv_item->tx_frames + conv_item->rx_frames);
double percent = totalPackets == 0 ? 0 : packets * 100 / totalPackets;
return QString::number(percent, 'f', 2) + "%";
percent = totalPackets == 0 ? 0 : (double) packets * 100 / (double) totalPackets;
}
return (qlonglong) 0;
return role == Qt::DisplayRole ? QString::number(percent, 'f', 2) + "%" : (QVariant)percent;
}
}
} else if (role == Qt::ToolTipRole) {

View File

@ -45,6 +45,7 @@
#include <QUrl>
#include <QTemporaryFile>
#include <QHBoxLayout>
#include <QRegularExpressionMatch>
TabData::TabData() :
_name(QString()),
@ -83,6 +84,54 @@ bool TrafficDataFilterProxy::filterAcceptsRow(int source_row, const QModelIndex
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
}
bool TrafficDataFilterProxy::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
if (! source_left.isValid() || ! qobject_cast<const ATapDataModel *>(source_left.model()))
return false;
if (! source_right.isValid() || ! qobject_cast<const ATapDataModel *>(source_right.model()))
return false;
QVariant datA = source_left.data(ATapDataModel::UNFORMATTED_DISPLAYDATA);
QVariant datB = source_right.data(ATapDataModel::UNFORMATTED_DISPLAYDATA);
QString strA = datA.toString().toLower();
QString strB = datB.toString().toLower();
QRegularExpression re = QRegularExpression(QString("[a-f\\d]{2}:[a-f\\d]{2}:[a-f\\d]{2}:[a-f\\d]{2}:[a-f\\d]{2}:[a-f\\d]{2}"));
QRegularExpressionMatch match = re.match(strA);
if (match.hasMatch())
return strA < strB;
QRegularExpression reIp("(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})");
match = reIp.match(strA);
QRegularExpressionMatch matchB = reIp.match(strB);
QStringList listA = strA.split('.');
QStringList listB = strB.split('.');
if (match.hasMatch() && listA.count() == 4 && ! matchB.hasMatch())
return true;
else if (match.hasMatch() && listA.count() == 4 && matchB.hasMatch() && listB.count() == 4 ) {
quint32 ipA = (listA.at(0).toInt() << 24) + (listA.at(1).toInt() << 16) + (listA.at(2).toInt() << 8) + listA.at(3).toInt();
quint32 ipB = (listB.at(0).toInt() << 24) + (listB.at(1).toInt() << 16) + (listB.at(2).toInt() << 8) + listB.at(3).toInt();
return ipA < ipB;
}
QString iPv6Pattern("(([\\da-f]{1,4}:){7,7}[\\da-f]{1,4}|([\\da-f]{1,4}:){1,7}:|([\\da-f]{1,4}:){1,6}:[\\da-f]{1,4}|"
"([\\da-f]{1,4}:){1,5}(:[\\da-f]{1,4}){1,2}|([\\da-f]{1,4}:){1,4}(:[\\da-f]{1,4}){1,3}|([\\da-f]{1,4}:){1,3}(:"
"[\\da-f]{1,4}){1,4}|([\\da-f]{1,4}:){1,2}(:[\\da-f]{1,4}){1,5}|[\\da-f]{1,4}:((:[\\da-f]{1,4}){1,6})|:((:[\\da"
"-f]{1,4}){1,7}|:)|fe80:(:[\\da-f]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}"
"\\d){0,1}\\d)\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}\\d){0,1}\\d)|([\\da-f]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}\\d){0,1}"
"\\d)\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}\\d){0,1}\\d))");
QRegularExpression reIPv6(iPv6Pattern);
match = reIPv6.match(strA);
if (match.hasMatch())
return strA < strB;
if (datA.canConvert<double>() && datB.canConvert<double>())
return datA.toDouble() < datB.toDouble();
return QSortFilterProxyModel::lessThan(source_left, source_right);
}
static gboolean iterateProtocols(const void *key, void *value, void *userdata)
{

View File

@ -71,6 +71,7 @@ public:
protected:
virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
virtual bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const;
};

View File

@ -15,9 +15,11 @@
#include <wsutil/utf8_entities.h>
#include <wsutil/filesystem.h>
#include <wsutil/str_util.h>
#include "ui/recent.h"
#include <ui/qt/utils/qt_ui_utils.h>
#include <ui/qt/main_application.h>
#include <ui/qt/main_window.h>
#include <ui/qt/filter_action.h>