From 8761ac364a5361a75a03fdcc0bb780764aa99e86 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Mon, 1 May 2023 14:27:13 +0200 Subject: [PATCH] More EventsModel into its own file. --- events.cpp | 140 +++++++++++++++++++++++++++++++++++++++++++ events.h | 51 ++++++++++++++++ meson.build | 2 +- stats.cpp | 170 +--------------------------------------------------- 4 files changed, 193 insertions(+), 170 deletions(-) create mode 100644 events.cpp create mode 100644 events.h diff --git a/events.cpp b/events.cpp new file mode 100644 index 0000000..a08f1c7 --- /dev/null +++ b/events.cpp @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include "events.h" + +using namespace std; + +string format_timestamp(uint64_t pos); + +QVariant EventsModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) { + return QVariant(); + } + if (orientation == Qt::Horizontal) { + if (section == 0) { + return "Time"; + } else if (section == 1) { + return "Player"; + } else { + return "Type"; + } + } else { + return ""; + } +} + +QVariant EventsModel::data(const QModelIndex &index, int role) const +{ + if (role != Qt::DisplayRole) { + return QVariant(); + } + refresh_if_needed(); + if (index.column() == 0) { + return QString::fromUtf8(format_timestamp(events[index.row()].t)); + } else if (index.column() == 1) { + optional player_id = events[index.row()].player_id; + if (player_id) { + const Player &p = players[*player_id]; + return QString::fromUtf8(p.name + " (" + p.number + ")"); + } else { + return QVariant(); + } + } else if (index.column() == 2) { + return QString::fromUtf8(events[index.row()].type); + } + return QVariant(); +} + +void EventsModel::refresh_if_needed() const +{ + if (!stale) { + return; + } + + players.clear(); + events.clear(); + stale = false; + + // Read the players. + sqlite3_stmt *stmt; + int ret = sqlite3_prepare_v2(db, "SELECT player, number, name FROM player", -1, &stmt, 0); + if (ret != SQLITE_OK) { + fprintf(stderr, "SELECT prepare: %s\n", sqlite3_errmsg(db)); + abort(); + } + for ( ;; ) { + ret = sqlite3_step(stmt); + if (ret == SQLITE_ROW) { + Player p; + p.player_id = sqlite3_column_int(stmt, 0); + p.number = (const char *)sqlite3_column_text(stmt, 1); + p.name = (const char *) sqlite3_column_text(stmt, 2); + players[p.player_id] = std::move(p); + } else if (ret == SQLITE_DONE) { + break; + } else { + fprintf(stderr, "SELECT step: %s\n", sqlite3_errmsg(db)); + abort(); + } + } + ret = sqlite3_finalize(stmt); + if (ret != SQLITE_OK) { + fprintf(stderr, "SELECT finalize: %s\n", sqlite3_errmsg(db)); + abort(); + } + + // Read the events. + ret = sqlite3_prepare_v2(db, "SELECT t, player, type FROM event", -1, &stmt, 0); + if (ret != SQLITE_OK) { + fprintf(stderr, "SELECT prepare: %s\n", sqlite3_errmsg(db)); + abort(); + } + for ( ;; ) { + ret = sqlite3_step(stmt); + if (ret == SQLITE_ROW) { + Event e; + e.t = sqlite3_column_int(stmt, 0); + e.player_id = sqlite3_column_int(stmt, 1); + e.type = (const char *)sqlite3_column_text(stmt, 2); + events.push_back(std::move(e)); + } else if (ret == SQLITE_DONE) { + break; + } else { + fprintf(stderr, "SELECT step: %s\n", sqlite3_errmsg(db)); + abort(); + } + } + ret = sqlite3_finalize(stmt); + if (ret != SQLITE_OK) { + fprintf(stderr, "SELECT finalize: %s\n", sqlite3_errmsg(db)); + abort(); + } + + // TODO what if data changes externally? + //emit dataChanged(QModelIndex( +} + +int EventsModel::insert_event(uint64_t t, int player_id) +{ + auto it = lower_bound(events.begin(), events.end(), t, + [](const Event &e, uint64_t t) { return e.t < t; }); + int pos = distance(events.begin(), it); + beginInsertRows(QModelIndex(), pos, pos + 1); + + Event e; + e.t = t; + e.player_id = player_id; + e.type = "unknown"; + events.insert(events.begin() + pos, e); + + endInsertRows(); + + // FIXME sqlite + + return pos; +} diff --git a/events.h b/events.h new file mode 100644 index 0000000..66398d1 --- /dev/null +++ b/events.h @@ -0,0 +1,51 @@ +#ifndef _EVENTS_H +#define _EVENTS_H 1 + +#include +#include +#include +#include +#include +#include + +class EventsModel : public QAbstractTableModel +{ +public: + EventsModel(sqlite3 *db) : db(db) {} + + int rowCount(const QModelIndex &parent) const override + { + refresh_if_needed(); + return events.size(); + } + int columnCount(const QModelIndex &column) const override + { + return 3; + } + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + QVariant data(const QModelIndex &index, int role) const override; + + int insert_event(uint64_t t, int player_id); + +private: + struct Player { + int player_id; + std::string number; + std::string name; + }; + mutable std::map players; + + struct Event { + uint64_t t; + std::optional player_id; + std::string type; + }; + mutable std::vector events; + mutable bool stale = true; + + sqlite3 *db; + + void refresh_if_needed() const; +}; + +#endif // !defined(_EVENTS_H) diff --git a/meson.build b/meson.build index dd159e1..27e8a48 100644 --- a/meson.build +++ b/meson.build @@ -9,4 +9,4 @@ qt_files = qt6.preprocess( ui_files: ['mainwindow.ui'], dependencies: qt6deps) -executable('stats', 'stats.cpp', qt_files, dependencies: [qt6deps, sqlite3dep]) +executable('stats', ['stats.cpp', 'events.cpp'], qt_files, dependencies: [qt6deps, sqlite3dep]) diff --git a/stats.cpp b/stats.cpp index 356c5f9..c8f0be5 100644 --- a/stats.cpp +++ b/stats.cpp @@ -12,6 +12,7 @@ #include #include "mainwindow.h" #include "ui_mainwindow.h" +#include "events.h" using namespace std; @@ -29,175 +30,6 @@ string format_timestamp(uint64_t pos) return buf; } -class EventsModel : public QAbstractTableModel -{ -public: - EventsModel(sqlite3 *db) : db(db) {} - - int rowCount(const QModelIndex &parent) const override - { - refresh_if_needed(); - return events.size(); - } - int columnCount(const QModelIndex &column) const override - { - return 3; - } - QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - QVariant data(const QModelIndex &index, int role) const override; - - int insert_event(uint64_t t, int player_id); - -private: - struct Player { - int player_id; - string number; - string name; - }; - mutable map players; - - struct Event { - uint64_t t; - optional player_id; - string type; - }; - mutable vector events; - mutable bool stale = true; - - sqlite3 *db; - - void refresh_if_needed() const; -}; - -QVariant EventsModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (role != Qt::DisplayRole) { - return QVariant(); - } - if (orientation == Qt::Horizontal) { - if (section == 0) { - return "Time"; - } else if (section == 1) { - return "Player"; - } else { - return "Type"; - } - } else { - return ""; - } -} - -QVariant EventsModel::data(const QModelIndex &index, int role) const -{ - if (role != Qt::DisplayRole) { - return QVariant(); - } - refresh_if_needed(); - if (index.column() == 0) { - return QString::fromUtf8(format_timestamp(events[index.row()].t)); - } else if (index.column() == 1) { - optional player_id = events[index.row()].player_id; - if (player_id) { - const Player &p = players[*player_id]; - return QString::fromUtf8(p.name + " (" + p.number + ")"); - } else { - return QVariant(); - } - } else if (index.column() == 2) { - return QString::fromUtf8(events[index.row()].type); - } - return QVariant(); -} - -void EventsModel::refresh_if_needed() const -{ - if (!stale) { - return; - } - - players.clear(); - events.clear(); - stale = false; - - // Read the players. - sqlite3_stmt *stmt; - int ret = sqlite3_prepare_v2(db, "SELECT player, number, name FROM player", -1, &stmt, 0); - if (ret != SQLITE_OK) { - fprintf(stderr, "SELECT prepare: %s\n", sqlite3_errmsg(db)); - abort(); - } - for ( ;; ) { - ret = sqlite3_step(stmt); - if (ret == SQLITE_ROW) { - Player p; - p.player_id = sqlite3_column_int(stmt, 0); - p.number = (const char *)sqlite3_column_text(stmt, 1); - p.name = (const char *) sqlite3_column_text(stmt, 2); - players[p.player_id] = std::move(p); - } else if (ret == SQLITE_DONE) { - break; - } else { - fprintf(stderr, "SELECT step: %s\n", sqlite3_errmsg(db)); - abort(); - } - } - ret = sqlite3_finalize(stmt); - if (ret != SQLITE_OK) { - fprintf(stderr, "SELECT finalize: %s\n", sqlite3_errmsg(db)); - abort(); - } - - // Read the events. - ret = sqlite3_prepare_v2(db, "SELECT t, player, type FROM event", -1, &stmt, 0); - if (ret != SQLITE_OK) { - fprintf(stderr, "SELECT prepare: %s\n", sqlite3_errmsg(db)); - abort(); - } - for ( ;; ) { - ret = sqlite3_step(stmt); - if (ret == SQLITE_ROW) { - Event e; - e.t = sqlite3_column_int(stmt, 0); - e.player_id = sqlite3_column_int(stmt, 1); - e.type = (const char *)sqlite3_column_text(stmt, 2); - events.push_back(std::move(e)); - } else if (ret == SQLITE_DONE) { - break; - } else { - fprintf(stderr, "SELECT step: %s\n", sqlite3_errmsg(db)); - abort(); - } - } - ret = sqlite3_finalize(stmt); - if (ret != SQLITE_OK) { - fprintf(stderr, "SELECT finalize: %s\n", sqlite3_errmsg(db)); - abort(); - } - - // TODO what if data changes externally? - //emit dataChanged(QModelIndex( -} - -int EventsModel::insert_event(uint64_t t, int player_id) -{ - auto it = lower_bound(events.begin(), events.end(), t, - [](const Event &e, uint64_t t) { return e.t < t; }); - int pos = distance(events.begin(), it); - beginInsertRows(QModelIndex(), pos, pos + 1); - - Event e; - e.t = t; - e.player_id = player_id; - e.type = "unknown"; - events.insert(events.begin() + pos, e); - - endInsertRows(); - - // FIXME sqlite - - return pos; -} - MainWindow::MainWindow() { player = new QMediaPlayer; -- 2.39.2