194 lines
4.4 KiB
C++
194 lines
4.4 KiB
C++
/*
|
|
* Copyright 2018 - 2023 gary@drinkingtea.net
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#include <ox/std/assert.hpp>
|
|
#include <ox/std/algorithm.hpp>
|
|
|
|
#include <QHash>
|
|
#include <QJsonArray>
|
|
#include <QSettings>
|
|
|
|
#include "processdata.hpp"
|
|
|
|
static ChId channelIdIt = 0;
|
|
static QHash<QString, ChId> channelToId;
|
|
struct ChannelData {
|
|
QString fullName;
|
|
QString name;
|
|
ChId parent = -1;
|
|
ChannelData(const QString &pFullName, ChId pParent) {
|
|
fullName = pFullName;
|
|
parent = pParent;
|
|
const auto lastSep = fullName.lastIndexOf(ChannelSplitter);
|
|
if (lastSep < 0) {
|
|
name = fullName;
|
|
} else {
|
|
name = fullName.mid(lastSep + ox_strlen(ChannelSplitter));
|
|
}
|
|
}
|
|
};
|
|
static QVector<ChannelData> idToChannel = {{"", -1}};
|
|
|
|
static void addChannel(const QString &ch, ChId parent = -1) {
|
|
const auto chPath = ch.split(ChannelSplitter);
|
|
if (chPath.empty()) {
|
|
return;
|
|
}
|
|
const auto add = [](const QString &c, ChId parent) {
|
|
if (!channelToId.contains(c)) {
|
|
channelToId.emplace(c, ++channelIdIt);
|
|
idToChannel.emplace_back(c, parent);
|
|
}
|
|
return channelToId[c];
|
|
};
|
|
auto current = chPath.first();
|
|
add(current, parent);
|
|
for (auto i = 1; i < chPath.size(); ++i) {
|
|
const auto &segment = chPath[i];
|
|
current += ChannelSplitter + segment;
|
|
parent = add(current, parent);
|
|
}
|
|
}
|
|
|
|
[[nodiscard]]
|
|
const QString &getChannelFullName(ChId id) {
|
|
return idToChannel[id].fullName;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
const QString &getChannelName(ChId id) {
|
|
return idToChannel[id].name;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
ChId getChannelId(const QString &ch) {
|
|
if (!channelToId.contains(ch)) [[unlikely]] {
|
|
addChannel(ch);
|
|
return channelIdIt;
|
|
}
|
|
return channelToId.value(ch);
|
|
}
|
|
|
|
[[nodiscard]]
|
|
ChId getChannelParentId(ChId id) {
|
|
return idToChannel[id].parent;
|
|
}
|
|
|
|
|
|
Channel::Channel(ChId pId, Channel *pParent) {
|
|
id = pId;
|
|
parent = pParent;
|
|
QSettings settings;
|
|
if (!fullName().isEmpty()) {
|
|
settings.beginGroup("Bullock.Channel.Enabled");
|
|
on = settings.value(fullName(), true).toBool();
|
|
settings.endGroup();
|
|
}
|
|
}
|
|
|
|
int Channel::childrenMsgCnt() const noexcept {
|
|
auto out = 0;
|
|
for (const auto &c : children) {
|
|
out += c->msgCnt + c->childrenMsgCnt();
|
|
}
|
|
return out;
|
|
}
|
|
|
|
bool Channel::showMsgs() const noexcept {
|
|
return this->on && (!parent || parent->showMsgs());
|
|
}
|
|
|
|
const QString &Channel::name() const {
|
|
return getChannelName(id);
|
|
}
|
|
|
|
const QString &Channel::fullName() const {
|
|
return getChannelFullName(id);
|
|
}
|
|
|
|
int Channel::row() const noexcept {
|
|
if (!parent) [[unlikely]] {
|
|
return 0;
|
|
}
|
|
for (auto i = 0; const auto &c : parent->children) {
|
|
if (c.get() == this) {
|
|
return i;
|
|
}
|
|
++i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void Channel::setEnabled(bool val) noexcept {
|
|
on = val;
|
|
QSettings settings;
|
|
settings.beginGroup("Bullock.Channel.Enabled");
|
|
settings.setValue(fullName(), val);
|
|
settings.endGroup();
|
|
}
|
|
|
|
[[nodiscard]]
|
|
bool Channel::enabled() const noexcept {
|
|
return (parent == nullptr || parent->enabled()) && on;
|
|
}
|
|
|
|
|
|
Field::Field(const QJsonObject &field) {
|
|
this->name = field["name"].toString();
|
|
this->type = field["type"].toString();
|
|
this->value = field["value"].toString();
|
|
const auto fields = field["fields"].toArray();
|
|
for (const auto &field : fields) {
|
|
this->fields.emplace_back(field.toObject());
|
|
}
|
|
}
|
|
|
|
Frame::Frame(const QJsonObject &frame) {
|
|
this->arch = frame["arch"].toString();
|
|
this->function = frame["function"].toString();
|
|
this->file = frame["file"].toString();
|
|
this->line = frame["line"].toDouble();
|
|
const auto fields = frame["fields"].toArray();
|
|
for (const auto &field : fields) {
|
|
this->fields.emplace_back(field.toObject());
|
|
}
|
|
}
|
|
|
|
|
|
TraceEvent::TraceEvent(const QJsonObject &tp) {
|
|
this->_channel = getChannelId(tp["channel"].toString());
|
|
this->logMsg = tp["log_msg"].toString();
|
|
this->_file = tp["file"].toString();
|
|
this->_line = tp["line"].toInt();
|
|
const auto frames = tp["frames"].toArray();
|
|
for (const auto &frame : frames) {
|
|
this->frames.emplace_back(frame.toObject());
|
|
}
|
|
}
|
|
|
|
TraceEvent::TraceEvent(const ox::trace::TraceMsgRcv &tm) {
|
|
this->_channel = getChannelId(tm.ch.c_str());
|
|
this->logMsg = tm.msg.c_str();
|
|
this->_file = tm.file.c_str();
|
|
this->_line = tm.line;
|
|
this->time = tm.time;
|
|
}
|
|
|
|
const QString &TraceEvent::channel() const noexcept {
|
|
return idToChannel[_channel].fullName;
|
|
}
|
|
|
|
const QString &TraceEvent::file() const noexcept {
|
|
return this->_file;
|
|
}
|
|
|
|
int TraceEvent::line() const noexcept {
|
|
return this->_line;
|
|
}
|
|
|