diff --git a/.gitignore b/.gitignore index 1b823a2..1dcc061 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ dist build +Session.vim diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0dc8372..2cd9534 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,7 +10,7 @@ add_executable( main.cpp mainwindow.cpp processdata.cpp - procselector.cpp + processselector.cpp server.cpp traceeventmodel.cpp traceview.cpp diff --git a/src/main.cpp b/src/main.cpp index bde818c..2f7e2b3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,11 +13,13 @@ int main(int argc, char **args) { QApplication app(argc, args); + app.setApplicationName("Bullock"); + app.setOrganizationName("DrinkingTea"); + app.setOrganizationDomain("drinkingtea.net"); LogServer server; MainWindow w; - app.setApplicationName(w.windowTitle()); w.show(); QObject::connect(&server, &LogServer::newDataFeed, &w, &MainWindow::addDataFeed); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 4a69c8c..adda935 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -14,8 +14,6 @@ #include #include -#include "traceview.hpp" - #include "mainwindow.hpp" MainWindow::MainWindow() { @@ -33,10 +31,12 @@ MainWindow::MainWindow() { auto leftPane = new QWidget(this); auto leftPaneSplitter = new QSplitter(Qt::Vertical, leftPane); m_procSelector = new ProcessSelector(leftPaneSplitter); + connect(m_procSelector, &ProcessSelector::selectionChanged, this, &MainWindow::setProcess); leftPaneSplitter->addWidget(m_procSelector); splitter->addWidget(leftPaneSplitter); - splitter->addWidget(new TraceView(splitter)); + m_traceView = new TraceView(splitter); + splitter->addWidget(m_traceView); splitter->setStretchFactor(1, 3); setCentralWidget(splitter); @@ -47,9 +47,19 @@ MainWindow::~MainWindow() { } void MainWindow::addDataFeed(DataFeed *feed) { - m_procData.push_back(feed->procData()); auto time = QDateTime::currentDateTime(); - m_procSelector->addProcess(time.toString()); + auto procKey = time.toString(); + m_procData[procKey] = feed->procData(); + m_procSelector->addProcess(procKey); +} + +void MainWindow::setProcess(QString procKey) { + if (m_procData.contains(procKey)) { + m_currentProc = m_procData[procKey].data(); + } else { + m_currentProc = nullptr; + } + m_traceView->setProcessData(m_currentProc); } void MainWindow::setupMenu() { diff --git a/src/mainwindow.hpp b/src/mainwindow.hpp index abb1f4a..73bbe0a 100644 --- a/src/mainwindow.hpp +++ b/src/mainwindow.hpp @@ -8,15 +8,19 @@ #include -#include "procselector.hpp" +#include "processselector.hpp" +#include "traceview.hpp" + #include "server.hpp" class MainWindow: public QMainWindow { Q_OBJECT private: - QVector> m_procData; + QHash> m_procData; + ProcessData *m_currentProc = nullptr; ProcessSelector *m_procSelector = nullptr; + TraceView *m_traceView = nullptr; public: MainWindow(); @@ -26,6 +30,9 @@ class MainWindow: public QMainWindow { public slots: void addDataFeed(DataFeed*); + private slots: + void setProcess(QString procKey); + private: void setupMenu(); diff --git a/src/processdata.cpp b/src/processdata.cpp index 18f17c9..8865bfd 100644 --- a/src/processdata.cpp +++ b/src/processdata.cpp @@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include #include #include "processdata.hpp" @@ -31,10 +32,19 @@ Frame::Frame(QJsonObject frame) { } TraceEvent::TraceEvent(QJsonObject tp) { - this->logMsg = tp["trace_msg"].toString(); + this->channel = tp["channel"].toString(); + this->logMsg = tp["log_msg"].toString(); auto frames = tp["frames"].toArray(); for (auto frame : frames) { this->frames.push_back(frame.toObject()); } } +QString TraceEvent::file() const { + return this->frames[0].file; +} + +int TraceEvent::line() const { + return this->frames[0].line; +} + diff --git a/src/processdata.hpp b/src/processdata.hpp index 0328e00..7bc0649 100644 --- a/src/processdata.hpp +++ b/src/processdata.hpp @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include @@ -39,9 +40,22 @@ struct TraceEvent { TraceEvent(QJsonObject tp = {}); + QString file() const; + + int line() const; + }; -struct ProcessData { - QString cmd; - QVector traceEvents; +struct ProcessData: public QObject { + Q_OBJECT + + public: + QString cmd; + QVector traceEvents; + + signals: + /** + * Emitted whenever a new TraceEvent is added. + */ + void traceEvent(const TraceEvent&); }; diff --git a/src/processselector.cpp b/src/processselector.cpp new file mode 100644 index 0000000..cd4b12b --- /dev/null +++ b/src/processselector.cpp @@ -0,0 +1,35 @@ +/* + * Copyright 2018 gtalent2@gmail.com + * + * 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 +#include +#include + +#include "processselector.hpp" + +ProcessSelector::ProcessSelector(QWidget *parent): QWidget(parent) { + const auto MostRecent = tr("Most Recent"); + auto lyt = new QVBoxLayout(this); + lyt->addWidget(new QLabel(tr("Processes"), this)); + lyt->addWidget(m_list); + m_list->addItem(MostRecent); + m_list->setCurrentRow(RowLatest); + connect(m_list, &QListWidget::currentTextChanged, [this, MostRecent](QString txt) { + if (txt == MostRecent && m_list->count() > 1) { + txt = m_list->item(1)->text(); + } + emit this->selectionChanged(txt); + }); +} + +void ProcessSelector::addProcess(QString procKey) { + m_list->insertItem(1, procKey); + if (m_list->currentRow() == RowLatest) { + emit selectionChanged(procKey); + } +} diff --git a/src/procselector.hpp b/src/processselector.hpp similarity index 100% rename from src/procselector.hpp rename to src/processselector.hpp diff --git a/src/procselector.cpp b/src/procselector.cpp deleted file mode 100644 index b452c00..0000000 --- a/src/procselector.cpp +++ /dev/null @@ -1,20 +0,0 @@ - -#include -#include - -#include "procselector.hpp" - -ProcessSelector::ProcessSelector(QWidget *parent): QWidget(parent) { - auto lyt = new QVBoxLayout(this); - lyt->addWidget(new QLabel(tr("Processes"), this)); - lyt->addWidget(m_list); - m_list->addItem(tr("Most Recent")); - m_list->setCurrentRow(RowLatest); -} - -void ProcessSelector::addProcess(QString procKey) { - m_list->insertItem(1, procKey); - if (m_list->currentRow() == RowLatest) { - emit selectionChanged(procKey); - } -} diff --git a/src/server.cpp b/src/server.cpp index ec22421..5261cf2 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -32,9 +32,14 @@ void DataFeed::handleInit() { void DataFeed::read() { while (m_dev->bytesAvailable()) { - auto doc = QJsonDocument::fromJson(m_dev->readLine()); + const auto doc = QJsonDocument::fromJson(m_dev->readLine()); if (m_procData) { - m_procData->traceEvents.push_back(doc.object()); + const auto msg = doc.object(); + if (msg["type"] == "TraceEvent") { + const auto te = msg["data"].toObject(); + m_procData->traceEvents.push_back(te); + emit m_procData->traceEvent(m_procData->traceEvents.last()); + } } } } diff --git a/src/traceeventmodel.cpp b/src/traceeventmodel.cpp index e572bba..25d78b7 100644 --- a/src/traceeventmodel.cpp +++ b/src/traceeventmodel.cpp @@ -6,20 +6,83 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include + #include "traceeventmodel.hpp" int TraceEventModel::rowCount(const QModelIndex &parent) const { - if (m_procData) { - return m_procData->traceEvents.size(); - } else { - return 0; - } + return m_traceEvents.size(); } int TraceEventModel::columnCount(const QModelIndex &parent) const { return Column::End; } -QVariant TraceEventModel::data(const QModelIndex &index, int role) const { - return {}; +QVariant TraceEventModel::headerData(int section, Qt::Orientation orientation, int role) const { + if (role != Qt::DisplayRole) { + return QVariant(); + } + + if (orientation == Qt::Horizontal) { + switch (section) { + case Column::Channel: + return tr("Channel"); + case Column::Source: + return tr("Source"); + case Column::Message: + return tr("Message"); + default: + return QVariant(); + } + } + return QVariant(); +} + +QVariant TraceEventModel::data(const QModelIndex &index, int role) const { + if (!index.isValid()) { + return QVariant(); + } + + if (index.row() >= m_traceEvents.size() || index.row() < 0) { + return QVariant(); + } + + if (role == Qt::DisplayRole) { + const auto &te = m_traceEvents[index.row()]; + + switch (index.column()) { + case Column::Channel: + return te.channel; + case Column::Source: + return QString("%1:%2").arg(te.file()).arg(te.line()); + case Column::Message: + return te.logMsg; + default: + return {}; + } + } + return QVariant(); +} + +void TraceEventModel::setProcessData(ProcessData *data) { + beginResetModel(); + m_traceEvents.clear(); + if (m_procData) { + disconnect(m_procData, &ProcessData::traceEvent, this, &TraceEventModel::addEvent); + } + m_procData = data; + if (m_procData) { + for (const auto &te : m_procData->traceEvents) { + m_traceEvents.push_back(te); + } + connect(m_procData, &ProcessData::traceEvent, this, &TraceEventModel::addEvent); + } + endResetModel(); +} + +void TraceEventModel::addEvent(const TraceEvent &event) { + auto index = m_traceEvents.size(); + beginInsertRows(QModelIndex(), index, index); + m_traceEvents.push_back(event); + endInsertRows(); } diff --git a/src/traceeventmodel.hpp b/src/traceeventmodel.hpp index 046f11b..f52859c 100644 --- a/src/traceeventmodel.hpp +++ b/src/traceeventmodel.hpp @@ -10,19 +10,22 @@ #include "processdata.hpp" -#include +#include -class TraceEventModel: public QAbstractItemModel { +class TraceEventModel: public QAbstractTableModel { Q_OBJECT - private: + public: enum Column { - Channel, + Channel = 0, + Source, Message, End }; + private: + QVector m_traceEvents; ProcessData *m_procData = nullptr; public: @@ -30,5 +33,12 @@ class TraceEventModel: public QAbstractItemModel { int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + void setProcessData(ProcessData *data); + + public slots: + void addEvent(const TraceEvent &event); }; diff --git a/src/traceview.cpp b/src/traceview.cpp index 77d0838..b0b9bf3 100644 --- a/src/traceview.cpp +++ b/src/traceview.cpp @@ -6,13 +6,46 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include #include -#include +#include +#include #include "traceview.hpp" TraceView::TraceView(QWidget *parent): QWidget(parent) { auto lyt = new QHBoxLayout; setLayout(lyt); - lyt->addWidget(new QTableView(this)); + m_eventTable = new QTableView(this); + m_model = new TraceEventModel; + m_eventTable->setModel(m_model); + m_eventTable->horizontalHeader()->setStretchLastSection(true); + m_eventTable->verticalHeader()->hide(); + m_eventTable->setSelectionBehavior(QAbstractItemView::SelectRows); + lyt->addWidget(m_eventTable); + readState(); +} + +TraceView::~TraceView() { + writeState(); +} + +void TraceView::readState() { + QSettings settings; + settings.beginGroup("TraceView"); + m_eventTable->horizontalHeader()->restoreState(settings.value("eventTableState").toByteArray()); + m_eventTable->horizontalHeader()->restoreGeometry(settings.value("eventTableGeometry").toByteArray()); + settings.endGroup(); +} + +void TraceView::writeState() { + QSettings settings; + settings.beginGroup("TraceView"); + settings.setValue("eventTableState", m_eventTable->horizontalHeader()->saveState()); + settings.setValue("eventTableGeometry", m_eventTable->horizontalHeader()->saveGeometry()); + settings.endGroup(); +} + +void TraceView::setProcessData(ProcessData *data) { + m_model->setProcessData(data); } diff --git a/src/traceview.hpp b/src/traceview.hpp index 336b913..bf2a346 100644 --- a/src/traceview.hpp +++ b/src/traceview.hpp @@ -8,12 +8,30 @@ #pragma once +#include #include +#include "traceeventmodel.hpp" + +#include "processdata.hpp" + class TraceView: public QWidget { Q_OBJECT + private: + QTableView *m_eventTable; + TraceEventModel *m_model = nullptr; + public: TraceView(QWidget *parent = nullptr); + ~TraceView(); + + void setProcessData(ProcessData *data); + + private: + void readState(); + + void writeState(); + };