diff --git a/src/warchron/controller/controller.py b/src/warchron/controller/controller.py index 15a9461..e7ba6a4 100644 --- a/src/warchron/controller/controller.py +++ b/src/warchron/controller/controller.py @@ -1,53 +1,32 @@ from pathlib import Path from PyQt6.QtWidgets import QMessageBox, QDialog -from warchron.model.model import Model -from warchron.view.view import View -from warchron.view.view import PlayerDialog, WarDialog, CampaignDialog +from warchron.view.view import PlayerDialog class Controller: - def __init__(self, model: Model, view: View): + def __init__(self, model, view): self.model = model self.view = view self.current_file: Path | None = None - self.selected_war_id = None - self.selected_campaign_id = None - self.selected_round_id = None self.view.on_close_callback = self.on_app_close self.is_dirty = False self.__connect() self.refresh_players_view() - self.refresh_wars_view() self.update_window_title() - self.update_actions_state() - self.view.on_tree_selection_changed = self.on_tree_selection_changed - self.view.on_add_campaign = self.add_campaign - self.view.on_add_round = self.add_round def __connect(self): + self.view.addPlayerBtn.clicked.connect(self.add_player) self.view.actionExit.triggered.connect(self.view.close) self.view.actionNew.triggered.connect(self.new) self.view.actionOpen.triggered.connect(self.open_file) self.view.actionSave.triggered.connect(self.save) self.view.actionSave_as.triggered.connect(self.save_as) - self.view.addPlayerBtn.clicked.connect(self.add_player) - self.view.addWarBtn.clicked.connect(self.add_war) - def on_app_close(self) -> bool: - if self.is_dirty: - reply = QMessageBox.question( - self.view, - "Unsaved changes", - "You have unsaved changes. Do you want to save before quitting?", - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No | QMessageBox.StandardButton.Cancel - ) - if reply == QMessageBox.StandardButton.Yes: - self.save() - elif reply == QMessageBox.StandardButton.Cancel: - return False - return True - + def refresh_players_view(self): + players = self.model.get_all_players() + self.view.display_players(players) + def new(self): if self.is_dirty: reply = QMessageBox.question( @@ -62,7 +41,6 @@ class Controller: self.current_file = None self.is_dirty = False self.refresh_players_view() - self.refresh_wars_view() self.update_window_title() def open_file(self): @@ -82,9 +60,22 @@ class Controller: self.current_file = path self.is_dirty = False self.refresh_players_view() - self.refresh_wars_view() self.update_window_title() - + + def on_app_close(self) -> bool: + if self.is_dirty: + reply = QMessageBox.question( + self.view, + "Unsaved changes", + "You have unsaved changes. Do you want to save before quitting?", + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No | QMessageBox.StandardButton.Cancel + ) + if reply == QMessageBox.StandardButton.Yes: + self.save() + elif reply == QMessageBox.StandardButton.Cancel: + return False + return True + def save(self): if not self.current_file: self.save_as() @@ -112,30 +103,6 @@ class Controller: base = base + " *" self.view.setWindowTitle(base) - def refresh_players_view(self): - players = self.model.get_all_players() - self.view.display_players(players) - - def refresh_wars_view(self): - wars = self.model.get_all_wars() - self.view.display_wars(wars) - - def on_tree_selection_changed(self, selection): - self.selected_war_id = None - self.selected_campaign_id = None - self.selected_round_id = None - if selection: - if selection["type"] == "war": - self.selected_war_id = selection["id"] - elif selection["type"] == "campaign": - self.selected_campaign_id = selection["id"] - elif selection["type"] == "round": - self.selected_round_id = selection["id"] - self.update_actions_state() - - def update_actions_state(self): - self.view.set_add_campaign_enabled(self.selected_war_id is not None) - self.view.set_add_round_enabled(self.selected_campaign_id is not None) def add_player(self): dialog = PlayerDialog(self.view) @@ -153,42 +120,3 @@ class Controller: self.is_dirty = True self.refresh_players_view() self.update_window_title() - - def add_war(self): - dialog = WarDialog(self.view) - result = dialog.exec() # modal blocking dialog - if result == QDialog.DialogCode.Accepted: - name = dialog.get_war_name() - if not name: - QMessageBox.warning( - self.view, - "Invalid name", - "War name cannot be empty." - ) - return - self.model.add_war(name) - self.is_dirty = True - self.refresh_wars_view() - self.update_window_title() - - def add_campaign(self): - if not self.selected_war_id: - return - dialog = CampaignDialog(self.view) - if dialog.exec() != QDialog.DialogCode.Accepted: - return - name = dialog.get_campaign_name() - if not name: - return - self.model.add_campaign(self.selected_war_id, name) - self.is_dirty = True - self.refresh_wars_view() - self.update_window_title() - - def add_round(self): - if not self.selected_campaign_id: - return - self.model.add_round(self.selected_campaign_id) - self.is_dirty = True - self.refresh_wars_view() - self.update_window_title() diff --git a/src/warchron/model/campaign.py b/src/warchron/model/campaign.py index 6a7eb99..ffe070b 100644 --- a/src/warchron/model/campaign.py +++ b/src/warchron/model/campaign.py @@ -9,7 +9,7 @@ class Campaign: self.name = name self.month = datetime.now().month self.entrants = {} - self.rounds = [] + self.rounds = {} self.is_over = False def set_id(self, new_id): @@ -42,20 +42,4 @@ class Campaign: ## entrants placeholder ## rounds placeholder tmp.set_state(is_over) - return tmp - - def add_round(self, number: int) -> Round: - round = Round() - self.rounds.append(round) - return round - - def get_round(self, round_id) -> Round: - return self.rounds[round_id] - - def get_all_rounds(self) -> list[Round]: - return list(self.rounds) - - def add_round(self) -> Round: - round = Round() - self.rounds.append(round) - return round \ No newline at end of file + return tmp \ No newline at end of file diff --git a/src/warchron/model/model.py b/src/warchron/model/model.py index 0cc4bdf..5e97b44 100644 --- a/src/warchron/model/model.py +++ b/src/warchron/model/model.py @@ -4,8 +4,6 @@ import shutil from warchron.model.player import Player from warchron.model.war import War -from warchron.model.campaign import Campaign -from warchron.model.round import Round class Model: def __init__(self): @@ -71,36 +69,13 @@ class Model: def get_all_players(self) -> list[Player]: return list(self.players.values()) - def add_war(self, name) -> War: + def add_war(self, name): war = War(name) self.wars[war.id] = war return war - def get_war(self, id) -> War: + def get_war(self, id): return self.wars[id] def get_all_wars(self) -> list[War]: return list(self.wars.values()) - - def add_campaign(self, war_id: str, name: str) -> Campaign: - war = self.get_war(war_id) - return war.add_campaign(name) - - def get_campaign(self, campaign_id) -> Campaign: - for war in self.wars.values(): - for campaign in war.campaigns: - if campaign.id == campaign_id: - return campaign - raise KeyError("Campaign not found") - - def add_round(self, campaign_id: str) -> Round: - campaign = self.get_campaign(campaign_id) - return campaign.add_round() - - def get_round(self, round_id: str) -> Round: - for war in self.wars.values(): - for campaign in war.campaigns: - for rnd in campaign.rounds: - if rnd.id == round_id: - return rnd - raise KeyError("Round not found") \ No newline at end of file diff --git a/src/warchron/model/round.py b/src/warchron/model/round.py index 04cfb81..faceb0d 100644 --- a/src/warchron/model/round.py +++ b/src/warchron/model/round.py @@ -1,21 +1,20 @@ -from uuid import uuid4 - class Round: - def __init__(self): - self.id = str(uuid4()) + def __init__(self, number): + self.number = number self.sectors = {} self.choices = {} self.battles = {} self.is_over = False - def set_id(self, new_id): - self.id = new_id + def set_number(self, new_number): + self.number = new_number def set_state(self, new_state): self.is_over = new_state def toDict(self): return { + "number" : self.number, "sectors" : self.sectors, "choices" : self.choices, "battles" : self.battles, @@ -23,9 +22,8 @@ class Round: } @staticmethod - def fromDict(id, sectors, choices, battles, is_over): - tmp = Round() - tmp.set_id(id) + def fromDict(id, number, sectors, choices, battles, is_over): + tmp = Round(number=number) ## sectors placeholder ## choices placeholder ## battles placeholder diff --git a/src/warchron/model/war.py b/src/warchron/model/war.py index 564aeb3..308cec2 100644 --- a/src/warchron/model/war.py +++ b/src/warchron/model/war.py @@ -9,9 +9,10 @@ class War: self.name = name self.year = datetime.now().year self.entrants = {} - self.campaigns = [] + self.campaigns = {} self.is_over = False + def set_id(self, new_id): self.id = new_id @@ -42,20 +43,4 @@ class War: ## entrants placeholder ## campaigns placeholder tmp.set_state(is_over) - return tmp - - def add_campaign(self, name) -> Campaign: - campaign = Campaign(name) - self.campaigns.append(campaign) - return campaign - - def get_campaign(self, campaign_id) -> Campaign: - return self.campaigns[campaign_id] - - def get_all_campaigns(self) -> list[Campaign]: - return list(self.campaigns) - - def add_campaign(self, name: str) -> Campaign: - campaign = Campaign(name) - self.campaigns.append(campaign) - return campaign \ No newline at end of file + return tmp \ No newline at end of file diff --git a/src/warchron/view/ui/ui_campaign_dialog.py b/src/warchron/view/ui/ui_campaign_dialog.py deleted file mode 100644 index 2482d5b..0000000 --- a/src/warchron/view/ui/ui_campaign_dialog.py +++ /dev/null @@ -1,50 +0,0 @@ -# Form implementation generated from reading ui file '.\src\warchron\view\ui\ui_campaign_dialog.ui' -# -# Created by: PyQt6 UI code generator 6.7.1 -# -# WARNING: Any manual changes made to this file will be lost when pyuic6 is -# run again. Do not edit this file unless you know what you are doing. - - -from PyQt6 import QtCore, QtGui, QtWidgets - - -class Ui_campaignDialog(object): - def setupUi(self, campaignDialog): - campaignDialog.setObjectName("campaignDialog") - campaignDialog.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal) - campaignDialog.resize(378, 98) - icon = QtGui.QIcon() - icon.addPixmap(QtGui.QPixmap(".\\src\\warchron\\view\\ui\\../resources/warchron_logo.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) - campaignDialog.setWindowIcon(icon) - self.buttonBox = QtWidgets.QDialogButtonBox(parent=campaignDialog) - self.buttonBox.setGeometry(QtCore.QRect(10, 60, 341, 32)) - self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) - self.buttonBox.setObjectName("buttonBox") - self.label = QtWidgets.QLabel(parent=campaignDialog) - self.label.setGeometry(QtCore.QRect(10, 20, 47, 14)) - self.label.setObjectName("label") - self.campaignName = QtWidgets.QLineEdit(parent=campaignDialog) - self.campaignName.setGeometry(QtCore.QRect(60, 20, 113, 20)) - self.campaignName.setObjectName("campaignName") - - self.retranslateUi(campaignDialog) - self.buttonBox.accepted.connect(campaignDialog.accept) # type: ignore - self.buttonBox.rejected.connect(campaignDialog.reject) # type: ignore - QtCore.QMetaObject.connectSlotsByName(campaignDialog) - - def retranslateUi(self, campaignDialog): - _translate = QtCore.QCoreApplication.translate - campaignDialog.setWindowTitle(_translate("campaignDialog", "Campaign")) - self.label.setText(_translate("campaignDialog", "Name:")) - - -if __name__ == "__main__": - import sys - app = QtWidgets.QApplication(sys.argv) - campaignDialog = QtWidgets.QDialog() - ui = Ui_campaignDialog() - ui.setupUi(campaignDialog) - campaignDialog.show() - sys.exit(app.exec()) diff --git a/src/warchron/view/ui/ui_campaign_dialog.ui b/src/warchron/view/ui/ui_campaign_dialog.ui deleted file mode 100644 index c5ef227..0000000 --- a/src/warchron/view/ui/ui_campaign_dialog.ui +++ /dev/null @@ -1,98 +0,0 @@ - - - campaignDialog - - - Qt::ApplicationModal - - - - 0 - 0 - 378 - 98 - - - - Campaign - - - - ../resources/warchron_logo.png../resources/warchron_logo.png - - - - - 10 - 60 - 341 - 32 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - 10 - 20 - 47 - 14 - - - - Name: - - - - - - 60 - 20 - 113 - 20 - - - - - - - - buttonBox - accepted() - campaignDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - campaignDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/src/warchron/view/ui/ui_main_window.py b/src/warchron/view/ui/ui_main_window.py index a6c422d..e5c8a37 100644 --- a/src/warchron/view/ui/ui_main_window.py +++ b/src/warchron/view/ui/ui_main_window.py @@ -51,16 +51,12 @@ class Ui_MainWindow(object): self.addCampaignBtn.setEnabled(False) self.addCampaignBtn.setGeometry(QtCore.QRect(110, 20, 91, 23)) self.addCampaignBtn.setObjectName("addCampaignBtn") - self.addRoundBtn = QtWidgets.QPushButton(parent=self.warsTab) - self.addRoundBtn.setEnabled(False) - self.addRoundBtn.setGeometry(QtCore.QRect(220, 20, 91, 23)) - self.addRoundBtn.setObjectName("addRoundBtn") icon2 = QtGui.QIcon() icon2.addPixmap(QtGui.QPixmap(".\\src\\warchron\\view\\ui\\../resources/swords-small.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) self.tabWidget.addTab(self.warsTab, icon2, "") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(parent=MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22)) self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(parent=self.menubar) self.menuFile.setObjectName("menuFile") @@ -148,7 +144,6 @@ class Ui_MainWindow(object): self.tabWidget.setTabText(self.tabWidget.indexOf(self.playersTab), _translate("MainWindow", "Players")) self.addWarBtn.setText(_translate("MainWindow", "Add war")) self.addCampaignBtn.setText(_translate("MainWindow", "Add Campaign")) - self.addRoundBtn.setText(_translate("MainWindow", "Add Round")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.warsTab), _translate("MainWindow", "Wars")) self.menuFile.setTitle(_translate("MainWindow", "File")) self.menuEdit.setTitle(_translate("MainWindow", "Edit")) diff --git a/src/warchron/view/ui/ui_main_window.ui b/src/warchron/view/ui/ui_main_window.ui index c20c876..b88ad16 100644 --- a/src/warchron/view/ui/ui_main_window.ui +++ b/src/warchron/view/ui/ui_main_window.ui @@ -124,22 +124,6 @@ Add Campaign - - - false - - - - 220 - 20 - 91 - 23 - - - - Add Round - - @@ -149,7 +133,7 @@ 0 0 800 - 21 + 22 diff --git a/src/warchron/view/ui/ui_war_dialog.py b/src/warchron/view/ui/ui_war_dialog.py deleted file mode 100644 index 46404e7..0000000 --- a/src/warchron/view/ui/ui_war_dialog.py +++ /dev/null @@ -1,50 +0,0 @@ -# Form implementation generated from reading ui file '.\src\warchron\view\ui\ui_war_dialog.ui' -# -# Created by: PyQt6 UI code generator 6.7.1 -# -# WARNING: Any manual changes made to this file will be lost when pyuic6 is -# run again. Do not edit this file unless you know what you are doing. - - -from PyQt6 import QtCore, QtGui, QtWidgets - - -class Ui_warDialog(object): - def setupUi(self, warDialog): - warDialog.setObjectName("warDialog") - warDialog.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal) - warDialog.resize(378, 98) - icon = QtGui.QIcon() - icon.addPixmap(QtGui.QPixmap(".\\src\\warchron\\view\\ui\\../resources/warchron_logo.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) - warDialog.setWindowIcon(icon) - self.buttonBox = QtWidgets.QDialogButtonBox(parent=warDialog) - self.buttonBox.setGeometry(QtCore.QRect(10, 60, 341, 32)) - self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) - self.buttonBox.setObjectName("buttonBox") - self.label = QtWidgets.QLabel(parent=warDialog) - self.label.setGeometry(QtCore.QRect(10, 20, 47, 14)) - self.label.setObjectName("label") - self.warName = QtWidgets.QLineEdit(parent=warDialog) - self.warName.setGeometry(QtCore.QRect(60, 20, 113, 20)) - self.warName.setObjectName("warName") - - self.retranslateUi(warDialog) - self.buttonBox.accepted.connect(warDialog.accept) # type: ignore - self.buttonBox.rejected.connect(warDialog.reject) # type: ignore - QtCore.QMetaObject.connectSlotsByName(warDialog) - - def retranslateUi(self, warDialog): - _translate = QtCore.QCoreApplication.translate - warDialog.setWindowTitle(_translate("warDialog", "War")) - self.label.setText(_translate("warDialog", "Name:")) - - -if __name__ == "__main__": - import sys - app = QtWidgets.QApplication(sys.argv) - warDialog = QtWidgets.QDialog() - ui = Ui_warDialog() - ui.setupUi(warDialog) - warDialog.show() - sys.exit(app.exec()) diff --git a/src/warchron/view/ui/ui_war_dialog.ui b/src/warchron/view/ui/ui_war_dialog.ui deleted file mode 100644 index 89ae183..0000000 --- a/src/warchron/view/ui/ui_war_dialog.ui +++ /dev/null @@ -1,98 +0,0 @@ - - - warDialog - - - Qt::ApplicationModal - - - - 0 - 0 - 378 - 98 - - - - War - - - - ../resources/warchron_logo.png../resources/warchron_logo.png - - - - - 10 - 60 - 341 - 32 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - 10 - 20 - 47 - 14 - - - - Name: - - - - - - 60 - 20 - 113 - 20 - - - - - - - - buttonBox - accepted() - warDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - warDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/src/warchron/view/view.py b/src/warchron/view/view.py index d44615f..7ca4f03 100644 --- a/src/warchron/view/view.py +++ b/src/warchron/view/view.py @@ -1,49 +1,25 @@ from pathlib import Path -import calendar from PyQt6 import QtWidgets -from PyQt6.QtCore import Qt -from PyQt6.QtWidgets import QDialog, QFileDialog, QTreeWidgetItem +from PyQt6.QtWidgets import QDialog, QFileDialog from PyQt6.QtGui import QCloseEvent from warchron.view.ui.ui_main_window import Ui_MainWindow from warchron.view.ui.ui_player_dialog import Ui_playerDialog -from warchron.view.ui.ui_war_dialog import Ui_warDialog -from warchron.view.ui.ui_campaign_dialog import Ui_campaignDialog - -ROLE_TYPE = Qt.ItemDataRole.UserRole -ROLE_ID = Qt.ItemDataRole.UserRole + 1 class View(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(View, self).__init__(parent) self.setupUi(self) self.on_close_callback = None - self.on_selection_changed = None - self.on_add_campaign = None - self.on_add_round = None - self.warsTree.currentItemChanged.connect(self._emit_selection_changed) - self.addCampaignBtn.clicked.connect(self._on_add_campaign_clicked) - self.addRoundBtn.clicked.connect(self._on_add_round_clicked) - def _emit_selection_changed(self, current, previous): - if not self.on_tree_selection_changed: - return - if not current: - self.on_tree_selection_changed(None) - return - self.on_tree_selection_changed({ - "type": current.data(0, ROLE_TYPE), - "id": current.data(0, ROLE_ID), - }) - - def _on_add_campaign_clicked(self): - if self.on_add_campaign: - self.on_add_campaign() - - def _on_add_round_clicked(self): - if self.on_add_round: - self.on_add_round() + def display_players(self, players: list): + table = self.playersTable + table.setRowCount(len(players)) + for row, player in enumerate(players): + table.setItem(row, 0, QtWidgets.QTableWidgetItem(player.name)) + table.setItem(row, 1, QtWidgets.QTableWidgetItem(player.id)) + table.resizeColumnsToContents() def closeEvent(self, event: QCloseEvent): if self.on_close_callback: @@ -71,51 +47,6 @@ class View(QtWidgets.QMainWindow, Ui_MainWindow): ) return Path(filename) if filename else None - def display_players(self, players: list): - table = self.playersTable - table.setRowCount(len(players)) - for row, player in enumerate(players): - table.setItem(row, 0, QtWidgets.QTableWidgetItem(player.name)) - table.setItem(row, 1, QtWidgets.QTableWidgetItem(player.id)) - table.resizeColumnsToContents() - - def display_wars(self, wars: list): - tree = self.warsTree - tree.clear() - tree.setColumnCount(1) - tree.setHeaderLabels(["Wars"]) - for war in wars: - war_item = QTreeWidgetItem([f"{war.name} ({war.year})"]) - war_item.setData(0, ROLE_TYPE, "war") - war_item.setData(0, ROLE_ID, war.id) - tree.addTopLevelItem(war_item) - for camp in war.get_all_campaigns(): - camp_item = QTreeWidgetItem([f"{camp.name} ({calendar.month_name[camp.month]})"]) - camp_item.setData(0, ROLE_TYPE, "campaign") - camp_item.setData(0, ROLE_ID, camp.id) - war_item.addChild(camp_item) - for index, rnd in enumerate(camp.get_all_rounds(), start=1): - rnd_item = QTreeWidgetItem([f"Round {index}"]) - rnd_item.setData(0, ROLE_TYPE, "round") - rnd_item.setData(0, ROLE_ID, rnd.id) - camp_item.addChild(rnd_item) - tree.expandAll() - - def get_selected_tree_item(self): - item = self.warsTree.currentItem() - if not item: - return None - return { - "type": item.data(0, ROLE_TYPE), - "id": item.data(0, ROLE_ID) - } - - def set_add_campaign_enabled(self, enabled: bool): - self.addCampaignBtn.setEnabled(enabled) - - def set_add_round_enabled(self, enabled: bool): - self.addRoundBtn.setEnabled(enabled) - class PlayerDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) @@ -124,21 +55,3 @@ class PlayerDialog(QDialog): def get_player_name(self) -> str: return self.ui.playerName.text().strip() - -class WarDialog(QDialog): - def __init__(self, parent=None): - super().__init__(parent) - self.ui = Ui_warDialog() - self.ui.setupUi(self) - - def get_war_name(self) -> str: - return self.ui.warName.text().strip() - -class CampaignDialog(QDialog): - def __init__(self, parent=None): - super().__init__(parent) - self.ui = Ui_campaignDialog() - self.ui.setupUi(self) - - def get_campaign_name(self) -> str: - return self.ui.campaignName.text().strip()