From 90b51a9bdc21a5f8a90e4b54ec7deefab8fd39f5 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Thu, 3 Aug 2023 23:21:22 +0200 Subject: [PATCH] Make it possible to edit players from the UI. Adding will happen in a future step. Deleting, even further out. --- edit_player_dialog.cpp | 13 ++++ edit_player_dialog.h | 17 +++++ edit_player_dialog.ui | 141 +++++++++++++++++++++++++++++++++++++++++ mainwindow.cpp | 20 ++++++ mainwindow.h | 1 + meson.build | 6 +- players.cpp | 53 ++++++++++++++-- players.h | 15 +++-- 8 files changed, 252 insertions(+), 14 deletions(-) create mode 100644 edit_player_dialog.cpp create mode 100644 edit_player_dialog.h create mode 100644 edit_player_dialog.ui diff --git a/edit_player_dialog.cpp b/edit_player_dialog.cpp new file mode 100644 index 0000000..bb8ca03 --- /dev/null +++ b/edit_player_dialog.cpp @@ -0,0 +1,13 @@ +#include "edit_player_dialog.h" + +EditPlayerDialog::EditPlayerDialog(const std::string &number, const std::string &gender, const std::string &name) +{ + ui = new Ui::EditPlayerDialog; + ui->setupUi(this); + + ui->number->setText(QString::fromUtf8(number)); + ui->gender->setText(QString::fromUtf8(gender)); + ui->name->setText(QString::fromUtf8(name)); + + setModal(true); +} diff --git a/edit_player_dialog.h b/edit_player_dialog.h new file mode 100644 index 0000000..bcff1ee --- /dev/null +++ b/edit_player_dialog.h @@ -0,0 +1,17 @@ +#include +#include +#include "ui_edit_player_dialog.h" + +class EditPlayerDialog : public QDialog +{ + Q_OBJECT + +public: + EditPlayerDialog(const std::string &number, const std::string &gender, const std::string &name); + std::string number() const { return ui->number->text().toStdString(); } + std::string gender() const { return ui->gender->text().toStdString(); } + std::string name() const { return ui->name->text().toStdString(); } + +private: + Ui::EditPlayerDialog *ui; +}; diff --git a/edit_player_dialog.ui b/edit_player_dialog.ui new file mode 100644 index 0000000..34ee418 --- /dev/null +++ b/edit_player_dialog.ui @@ -0,0 +1,141 @@ + + + EditPlayerDialog + + + + 0 + 0 + 400 + 191 + + + + Edit player + + + true + + + + + + + + + 0 + 0 + + + + + 60 + 16777215 + + + + 3 + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + Gender (optional): + + + + + + + Number (optional): + + + + + + + + 0 + 0 + + + + + 25 + 16777215 + + + + + + + 1 + + + + + + + Name: + + + + + + + + + number + gender + name + + + + + buttonBox + accepted() + EditPlayerDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + EditPlayerDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/mainwindow.cpp b/mainwindow.cpp index bb6883f..74b6eed 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -12,6 +12,7 @@ #include #include #include "mainwindow.h" +#include "edit_player_dialog.h" #include "ui_mainwindow.h" #include "events.h" #include "players.h" @@ -344,6 +345,9 @@ MainWindow::MainWindow(EventsModel *events, PlayersModel *players, connect(ui->clear_player_list, &QPushButton::clicked, [this] { ui->player_view->selectionModel()->clear(); }); + connect(ui->player_view, &QTableView::doubleClicked, [this](const QModelIndex &index) { + open_edit_player_dialog(index.row()); + }); connect(ui->player_view->selectionModel(), &QItemSelectionModel::selectionChanged, [this] { update_gender_ratio(ui->video->get_position()); }); @@ -895,3 +899,19 @@ void MainWindow::formation_double_clicked(bool offense, unsigned row) update_ui_from_time(ui->video->get_position()); } +void MainWindow::open_edit_player_dialog(unsigned row) +{ + int player_id = players->get_player_id(row); + string number = players->get_player_number(row); + string gender = players->get_player_gender(row); + string name = players->get_player_name(row); + + EditPlayerDialog *dialog = new EditPlayerDialog(number, gender, name); + connect(dialog, &QDialog::finished, [this, dialog, player_id](int result) { + if (result == QDialog::Accepted) { + players->edit_player(player_id, dialog->number(), dialog->gender(), dialog->name()); + update_ui_from_time(ui->video->get_position()); + } + }); + dialog->show(); +} diff --git a/mainwindow.h b/mainwindow.h index 5592e3e..c16681b 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -34,6 +34,7 @@ private: void delete_current_event(); void make_substitution(); void formation_double_clicked(bool offense, unsigned row); + void open_edit_player_dialog(unsigned row); void update_ui_from_time(uint64_t t); void update_status(uint64_t t); diff --git a/meson.build b/meson.build index ce89137..2b4641b 100644 --- a/meson.build +++ b/meson.build @@ -9,11 +9,11 @@ libavutildep = dependency('libavutil') libswscaledep = dependency('libswscale') qt_files = qt6.preprocess( - moc_headers: ['mainwindow.h', 'clickable_label.h', 'video_widget.h'], - ui_files: ['mainwindow.ui'], + moc_headers: ['mainwindow.h', 'edit_player_dialog.h', 'clickable_label.h', 'video_widget.h'], + ui_files: ['mainwindow.ui', 'edit_player_dialog.ui'], dependencies: qt6deps) executable('pkanalytics', - ['main.cpp', 'mainwindow.cpp', 'events.cpp', 'players.cpp', 'formations.cpp', 'json.cpp', 'video_widget.cpp', 'ffmpeg_raii.cpp'], + ['main.cpp', 'mainwindow.cpp', 'events.cpp', 'players.cpp', 'formations.cpp', 'json.cpp', 'video_widget.cpp', 'ffmpeg_raii.cpp', 'edit_player_dialog.cpp'], qt_files, dependencies: [qt6deps, sqlite3dep, libavcodecdep, libavformatdep, libavutildep, libswscaledep]) diff --git a/players.cpp b/players.cpp index 585956f..ae60e11 100644 --- a/players.cpp +++ b/players.cpp @@ -10,7 +10,7 @@ string format_timestamp(uint64_t pos); PlayersModel::PlayersModel(sqlite3 *db) : db(db) { - load_data(); + players = load_data(); } QVariant PlayersModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -69,9 +69,52 @@ string PlayersModel::get_player_gender_by_id(unsigned player_id) return it->gender; } -void PlayersModel::load_data() +void PlayersModel::edit_player(int player_id, const string &number, const string &gender, const string &name) { - players.clear(); + auto it = find_if(players.begin(), players.end(), [player_id](const Player &p) { return p.player_id == int(player_id); }); + int old_row = distance(players.begin(), it); + + sqlite3_stmt *stmt; + int ret = sqlite3_prepare_v2(db, "UPDATE player SET number=?, gender=?, name=? WHERE player=?", -1, &stmt, 0); + if (ret != SQLITE_OK) { + fprintf(stderr, "UPDATE prepare: %s\n", sqlite3_errmsg(db)); + abort(); + } + + sqlite3_bind_text(stmt, 1, number.data(), number.size(), SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, gender.data(), gender.size(), SQLITE_STATIC); + sqlite3_bind_text(stmt, 3, name.data(), name.size(), SQLITE_STATIC); + sqlite3_bind_int64(stmt, 4, player_id); + + ret = sqlite3_step(stmt); + if (ret != SQLITE_DONE) { + fprintf(stderr, "UPDATE 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(); + } + + vector new_players = load_data(); + it = find_if(new_players.begin(), new_players.end(), [player_id](const Player &p) { return p.player_id == int(player_id); }); + int new_row = distance(new_players.begin(), it); + + if (old_row == new_row) { + players = std::move(new_players); + emit dataChanged(createIndex(old_row, 0), createIndex(old_row, 2)); + } else { + emit beginMoveRows(QModelIndex(), old_row, old_row, QModelIndex(), new_row); + players = std::move(new_players); + emit endInsertRows(); + } +} + +std::vector PlayersModel::load_data() +{ + std::vector new_players; // Read the players. sqlite3_stmt *stmt; @@ -88,7 +131,7 @@ void PlayersModel::load_data() p.number = (const char *)sqlite3_column_text(stmt, 1); p.name = (const char *)sqlite3_column_text(stmt, 2); p.gender = (const char *)sqlite3_column_text(stmt, 3); - players.push_back(p); + new_players.push_back(p); } else if (ret == SQLITE_DONE) { break; } else { @@ -101,4 +144,6 @@ void PlayersModel::load_data() fprintf(stderr, "SELECT finalize: %s\n", sqlite3_errmsg(db)); abort(); } + + return new_players; } diff --git a/players.h b/players.h index b5ba81a..38606e5 100644 --- a/players.h +++ b/players.h @@ -22,12 +22,11 @@ public: QVariant headerData(int section, Qt::Orientation orientation, int role) const override; QVariant data(const QModelIndex &index, int role) const override; - int get_player_id(unsigned row) const { - return players[row].player_id; - } - std::string get_player_gender(unsigned row) const { - return players[row].gender; - } + int get_player_id(unsigned row) const { return players[row].player_id; } + std::string get_player_number(unsigned row) const { return players[row].number; } + std::string get_player_name(unsigned row) const { return players[row].name; } + std::string get_player_gender(unsigned row) const { return players[row].gender; } + std::string get_player_name_by_id(unsigned player_id); std::string get_player_gender_by_id(unsigned player_id); QModelIndex get_row_start_qt(unsigned row) const { @@ -37,6 +36,8 @@ public: return createIndex(row, 2); } + void edit_player(int player_id, const std::string &number, const std::string &gender, const std::string &name); + private: struct Player { int player_id; @@ -48,7 +49,7 @@ private: sqlite3 *db; - void load_data(); + std::vector load_data(); }; #endif // !defined(_PLAYERS_H) -- 2.39.5