from pathlib import Path from PyQt6.QtWidgets import QMessageBox, QDialog from warchron.view.view import PlayerDialog, WarDialog class Controller: def __init__(self, model, view): self.model = model self.view = view self.current_file: Path | None = 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() def __connect(self): 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 new(self): if self.is_dirty: reply = QMessageBox.question( self.view, "Unsaved changes", "Discard current campaign?", QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No ) if reply != QMessageBox.StandardButton.Yes: return self.model.new() self.current_file = None self.is_dirty = False self.refresh_players_view() self.refresh_wars_view() self.update_window_title() def open_file(self): if self.is_dirty: reply = QMessageBox.question( self.view, "Unsaved changes", "Discard current campaign?", QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No ) if reply != QMessageBox.StandardButton.Yes: return path = self.view.ask_open_file() if not path: return self.model.load(path) self.current_file = path self.is_dirty = False self.refresh_players_view() self.refresh_wars_view() self.update_window_title() def save(self): if not self.current_file: self.save_as() return self.model.save(self.current_file) self.is_dirty = False self.update_window_title() def save_as(self): path = self.view.ask_save_file() if not path: return self.current_file = path self.model.save(path) self.is_dirty = False self.update_window_title() def update_window_title(self): base = "WarChron" if self.current_file: base += f" - {self.current_file.name}" else: base += f" - New file" if self.is_dirty: base = base + " *" self.view.setWindowTitle(base) def refresh_players_view(self): players = self.model.get_all_players() self.view.display_players(players) def add_player(self): dialog = PlayerDialog(self.view) result = dialog.exec() # modal blocking dialog if result == QDialog.DialogCode.Accepted: name = dialog.get_player_name() if not name: QMessageBox.warning( self.view, "Invalid name", "Player name cannot be empty." ) return self.model.add_player(name) self.is_dirty = True self.refresh_players_view() self.update_window_title() def refresh_wars_view(self): wars = self.model.get_all_wars() self.view.display_wars(wars) 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()