80 lines
2 KiB
C++
80 lines
2 KiB
C++
|
#include "event_filter.h"
|
||
|
|
||
|
#include <QAbstractItemModel>
|
||
|
#include <QMetaType>
|
||
|
#include <QRegularExpression>
|
||
|
|
||
|
void EventFilter::setFilter(const QString& text)
|
||
|
{
|
||
|
filters.clear();
|
||
|
if (!text.isEmpty()) {
|
||
|
for (const auto &s : text.split(QRegularExpression{"\\s+"})) {
|
||
|
if (const int split = s.indexOf(":"); split == -1)
|
||
|
filters.append({"", s.trimmed()});
|
||
|
else
|
||
|
filters.append({s.left(split).trimmed(), s.mid(split+1).trimmed()});
|
||
|
}
|
||
|
}
|
||
|
invalidateFilter();
|
||
|
}
|
||
|
|
||
|
bool EventFilter::remove(int row)
|
||
|
{
|
||
|
return removeRows(row, 1);
|
||
|
}
|
||
|
|
||
|
// Check if any of the given values match name: value.
|
||
|
static bool matches(const QVariantMap& values, const QString& name, const QString& value)
|
||
|
{
|
||
|
for (auto kv = values.constKeyValueBegin(); kv != values.constKeyValueEnd(); kv++) {
|
||
|
const auto& [fieldName, fieldValue] = *kv;
|
||
|
if (!name.isEmpty() && !fieldName.startsWith(name))
|
||
|
continue;
|
||
|
|
||
|
switch (fieldValue.type()) {
|
||
|
case QMetaType::QString:
|
||
|
// Prepend = to value for exact match.
|
||
|
if (value.startsWith("=")) {
|
||
|
if (fieldValue.toString() == value.mid(1))
|
||
|
return true;
|
||
|
} else {
|
||
|
if (fieldValue.toString().contains(value))
|
||
|
return true;
|
||
|
}
|
||
|
break;
|
||
|
case QMetaType::Bool:
|
||
|
// Prepend ! to value for inverted match.
|
||
|
if (value.startsWith("!")) {
|
||
|
if (fieldName.startsWith(value.mid(1)) && !fieldValue.toBool())
|
||
|
return true;
|
||
|
} else {
|
||
|
if (fieldName.startsWith(value) && fieldValue.toBool())
|
||
|
return true;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool EventFilter::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
|
||
|
{
|
||
|
const auto& model = sourceModel();
|
||
|
const auto& index = model->index(sourceRow, 0, sourceParent);
|
||
|
|
||
|
const auto& roles = model->roleNames();
|
||
|
const auto& tag = model->data(index, roles.key("tag")).toString();
|
||
|
const auto& values = model->data(index, roles.key("values")).toMap();
|
||
|
|
||
|
for (const auto& filter : filters) {
|
||
|
if (filter.first.isEmpty() && tag.startsWith(filter.second))
|
||
|
continue;
|
||
|
if (matches(values, filter.first, filter.second))
|
||
|
continue;
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|