summaryrefslogtreecommitdiff
path: root/event_list.cpp
blob: a1e88a52d9c97e5b69cf0488834a7ca40dd6ef10 (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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include "event_list.h"

#include <QJsonArray>
#include <QJSValue>

Qt::ItemFlags EventList::flags(const QModelIndex&) const
{
	return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren;
}

QHash<int, QByteArray> EventList::roleNames() const
{
	static const QHash<int, QByteArray> roles{
		{Role::Time, "time"},
		{Role::Tag, "tag"},
		{Role::Values, "values"},
	};
	return roles;
}

int EventList::rowCount(const QModelIndex&) const
{
	return events.size();
}

QVariant EventList::data(const QModelIndex& index, int role) const
{
	const auto& event = events[index.row()];
	switch (role) {
	case Role::Time:
		return event.time;
	case Role::Tag:
		return event.tag;
	case Role::Values:
		return event.values;
	default:
		return {};
	}
}

bool EventList::setData(const QModelIndex& index, const QVariant& value, int role)
{
	auto& event = events[index.row()];
	switch (role) {
	case Role::Time:
		event.time = value.toLongLong();
		break;
	case Role::Tag:
		event.tag = value.toString();
		break;
	case Role::Values:
		event.values = value.value<QJSValue>().toVariant().toMap();
		break;
	default:
		return false;
	}
	emit dataChanged(index, index, {role});
	return true;
}

int EventList::insert(const QString& tag, const int time)
{
	int row = time == -1 ? rowCount() : find(time);
	beginInsertRows(QModelIndex{}, row, row);
	events.insert(row, {time, tag});
	endInsertRows();
	return row;
}

bool EventList::removeRows(int row, int count, const QModelIndex&)
{
	beginRemoveRows({}, row, row + count - 1);
	while (row < events.size() && count-- > 0)
		events.removeAt(row);
	endRemoveRows();
	return count == -1;
}

void EventList::load(const QJsonObject& json)
{
	const auto& jsonTags = json["tags"].toArray();
	if (!jsonTags.isEmpty()) {
		tags = {};
		tagsOrder.clear();
		for (int i = 0; i < jsonTags.size(); i++) {
			const auto name = jsonTags[i]["tag"].toString();
			tags[name] = jsonTags[i].toObject();
			tagsOrder.append(name);
		}
		emit tagsChanged();
	}

	const auto& jsonEvents = json["events"].toArray();
	if (!jsonEvents.isEmpty()) {
		beginResetModel();
		events.clear();
		for (int i = 0; i < jsonEvents.size(); i++) {
			auto event = jsonEvents[i].toObject().toVariantMap();
			events.append({
				event["time"].toLongLong(),
				event["tag"].toString(),
				event[event.contains("values") ? "values" : "fields"].toMap(),
			});
		}
		endResetModel();
	}
}

QJsonObject EventList::save() const
{
	QJsonArray jsonEvents;
	for (const auto& event : events) {
		jsonEvents.append(QJsonObject{
			{"time", event.time},
			{"tag", event.tag},
			{"values", QJsonObject::fromVariantMap(event.values)}
		});
	}

	QJsonArray jsonTags;
	for (int i = 0; i < tagsOrder.size(); i++)
		jsonTags.append(tags[tagsOrder[i]].toObject());

	return {{"tags", jsonTags}, {"events", jsonEvents}};
}

// Return the index of the last event not later than given time.
// Assumes events are sorted by time.
int EventList::find(long long time) const
{
	int low = 0;
	int high = events.size() - 1;
	while (low <= high) {
		int mid = (low + high) / 2;
		if (events[mid].time <= time)
			low = mid + 1;
		else
			high = mid - 1;
	}
	return low;
}