81 lines
2.1 KiB
C++
81 lines
2.1 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+"})) {
|
|
const int split = s.indexOf(":");
|
|
if (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 = kv->first;
|
|
const auto& fieldValue = kv->second;
|
|
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;
|
|
}
|