291 lines
8.8 KiB
C++
291 lines
8.8 KiB
C++
/* expert_info_model.cpp
|
|
* Data model for Expert Info tap data.
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include <ui/qt/models/expert_info_model.h>
|
|
#include <ui/qt/models/expert_info_proxy_model.h>
|
|
#include <ui/qt/utils/color_utils.h>
|
|
|
|
#include <QRegularExpression>
|
|
|
|
ExpertInfoProxyModel::ExpertInfoProxyModel(QObject *parent) : QSortFilterProxyModel(parent),
|
|
severityMode_(Group)
|
|
{
|
|
}
|
|
|
|
bool ExpertInfoProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
|
|
{
|
|
ExpertPacketItem *left_item,
|
|
*right_item;
|
|
QString leftStr, rightStr;
|
|
bool checkPacketNumber = false;
|
|
int compare_ret;
|
|
|
|
if (source_left.parent().isValid() && source_right.parent().isValid()) {
|
|
left_item = static_cast<ExpertPacketItem*>(source_left.parent().internalPointer());
|
|
right_item = static_cast<ExpertPacketItem*>(source_right.parent().internalPointer());
|
|
} else {
|
|
left_item = static_cast<ExpertPacketItem*>(source_left.internalPointer());
|
|
right_item = static_cast<ExpertPacketItem*>(source_right.internalPointer());
|
|
}
|
|
|
|
if ((left_item != NULL) && (right_item != NULL)) {
|
|
switch (source_left.column())
|
|
{
|
|
case colProxySeverity:
|
|
if (left_item->severity() != right_item->severity()) {
|
|
return (left_item->severity() < right_item->severity());
|
|
}
|
|
|
|
checkPacketNumber = true;
|
|
break;
|
|
case colProxySummary:
|
|
compare_ret = left_item->summary().compare(right_item->summary());
|
|
if (compare_ret < 0)
|
|
return true;
|
|
if (compare_ret > 0)
|
|
return false;
|
|
|
|
checkPacketNumber = true;
|
|
break;
|
|
case colProxyGroup:
|
|
if (left_item->group() != right_item->group()) {
|
|
return (left_item->group() < right_item->group());
|
|
}
|
|
|
|
checkPacketNumber = true;
|
|
break;
|
|
case colProxyProtocol:
|
|
compare_ret = left_item->protocol().compare(right_item->protocol());
|
|
if (compare_ret < 0)
|
|
return true;
|
|
if (compare_ret > 0)
|
|
return false;
|
|
|
|
checkPacketNumber = true;
|
|
break;
|
|
case colProxyCount:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (checkPacketNumber) {
|
|
return (left_item->packetNum() < right_item->packetNum());
|
|
}
|
|
}
|
|
|
|
// fallback to string cmp on other fields
|
|
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
|
}
|
|
|
|
QVariant ExpertInfoProxyModel::data(const QModelIndex &proxy_index, int role) const
|
|
{
|
|
QModelIndex source_index;
|
|
|
|
switch (role)
|
|
{
|
|
case Qt::BackgroundRole:
|
|
{
|
|
source_index = mapToSource(proxy_index);
|
|
|
|
// only color base row
|
|
if (!source_index.isValid() || source_index.parent().isValid())
|
|
return QVariant();
|
|
|
|
ExpertPacketItem* item = static_cast<ExpertPacketItem*>(source_index.internalPointer());
|
|
if (item == NULL)
|
|
return QVariant();
|
|
|
|
// provide background color for groups
|
|
switch(item->severity()) {
|
|
case(PI_COMMENT):
|
|
return QBrush(ColorUtils::expert_color_comment);
|
|
case(PI_CHAT):
|
|
return QBrush(ColorUtils::expert_color_chat);
|
|
case(PI_NOTE):
|
|
return QBrush(ColorUtils::expert_color_note);
|
|
case(PI_WARN):
|
|
return QBrush(ColorUtils::expert_color_warn);
|
|
case(PI_ERROR):
|
|
return QBrush(ColorUtils::expert_color_error);
|
|
}
|
|
}
|
|
break;
|
|
case Qt::ForegroundRole:
|
|
{
|
|
source_index = mapToSource(proxy_index);
|
|
|
|
// only color base row
|
|
if (!source_index.isValid() || source_index.parent().isValid())
|
|
return QVariant();
|
|
|
|
ExpertPacketItem* item = static_cast<ExpertPacketItem*>(source_index.internalPointer());
|
|
if (item == NULL)
|
|
return QVariant();
|
|
|
|
// provide foreground color for groups
|
|
switch(item->severity()) {
|
|
case(PI_COMMENT):
|
|
case(PI_CHAT):
|
|
case(PI_NOTE):
|
|
case(PI_WARN):
|
|
case(PI_ERROR):
|
|
return QBrush(ColorUtils::expert_color_foreground);
|
|
}
|
|
}
|
|
break;
|
|
case Qt::TextAlignmentRole:
|
|
switch (proxy_index.column())
|
|
{
|
|
case colProxySeverity:
|
|
//packet number should be right aligned
|
|
if (source_index.parent().isValid())
|
|
return Qt::AlignRight;
|
|
break;
|
|
case colProxyCount:
|
|
return Qt::AlignRight;
|
|
default:
|
|
break;
|
|
}
|
|
return Qt::AlignLeft;
|
|
|
|
case Qt::DisplayRole:
|
|
source_index = mapToSource(proxy_index);
|
|
|
|
switch (proxy_index.column())
|
|
{
|
|
case colProxySeverity:
|
|
if (source_index.parent().isValid())
|
|
return sourceModel()->data(source_index.sibling(source_index.row(), ExpertInfoModel::colPacket), role);
|
|
|
|
return sourceModel()->data(source_index.sibling(source_index.row(), ExpertInfoModel::colSeverity), role);
|
|
case colProxySummary:
|
|
return sourceModel()->data(source_index.sibling(source_index.row(), ExpertInfoModel::colSummary), role);
|
|
case colProxyGroup:
|
|
return sourceModel()->data(source_index.sibling(source_index.row(), ExpertInfoModel::colGroup), role);
|
|
case colProxyProtocol:
|
|
return sourceModel()->data(source_index.sibling(source_index.row(), ExpertInfoModel::colProtocol), role);
|
|
case colProxyCount:
|
|
//only show counts for parent
|
|
if (!source_index.parent().isValid()) {
|
|
//because of potential filtering, count is computed manually
|
|
unsigned int count = 0;
|
|
ExpertPacketItem *child_item,
|
|
*item = static_cast<ExpertPacketItem*>(source_index.internalPointer());
|
|
for (int row = 0; row < item->childCount(); row++) {
|
|
child_item = item->child(row);
|
|
if (child_item == NULL)
|
|
continue;
|
|
if (filterAcceptItem(*child_item))
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return QSortFilterProxyModel::data(proxy_index, role);
|
|
}
|
|
|
|
QVariant ExpertInfoProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
{
|
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
|
|
|
switch ((enum ExpertProxyColumn)section) {
|
|
case colProxySeverity:
|
|
if (severityMode_ == Packet)
|
|
return tr("Packet");
|
|
else
|
|
return tr("Severity");
|
|
case colProxySummary:
|
|
return tr("Summary");
|
|
case colProxyGroup:
|
|
return tr("Group");
|
|
case colProxyProtocol:
|
|
return tr("Protocol");
|
|
case colProxyCount:
|
|
return tr("Count");
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return QVariant();
|
|
}
|
|
|
|
int ExpertInfoProxyModel::columnCount(const QModelIndex&) const
|
|
{
|
|
return colProxyLast;
|
|
}
|
|
|
|
bool ExpertInfoProxyModel::filterAcceptItem(ExpertPacketItem& item) const
|
|
{
|
|
if (hidden_severities_.contains(item.severity()))
|
|
return false;
|
|
|
|
if (!textFilter_.isEmpty()) {
|
|
QRegularExpression regex(textFilter_, QRegularExpression::CaseInsensitiveOption |
|
|
QRegularExpression::UseUnicodePropertiesOption);
|
|
if (! regex.isValid())
|
|
return false;
|
|
|
|
if (item.protocol().contains(regex))
|
|
return true;
|
|
|
|
if (item.summary().contains(regex))
|
|
return true;
|
|
|
|
if (item.colInfo().contains(regex))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ExpertInfoProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
|
{
|
|
QModelIndex severityIdx = sourceModel()->index(sourceRow, ExpertInfoModel::colSeverity, sourceParent);
|
|
ExpertPacketItem* item = static_cast<ExpertPacketItem*>(severityIdx.internalPointer());
|
|
if (item == NULL)
|
|
return true;
|
|
|
|
return filterAcceptItem(*item);
|
|
}
|
|
|
|
//GUI helpers
|
|
void ExpertInfoProxyModel::setSeverityMode(enum SeverityMode mode)
|
|
{
|
|
severityMode_ = mode;
|
|
emit headerDataChanged(Qt::Vertical, 0, 1);
|
|
}
|
|
|
|
void ExpertInfoProxyModel::setSeverityFilter(int severity, bool hide)
|
|
{
|
|
if (hide)
|
|
{
|
|
hidden_severities_ << severity;
|
|
}
|
|
else
|
|
{
|
|
hidden_severities_.removeOne(severity);
|
|
}
|
|
|
|
invalidateFilter();
|
|
}
|
|
|
|
void ExpertInfoProxyModel::setSummaryFilter(const QString &filter)
|
|
{
|
|
textFilter_ = filter;
|
|
invalidateFilter();
|
|
}
|