summaryrefslogtreecommitdiff
path: root/event_filter.cpp
blob: 68aa702c0f1c5d50f1112dddd14cabb88a9d37fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#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;
}