]> git.sesse.net Git - pkanalytics/commitdiff
Make it possible to edit players from the UI.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Thu, 3 Aug 2023 21:21:22 +0000 (23:21 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Thu, 3 Aug 2023 21:21:22 +0000 (23:21 +0200)
Adding will happen in a future step. Deleting, even further out.

edit_player_dialog.cpp [new file with mode: 0644]
edit_player_dialog.h [new file with mode: 0644]
edit_player_dialog.ui [new file with mode: 0644]
mainwindow.cpp
mainwindow.h
meson.build
players.cpp
players.h

diff --git a/edit_player_dialog.cpp b/edit_player_dialog.cpp
new file mode 100644 (file)
index 0000000..bb8ca03
--- /dev/null
@@ -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 (file)
index 0000000..bcff1ee
--- /dev/null
@@ -0,0 +1,17 @@
+#include <QDialog>
+#include <string>
+#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 (file)
index 0000000..34ee418
--- /dev/null
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>EditPlayerDialog</class>
+ <widget class="QDialog" name="EditPlayerDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>191</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Edit player</string>
+  </property>
+  <property name="modal">
+   <bool>true</bool>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_2">
+   <item row="0" column="0">
+    <layout class="QGridLayout" name="gridLayout">
+     <item row="0" column="1">
+      <widget class="QLineEdit" name="number">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>60</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="maxLength">
+        <number>3</number>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="1">
+      <widget class="QDialogButtonBox" name="buttonBox">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="standardButtons">
+        <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="1">
+      <widget class="QLineEdit" name="name"/>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="label_3">
+       <property name="text">
+        <string>Gender (optional):</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="0">
+      <widget class="QLabel" name="label_2">
+       <property name="text">
+        <string>Number (optional):</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QLineEdit" name="gender">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>25</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="inputMask">
+        <string/>
+       </property>
+       <property name="maxLength">
+        <number>1</number>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="0">
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Name:</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>number</tabstop>
+  <tabstop>gender</tabstop>
+  <tabstop>name</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>EditPlayerDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>EditPlayerDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
index bb6883f7cf58918f50f4e1e6f0a8c7c7ce77140a..74b6eed5f58cdfa0b61523b958b91782196a0955 100644 (file)
@@ -12,6 +12,7 @@
 #include <optional>
 #include <sqlite3.h>
 #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();
+}
index 5592e3ebcfed5b4543355e7f2391805e7b44570b..c16681b18d53cc6adb4bad68605f4d3dc9e203e0 100644 (file)
@@ -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);
index ce89137edd83ec4c8e9f3dc7345ca63221facab4..2b4641b278ee8b747dc6c24ae7f23842e09f3ebe 100644 (file)
@@ -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])
index 585956fde318023f57e00d62669b10f4c10c6b35..ae60e11700d0305e54d549070eb4edde231cce0c 100644 (file)
@@ -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<Player> 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::Player> PlayersModel::load_data()
+{
+       std::vector<Player> 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;
 }
index b5ba81afb5590eec890767494986dd48e6515e93..38606e57569b3c5b94fa8a47e1d42132771789ce 100644 (file)
--- 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<Player> load_data();
 };
 
 #endif  // !defined(_PLAYERS_H)