aboutsummaryrefslogtreecommitdiff
path: root/gui
diff options
context:
space:
mode:
Diffstat (limited to 'gui')
-rw-r--r--gui/gui.todo16
-rw-r--r--gui/main_window.py6
-rw-r--r--gui/tab_races.py364
3 files changed, 372 insertions, 14 deletions
diff --git a/gui/gui.todo b/gui/gui.todo
index 9c22070..fab3020 100644
--- a/gui/gui.todo
+++ b/gui/gui.todo
@@ -15,13 +15,13 @@
- [x] {show} circuit lap count
- [x] {show} photo / map
[ ] races
- - [ ] {create} new race
- - [ ] {show} race number
- - [ ] {show} race date
- - [ ] {set} race outcome
- - [ ] {set} points (per driver)
- - [ ] {set} driver that got the fastest round
- - [ ] {set/order} drivers by finish number
- - [ ] {set/radio} driver disqualified/DNF
+ - [x] {show} race number
+ - [x] {show} race date
+ - [x] {set} race outcome (end position)
+ - [x] {set} driver fastest lap time
+ - [ ] {show/calculate} points (per driver)
+ - [x] {set/order} drivers by finish number
+ - [x] {set} driver disqualified/DNF
- [ ] {add} race to calendar year
+ - [ ] {create} new race (calendar year)
diff --git a/gui/main_window.py b/gui/main_window.py
index a269f45..d6ad53d 100644
--- a/gui/main_window.py
+++ b/gui/main_window.py
@@ -76,11 +76,11 @@ class MainWindow(QMainWindow):
self._tab_drivers.update()
self._tab_teams.update()
self._tab_circuits.update()
- # self._tab_races.update()
+ self._tab_races.update()
def switch_season(self):
self.calendar_id = self.sender().property("id")
- self.update()
+ self._tab_races.set_calendar_id(self.calendar_id)
def __init__(self, cursor: mariadb.Cursor, db: mariadb.Connection, parent=None):
super(MainWindow, self).__init__(parent)
@@ -94,7 +94,7 @@ class MainWindow(QMainWindow):
self._tab_drivers = TabDrivers(self.cursor, self)
self._tab_teams = TabTeams(self.cursor, self)
self._tab_circuits = TabCircuits(self.cursor, self)
- self._tab_races = TabRaces(self)
+ self._tab_races = TabRaces(self.cursor, self)
self.main_layout = QTabWidget(self);
self.main_layout.addTab(self._tab_drivers, "Drivers")
diff --git a/gui/tab_races.py b/gui/tab_races.py
index 6d96152..9112574 100644
--- a/gui/tab_races.py
+++ b/gui/tab_races.py
@@ -1,13 +1,371 @@
import os
+import mariadb
from PySide6.QtGui import *
from PySide6.QtWidgets import *
+from PySide6.QtCore import *
+from PySide6.QtCore import Qt
+
+from split_view_layout import *
+
+from dataclasses import dataclass
+
+@dataclass
+class DBRace():
+ id: int = 0
+ week: int = 0
+ date: str = ""
+ circuit: str = ""
+ number: int = 0
+
+class RacesModel(QAbstractTableModel):
+ cursor: mariadb.Cursor
+ calendar_id: int = 1
+
+ _header = ["Week", "Date", "Circuit", "Number"]
+ _data: [DBRace] = []
+
+ def update(self):
+ self.beginResetModel()
+ self.cursor.execute("select race.ID, racedate.week, racedate.date, circuit.name, row_number() over (order by date) from race join racedate on race.raceDateID = racedate.ID join circuit on race.circuitID = circuit.ID where racedate.calendarID = ?", (self.calendar_id,))
+ self._data = list()
+ for result in self.cursor.fetchall():
+ trans_res = list(result)
+ trans_res[2] = trans_res[2].strftime('%Y-%m-%d')
+ self._data.append(DBRace(*trans_res))
+ self.endResetModel()
+
+ def __init__(self, cursor):
+ super().__init__()
+ self.cursor = cursor
+ self.update()
+
+ def rowCount(self, index=0):
+ return len(self._data)
+
+ def columnCount(self, index=0):
+ return len(self._header)
+
+ def headerData(self, section, orientation, role):
+ if role == Qt.DisplayRole:
+ if orientation == Qt.Horizontal:
+ return self._header[section]
+ else:
+ return self._data[section].id
+
+ def data(self, index, role):
+ if role == Qt.DisplayRole:
+ race = self._data[index.row()]
+ return (
+ race.week,
+ race.date,
+ race.circuit,
+ race.number,
+ )[index.column()]
+
+ def set_calendar_id(self, calendar_id):
+ self.calendar_id = calendar_id
+ self.update()
+
+class RaceBrowser(QWidget):
+ view: QTableView
+ model_table: RacesModel
+ model_proxy: QSortFilterProxyModel
+ parent_update_fn: callable
+ selected_race_id: int = 1
+ ignore_update: bool = False
+ temp_selection_index: int = 0
+
+ def update(self, cascade=True):
+ self.model_table.update()
+ self.ignore_update = True
+ self.view.selectRow(self.temp_selection_index)
+ self.ignore_update = False
+
+ def parent_update(self):
+ if self.parent_update_fn != None:
+ self.parent_update_fn()
+
+ def set_parent_update(self, fn):
+ self.parent_update_fn = fn
+
+ def set_calendar_id(self, calendar_id):
+ self.model_table.set_calendar_id(calendar_id)
+
+ def on_selection(self):
+ if self.ignore_update: return
+ rows = self.view.selectionModel().selectedRows()
+ if len(rows) == 0: return
+ row = rows[0].row()
+ self.temp_selection_index = row
+ index = self.model_proxy.mapToSource(self.model_proxy.index(row, 0))
+ new_race_id = self.model_table.headerData(index.row(), Qt.Vertical, Qt.DisplayRole)
+ if self.selected_race_id == new_race_id: return
+ self.selected_race_id = new_race_id
+ self.parent_update()
+
+ def __init__(self, cursor: mariadb.Cursor, parent=None):
+ super(RaceBrowser, self).__init__(parent)
+
+ self.cursor = cursor
+
+ self.view = QTableView()
+ self.view.setSelectionBehavior(QAbstractItemView.SelectRows)
+ self.model_table = RacesModel(self.cursor)
+ self.model_proxy = QSortFilterProxyModel()
+ self.model_proxy.setSourceModel(self.model_table)
+ self.view.setModel(self.model_proxy)
+ self.view.setSortingEnabled(True)
+ self.view.selectionModel().selectionChanged.connect(self.on_selection)
+
+ layout = QGridLayout();
+ layout.addWidget(self.view)
+ self.setLayout(layout)
+
+@dataclass
+class DBResult():
+ id: int = 0
+ driver: str = ""
+ fastest_lap: int = 0
+ position: int = 0
+ status: str = ""
+
+class ResultsModel(QAbstractTableModel):
+ cursor: mariadb.Cursor
+ race_id: int = 1
+
+ _header = ["Driver", "Fastest lap [s]", "Endposition", "Status"]
+ _data: [DBResult] = []
+
+ def update(self):
+ self.beginResetModel()
+ self.cursor.execute("select raceresult.ID, regexp_replace(concat(member.firstName, ' ', member.middleName, ' ', member.lastName), ' *', ' ') as driver, raceresult.fastestlap, endposition.position, specialposition.type from raceresult join endposition on endposition.ID = raceresult.endPositionID join member on member.ID = endposition.memberID join specialposition on specialposition.ID = endposition.specialPositionID where raceresult.raceID = ? order by endposition.position", (self.race_id,))
+ self._data = list()
+ for result in self.cursor.fetchall():
+ self._data.append(DBResult(*result))
+ self.endResetModel()
+
+ def __init__(self, cursor):
+ super().__init__()
+ self.cursor = cursor
+ self.update()
+
+ def rowCount(self, index=0):
+ return len(self._data)
+
+ def columnCount(self, index=0):
+ return len(self._header)
+
+ def headerData(self, section, orientation, role):
+ if role == Qt.DisplayRole:
+ if orientation == Qt.Horizontal:
+ return self._header[section]
+ else:
+ return self._data[section].id
+
+ def data(self, index, role):
+ if role == Qt.DisplayRole:
+ result = self._data[index.row()]
+ return (
+ result.driver,
+ result.fastest_lap,
+ result.position,
+ result.status,
+ )[index.column()]
+
+ def set_race_id(self, race_id):
+ self.race_id = race_id
+ self.update()
+
+class ResultBrowser(QWidget):
+ view: QTableView
+ model_table: ResultsModel
+ model_proxy: QSortFilterProxyModel
+ parent_update_fn: callable
+ selected_result_id: int = 1
+ ignore_update: bool = False
+ temp_selection_index: int = 0
+
+ def update(self, cascade=True):
+ self.model_table.update()
+ self.ignore_update = True
+ self.view.selectRow(self.temp_selection_index)
+ self.ignore_update = False
+
+ def parent_update(self):
+ if self.parent_update_fn != None:
+ self.parent_update_fn()
+
+ def set_parent_update(self, fn):
+ self.parent_update_fn = fn
+
+ def set_race_id(self, race_id):
+ self.model_table.set_race_id(race_id)
+
+ def on_selection(self):
+ if self.ignore_update: return
+ rows = self.view.selectionModel().selectedRows()
+ if len(rows) == 0: return
+ row = rows[0].row()
+ self.temp_selection_index = row
+ index = self.model_proxy.mapToSource(self.model_proxy.index(row, 0))
+ new_result_id = self.model_table.headerData(index.row(), Qt.Vertical, Qt.DisplayRole)
+ if self.selected_result_id == new_result_id: return
+ self.selected_result_id = new_result_id
+ self.parent_update()
+
+ def __init__(self, cursor: mariadb.Cursor, parent=None):
+ super(ResultBrowser, self).__init__(parent)
+
+ self.cursor = cursor
+
+ self.view = QTableView()
+ self.view.setSelectionBehavior(QAbstractItemView.SelectRows)
+ self.model_table = ResultsModel(self.cursor)
+ self.model_proxy = QSortFilterProxyModel()
+ self.model_proxy.setSourceModel(self.model_table)
+ self.view.setModel(self.model_proxy)
+ self.view.setSortingEnabled(True)
+ self.view.selectionModel().selectionChanged.connect(self.on_selection)
+
+ layout = QGridLayout();
+ layout.addWidget(self.view)
+ self.setLayout(layout)
+
+class ResultDetailsWidget(QWidget):
+ cursor: mariadb.Cursor
+ parent_update_fn: callable
+ selected_result_id: int = 1
+
+ result_details: DBResult
+
+ label_id: QLabel
+ num_end_position: QSpinBox
+ combo_status: QComboBox
+ num_fastest_lap_time: QSpinBox
+
+ def update(self, cascade=True):
+ self.cursor.execute("select endposition.position, specialposition.type, raceresult.fastestlap from endposition join raceresult on raceresult.endPositionID = endposition.ID join specialposition on specialposition.ID = endposition.specialPositionID where raceresult.ID = ?", (self.selected_result_id,))
+ result = self.cursor.fetchone()
+
+ self.label_id.setText(f"{self.selected_result_id}")
+ self.num_end_position.setValue(result[0])
+ self.combo_status.setCurrentText(result[1])
+ self.num_fastest_lap_time.setValue(result[2])
+
+ if cascade == False: return
+
+ def parent_update(self):
+ if self.parent_update_fn != None:
+ self.parent_update_fn()
+
+ def set_result_id(self, id):
+ self.selected_result_id = id
+ self.update(False)
+
+ def set_parent_update(self, fn):
+ self.parent_update_fn = fn
+
+ def save_edits(self):
+ fastest_lap = self.num_fastest_lap_time.value()
+ end_position = self.num_end_position.value()
+ special_position_id = self.combo_status.itemData(self.combo_status.currentIndex())
+
+ self.cursor.execute("select endPositionID from raceresult where ID = ?", (self.selected_result_id,))
+ endposition_id = self.cursor.fetchone()[0]
+
+ self.cursor.execute("update `raceresult` set `fastestlap` = ? where `ID` = ?", (fastest_lap, self.selected_result_id,))
+ self.cursor.execute("update `endposition` set `position` = ?, `specialPositionID` = ? where `ID` = ?", (end_position, special_position_id, endposition_id,))
+
+ self.parent_update()
+
+ def __init__(self, cursor: mariadb.Cursor, parent=None):
+ super(ResultDetailsWidget, self).__init__(parent)
+ self.cursor = cursor
+
+ self.result_details = DBResult()
+
+ layout = QVBoxLayout(self)
+ layout.setAlignment(Qt.AlignmentFlag.AlignTop)
+
+ self.label_id = QLabel("hoi")
+ self.num_end_position = QSpinBox()
+ self.num_end_position.setMinimum(0);
+ self.num_end_position.setMaximum(25);
+ self.num_end_position.setSingleStep(1);
+ self.num_fastest_lap_time = QSpinBox()
+ self.combo_status = QComboBox()
+
+ self.cursor.execute("select ID, type from specialposition")
+ for status in self.cursor.fetchall():
+ self.combo_status.addItem(status[1], status[0])
+
+ details_form = QFormLayout(self)
+ details_form.addRow("ID", self.label_id)
+ details_form.addRow("Fastest lap time (s)", self.num_fastest_lap_time)
+ details_form.addRow("End position", self.num_end_position)
+ details_form.addRow("Status", self.combo_status)
+ layout.addLayout(details_form)
+
+ self.push_button_save = QPushButton("Save edits")
+ self.push_button_save.clicked.connect(self.save_edits)
+ layout.addWidget(self.push_button_save)
+
+ self.setLayout(layout)
class TabRaces(QWidget):
- def __init__(self, parent=None):
+ calendar_id: int = 0
+ parent: QMainWindow
+ cursor: mariadb.Cursor
+ selected_race_id: int = 1
+ selected_race_result_id: int = 1
+
+ race_browser: RaceBrowser
+ result_browser: ResultBrowser
+ result_editor: ResultDetailsWidget
+
+ def set_calendar_id(self, calendar_id):
+ self.calendar_id = calendar_id
+ self.race_browser.set_calendar_id(calendar_id)
+
+ def update(self, cascade=True):
+ print("update TabRaces")
+
+ if not cascade: return
+ self.race_browser.update(True)
+
+ def child_update(self):
+ self.race_browser.update(False)
+ self.selected_race_id = self.race_browser.selected_race_id
+ self.result_browser.set_race_id(self.selected_race_id)
+ self.selected_race_result_id = self.result_browser.selected_result_id
+ self.result_editor.set_result_id(self.selected_race_result_id)
+
+ def __init__(self, cursor, parent=None):
super(TabRaces, self).__init__(parent)
+ self.parent = parent
+ self.cursor = cursor
+
+ self.race_browser = RaceBrowser(self.cursor, self)
+ self.result_browser = ResultBrowser(self.cursor, self)
+ self.result_editor = ResultDetailsWidget(self.cursor, self)
+ self.race_browser.set_parent_update(self.child_update)
+ self.result_browser.set_parent_update(self.child_update)
+ self.result_editor.set_parent_update(self.child_update)
- layout = QFormLayout()
- layout.addWidget(QLabel("hoi"))
+ layout = QHBoxLayout()
+ column1 = QVBoxLayout()
+ column1.addWidget(QLabel("Race"))
+ column1.addWidget(self.race_browser)
+ column2 = QVBoxLayout()
+ column2.addWidget(QLabel("Results"))
+ column2.addWidget(self.result_browser)
+ column3 = QVBoxLayout()
+ column3.setAlignment(Qt.AlignmentFlag.AlignTop)
+ column3.addWidget(QLabel("Details"))
+ column3.addWidget(self.result_editor)
+ layout.addLayout(column1)
+ layout.addLayout(column2)
+ layout.addLayout(column3)
self.setLayout(layout)