diff --git a/src/warchron/controller/controller.py b/src/warchron/controller/controller.py index 2cbd73c..8d92385 100644 --- a/src/warchron/controller/controller.py +++ b/src/warchron/controller/controller.py @@ -4,11 +4,6 @@ from pathlib import Path from PyQt6.QtWidgets import QMessageBox, QDialog from warchron.model.model import Model -from warchron.model.exception import ( - DeletionForbidden, - DeletionRequiresConfirmation, - UpdateRequiresConfirmation, -) from warchron.view.view import View from warchron.constants import ItemType, RefreshScope from warchron.controller.dtos import ( @@ -24,15 +19,17 @@ from warchron.controller.dtos import ( ChoiceDTO, BattleDTO, ) -from warchron.view.player_dialog import PlayerDialog -from warchron.view.war_dialog import WarDialog -from warchron.view.campaign_dialog import CampaignDialog -from warchron.view.objective_dialog import ObjectiveDialog -from warchron.view.war_participant_dialog import WarParticipantDialog -from warchron.view.campaign_participant_dialog import CampaignParticipantDialog -from warchron.view.sector_dialog import SectorDialog -from warchron.view.choices_dialog import ChoicesDialog -from warchron.view.battles_dialog import BattlesDialog +from warchron.view.view import ( + PlayerDialog, + WarDialog, + CampaignDialog, + ObjectiveDialog, + WarParticipantDialog, + CampaignParticipantDialog, + SectorDialog, + ChoicesDialog, + BattlesDialog, +) class Controller: @@ -367,49 +364,134 @@ class Controller: self.view.select_tree_item(item_type=item_type, item_id=item_id) def edit_item(self, item_type: str, item_id: str) -> None: - try: - if item_type == ItemType.PLAYER: - self.edit_player(item_id) + if item_type == ItemType.PLAYER: + play = self.model.get_player(item_id) + player_dialog = PlayerDialog(self.view, default_name=play.name) + if player_dialog.exec() == QDialog.DialogCode.Accepted: + name = player_dialog.get_player_name() + if not self._validate_player_inputs(name): + return + self.model.update_player(item_id, name=name) self.refresh(RefreshScope.PLAYERS_LIST) - elif item_type == ItemType.WAR: - self.edit_war(item_id) - self.refresh_and_select( - RefreshScope.WARS_TREE, item_type=ItemType.WAR, item_id=item_id - ) - elif item_type == ItemType.CAMPAIGN: - self.edit_campaign(item_id) - self.refresh_and_select( - RefreshScope.WARS_TREE, item_type=ItemType.CAMPAIGN, item_id=item_id - ) - elif item_type == ItemType.OBJECTIVE: - self.edit_objective(item_id) - self.refresh(RefreshScope.WAR_DETAILS) - elif item_type == ItemType.WAR_PARTICIPANT: - self.edit_war_participant(item_id) - self.refresh(RefreshScope.WAR_DETAILS) - elif item_type == ItemType.SECTOR: - self.edit_sector(item_id) - self.refresh(RefreshScope.CAMPAIGN_DETAILS) - elif item_type == ItemType.CAMPAIGN_PARTICIPANT: - self.edit_campaign_participant(item_id) - self.refresh(RefreshScope.CAMPAIGN_DETAILS) - elif item_type == ItemType.CHOICE: - self.edit_round_choice(item_id) - self.refresh(RefreshScope.ROUND_DETAILS) - elif item_type == ItemType.BATTLE: - self.edit_round_battle(item_id) - self.refresh(RefreshScope.ROUND_DETAILS) - self.is_dirty = True - except UpdateRequiresConfirmation as e: - reply = QMessageBox.question( - self.view, - "Confirm update", - e.message, - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + elif item_type == ItemType.WAR: + war = self.model.get_war(item_id) + war_dialog = WarDialog( + self.view, default_name=war.name, default_year=war.year ) - if reply == QMessageBox.StandardButton.Yes: - e.apply_update() + if war_dialog.exec() == QDialog.DialogCode.Accepted: + name = war_dialog.get_war_name() + year = war_dialog.get_war_year() + if not self._validate_war_inputs(name, year): + return + self.model.update_war(item_id, name=name, year=year) + self.refresh_and_select( + RefreshScope.WARS_TREE, item_type=ItemType.WAR, item_id=war.id + ) + elif item_type == ItemType.CAMPAIGN: + camp = self.model.get_campaign(item_id) + camp_dialog = CampaignDialog( + self.view, default_name=camp.name, default_month=camp.month + ) + if camp_dialog.exec() == QDialog.DialogCode.Accepted: + name = camp_dialog.get_campaign_name() + month = camp_dialog.get_campaign_month() + if not self._validate_campaign_inputs(name, month): + return + self.model.update_campaign(item_id, name=name, month=month) + self.refresh_and_select( + RefreshScope.WARS_TREE, item_type=ItemType.CAMPAIGN, item_id=camp.id + ) + elif item_type == ItemType.OBJECTIVE: + obj = self.model.get_objective(item_id) + obj_dialog = ObjectiveDialog( + self.view, default_name=obj.name, default_description=obj.description + ) + if obj_dialog.exec() == QDialog.DialogCode.Accepted: + name = obj_dialog.get_objective_name() + description = obj_dialog.get_objective_description() + if not self._validate_objective_inputs(name, description): + return + self.model.update_objective(item_id, name=name, description=description) + self.refresh(RefreshScope.WAR_DETAILS) + elif item_type == ItemType.WAR_PARTICIPANT: + war_part = self.model.get_war_participant(item_id) + player = self.model.get_player(war_part.player_id) + play_opt = ParticipantOption(id=player.id, name=player.name) + war_part_dialog = WarParticipantDialog( + self.view, + players=[play_opt], + default_player_id=war_part.id, + default_faction=war_part.faction, + editable_player=False, + ) + if war_part_dialog.exec() == QDialog.DialogCode.Accepted: + faction = war_part_dialog.get_participant_faction() + self.model.update_war_participant(item_id, faction=faction) + self.refresh(RefreshScope.WAR_DETAILS) + elif item_type == ItemType.SECTOR: + sect = self.model.get_sector(item_id) + camp = self.model.get_campaign_by_sector(item_id) + war = self.model.get_war_by_campaign(camp.id) + rounds = camp.get_all_rounds() + rnd_dto: List[RoundDTO] = [ + RoundDTO(id=rnd.id, index=i) for i, rnd in enumerate(rounds, start=1) + ] + objectives = war.get_all_objectives() + obj_dto: List[ObjectiveDTO] = [ + ObjectiveDTO(id=obj.id, name=obj.name, description=obj.description) + for obj in objectives + ] + sect_dialog = SectorDialog( + self.view, + default_name=sect.name, + rounds=rnd_dto, + default_round_id=sect.round_id, + objectives=obj_dto, + default_major_id=sect.major_objective_id, + default_minor_id=sect.minor_objective_id, + default_influence_id=sect.influence_objective_id, + ) + if sect_dialog.exec() == QDialog.DialogCode.Accepted: + name = sect_dialog.get_sector_name() + round_id = sect_dialog.get_round_id() + major_id = sect_dialog.get_major_id() + minor_id = sect_dialog.get_minor_id() + influence_id = sect_dialog.get_influence_id() + self.model.update_sector( + item_id, + name=name, + round_id=round_id, + major_id=major_id, + minor_id=minor_id, + influence_id=influence_id, + ) self.refresh(RefreshScope.CAMPAIGN_DETAILS) + elif item_type == ItemType.CAMPAIGN_PARTICIPANT: + camp_part = self.model.get_campaign_participant(item_id) + war_part = self.model.get_war_participant(camp_part.war_participant_id) + player = self.model.get_player(war_part.player_id) + part_opt = [ParticipantOption(id=player.id, name=player.name)] + camp_part_dialog = CampaignParticipantDialog( + self.view, + participants=part_opt, + default_participant_id=camp_part.id, + default_leader=camp_part.leader, + default_theme=camp_part.theme, + editable_player=False, + ) + if camp_part_dialog.exec() == QDialog.DialogCode.Accepted: + leader = camp_part_dialog.get_participant_leader() + theme = camp_part_dialog.get_participant_theme() + self.model.update_campaign_participant( + item_id, leader=leader, theme=theme + ) + self.refresh(RefreshScope.CAMPAIGN_DETAILS) + elif item_type == ItemType.CHOICE: + self.edit_round_choice(item_id) + self.refresh(RefreshScope.ROUND_DETAILS) + elif item_type == ItemType.BATTLE: + self.edit_round_battle(item_id) + self.refresh(RefreshScope.ROUND_DETAILS) def delete_item(self, item_type: str, item_id: str) -> None: reply = QMessageBox.question( @@ -420,56 +502,39 @@ class Controller: ) if reply != QMessageBox.StandardButton.Yes: return - try: - if item_type == ItemType.PLAYER: - self.model.remove_player(item_id) - self.refresh(RefreshScope.PLAYERS_LIST) - elif item_type == ItemType.WAR: - self.model.remove_war(item_id) - self.refresh(RefreshScope.WARS_TREE) - elif item_type == ItemType.CAMPAIGN: - war = self.model.get_war_by_campaign(item_id) - war_id = war.id - self.model.remove_campaign(item_id) - self.refresh_and_select( - RefreshScope.WARS_TREE, item_type=ItemType.WAR, item_id=war_id - ) - elif item_type == ItemType.OBJECTIVE: - self.model.remove_objective(item_id) - self.refresh(RefreshScope.WAR_DETAILS) - elif item_type == ItemType.WAR_PARTICIPANT: - self.model.remove_war_participant(item_id) - self.refresh(RefreshScope.WAR_DETAILS) - elif item_type == ItemType.SECTOR: - self.model.remove_sector(item_id) - self.refresh(RefreshScope.CAMPAIGN_DETAILS) - elif item_type == ItemType.CAMPAIGN_PARTICIPANT: - self.model.remove_campaign_participant(item_id) - self.refresh(RefreshScope.CAMPAIGN_DETAILS) - elif item_type == ItemType.ROUND: - camp = self.model.get_campaign_by_round(item_id) - camp_id = camp.id - self.model.remove_round(item_id) - self.refresh_and_select( - RefreshScope.WARS_TREE, item_type=ItemType.CAMPAIGN, item_id=camp_id - ) - self.is_dirty = True - except DeletionForbidden as e: - QMessageBox.warning( - self.view, - "Deletion forbidden", - e.reason, + if item_type == ItemType.PLAYER: + self.model.remove_player(item_id) + self.refresh(RefreshScope.PLAYERS_LIST) + elif item_type == ItemType.WAR: + self.model.remove_war(item_id) + self.refresh(RefreshScope.WARS_TREE) + elif item_type == ItemType.CAMPAIGN: + war = self.model.get_war_by_campaign(item_id) + war_id = war.id + self.model.remove_campaign(item_id) + self.refresh_and_select( + RefreshScope.WARS_TREE, item_type=ItemType.WAR, item_id=war_id ) - except DeletionRequiresConfirmation as e: - reply = QMessageBox.question( - self.view, - "Confirm deletion", - e.message, - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + elif item_type == ItemType.OBJECTIVE: + self.model.remove_objective(item_id) + self.refresh(RefreshScope.WAR_DETAILS) + elif item_type == ItemType.WAR_PARTICIPANT: + self.model.remove_war_participant(item_id) + self.refresh(RefreshScope.WAR_DETAILS) + elif item_type == ItemType.SECTOR: + self.model.remove_sector(item_id) + self.refresh(RefreshScope.CAMPAIGN_DETAILS) + elif item_type == ItemType.CAMPAIGN_PARTICIPANT: + self.model.remove_campaign_participant(item_id) + self.refresh(RefreshScope.CAMPAIGN_DETAILS) + elif item_type == ItemType.ROUND: + camp = self.model.get_campaign_by_round(item_id) + camp_id = camp.id + self.model.remove_round(item_id) + self.refresh_and_select( + RefreshScope.WARS_TREE, item_type=ItemType.CAMPAIGN, item_id=camp_id ) - if reply == QMessageBox.StandardButton.Yes: - e.cleanup_action() - self.refresh(RefreshScope.CAMPAIGN_DETAILS) + self.is_dirty = True # Player methods @@ -492,15 +557,6 @@ class Controller: self.is_dirty = True self.refresh(RefreshScope.PLAYERS_LIST) - def edit_player(self, player_id: str) -> None: - play = self.model.get_player(player_id) - player_dialog = PlayerDialog(self.view, default_name=play.name) - if player_dialog.exec() == QDialog.DialogCode.Accepted: - name = player_dialog.get_player_name() - if not self._validate_player_inputs(name): - return - self.model.update_player(player_id, name=name) - # War methods def _validate_war_inputs(self, name: str, year: int) -> bool: @@ -530,16 +586,6 @@ class Controller: RefreshScope.WARS_TREE, item_type=ItemType.WAR, item_id=war.id ) - def edit_war(self, war_id: str) -> None: - war = self.model.get_war(war_id) - war_dialog = WarDialog(self.view, default_name=war.name, default_year=war.year) - if war_dialog.exec() == QDialog.DialogCode.Accepted: - name = war_dialog.get_war_name() - year = war_dialog.get_war_year() - if not self._validate_war_inputs(name, year): - return - self.model.update_war(war_id, name=name, year=year) - # Objective methods def _validate_objective_inputs(self, name: str, description: str) -> bool: @@ -564,20 +610,6 @@ class Controller: self.is_dirty = True self.refresh(RefreshScope.WAR_DETAILS) - def edit_objective(self, objective_id: str) -> None: - obj = self.model.get_objective(objective_id) - obj_dialog = ObjectiveDialog( - self.view, default_name=obj.name, default_description=obj.description - ) - if obj_dialog.exec() == QDialog.DialogCode.Accepted: - name = obj_dialog.get_objective_name() - description = obj_dialog.get_objective_description() - if not self._validate_objective_inputs(name, description): - return - self.model.update_objective( - objective_id, name=name, description=description - ) - # War participant methods def add_war_participant(self) -> None: @@ -598,21 +630,6 @@ class Controller: self.is_dirty = True self.refresh(RefreshScope.WAR_DETAILS) - def edit_war_participant(self, participant_id: str) -> None: - war_part = self.model.get_war_participant(participant_id) - player = self.model.get_player(war_part.player_id) - play_opt = ParticipantOption(id=player.id, name=player.name) - war_part_dialog = WarParticipantDialog( - self.view, - players=[play_opt], - default_player_id=war_part.id, - default_faction=war_part.faction, - editable_player=False, - ) - if war_part_dialog.exec() == QDialog.DialogCode.Accepted: - faction = war_part_dialog.get_participant_faction() - self.model.update_war_participant(participant_id, faction=faction) - # Campaign methods def _validate_campaign_inputs(self, name: str, month: int) -> bool: @@ -649,18 +666,6 @@ class Controller: RefreshScope.WARS_TREE, item_type=ItemType.CAMPAIGN, item_id=camp.id ) - def edit_campaign(self, campaign_id: str) -> None: - camp = self.model.get_campaign(campaign_id) - camp_dialog = CampaignDialog( - self.view, default_name=camp.name, default_month=camp.month - ) - if camp_dialog.exec() == QDialog.DialogCode.Accepted: - name = camp_dialog.get_campaign_name() - month = camp_dialog.get_campaign_month() - if not self._validate_campaign_inputs(name, month): - return - self.model.update_campaign(campaign_id, name=name, month=month) - # Campaign participant methods def add_campaign_participant(self) -> None: @@ -687,26 +692,6 @@ class Controller: self.is_dirty = True self.refresh(RefreshScope.CAMPAIGN_DETAILS) - def edit_campaign_participant(self, participant_id: str) -> None: - camp_part = self.model.get_campaign_participant(participant_id) - war_part = self.model.get_war_participant(camp_part.war_participant_id) - player = self.model.get_player(war_part.player_id) - part_opt = [ParticipantOption(id=player.id, name=player.name)] - camp_part_dialog = CampaignParticipantDialog( - self.view, - participants=part_opt, - default_participant_id=camp_part.id, - default_leader=camp_part.leader, - default_theme=camp_part.theme, - editable_player=False, - ) - if camp_part_dialog.exec() == QDialog.DialogCode.Accepted: - leader = camp_part_dialog.get_participant_leader() - theme = camp_part_dialog.get_participant_theme() - self.model.update_campaign_participant( - participant_id, leader=leader, theme=theme - ) - # Sector methods def _validate_sector_inputs( @@ -755,44 +740,6 @@ class Controller: self.is_dirty = True self.refresh(RefreshScope.CAMPAIGN_DETAILS) - def edit_sector(self, sector_id: str) -> None: - sect = self.model.get_sector(sector_id) - camp = self.model.get_campaign_by_sector(sector_id) - war = self.model.get_war_by_campaign(camp.id) - rounds = camp.get_all_rounds() - rnd_dto: List[RoundDTO] = [ - RoundDTO(id=rnd.id, index=i) for i, rnd in enumerate(rounds, start=1) - ] - objectives = war.get_all_objectives() - obj_dto: List[ObjectiveDTO] = [ - ObjectiveDTO(id=obj.id, name=obj.name, description=obj.description) - for obj in objectives - ] - sect_dialog = SectorDialog( - self.view, - default_name=sect.name, - rounds=rnd_dto, - default_round_id=sect.round_id, - objectives=obj_dto, - default_major_id=sect.major_objective_id, - default_minor_id=sect.minor_objective_id, - default_influence_id=sect.influence_objective_id, - ) - if sect_dialog.exec() == QDialog.DialogCode.Accepted: - name = sect_dialog.get_sector_name() - round_id = sect_dialog.get_round_id() - major_id = sect_dialog.get_major_id() - minor_id = sect_dialog.get_minor_id() - influence_id = sect_dialog.get_influence_id() - self.model.update_sector( - sector_id, - name=name, - round_id=round_id, - major_id=major_id, - minor_id=minor_id, - influence_id=influence_id, - ) - # Round methods def add_round(self) -> None: diff --git a/src/warchron/model/battle.py b/src/warchron/model/battle.py deleted file mode 100644 index 04a24c7..0000000 --- a/src/warchron/model/battle.py +++ /dev/null @@ -1,35 +0,0 @@ -class Battle: - def __init__( - self, - sector_id: str, - player_1_id: str | None = None, - player_2_id: str | None = None, - ): - self.sector_id: str = sector_id # ref to Campaign.sector - self.player_1_id: str | None = player_1_id # ref to Campaign.participants - self.player_2_id: str | None = player_2_id # ref to Campaign.participants - self.winner_id: str | None = None - self.score: str | None = None - self.victory_condition: str | None = None - self.comment: str | None = None - - def set_id(self, new_id: str) -> None: - self.sector_id = new_id - - def set_player_1(self, new_player_id: str | None) -> None: - self.player_1_id = new_player_id - - def set_player_2(self, new_player_id: str | None) -> None: - self.player_2_id = new_player_id - - def set_winner(self, new_player_id: str | None) -> None: - self.winner_id = new_player_id - - def set_score(self, new_score: str | None) -> None: - self.score = new_score - - def set_victory_condition(self, new_victory_condition: str | None) -> None: - self.victory_condition = new_victory_condition - - def set_comment(self, new_comment: str | None) -> None: - self.comment = new_comment diff --git a/src/warchron/model/campaign.py b/src/warchron/model/campaign.py index 7adc7f2..bf3431e 100644 --- a/src/warchron/model/campaign.py +++ b/src/warchron/model/campaign.py @@ -2,15 +2,7 @@ from __future__ import annotations from uuid import uuid4 from typing import Any, Dict, List -from warchron.model.exception import ( - DeletionRequiresConfirmation, - UpdateRequiresConfirmation, -) -from warchron.model.campaign_participant import CampaignParticipant -from warchron.model.sector import Sector -from warchron.model.round import Round -from warchron.model.choice import Choice -from warchron.model.battle import Battle +from warchron.model.round import Round, Choice, Battle class Campaign: @@ -98,47 +90,12 @@ class Campaign: part.set_theme(theme) def remove_campaign_participant(self, participant_id: str) -> None: - rounds_blocking: list[Round] = [] - for rnd in self.rounds: - if rnd.has_choice_with_participant( - participant_id - ) or rnd.has_battle_with_participant(participant_id): - rounds_blocking.append(rnd) - if not rounds_blocking: - del self.participants[participant_id] - return - - def cleanup() -> None: - for rnd in rounds_blocking: - rnd.clear_participant_references(participant_id) - rnd.remove_choice(participant_id) - del self.participants[participant_id] - - rounds_str = ", ".join( - str(self.get_round_index(rnd.id)) for rnd in rounds_blocking - ) - raise DeletionRequiresConfirmation( - message=( - f"This participant is used in round(s): {rounds_str}.\n" - "Related choices and battles will be cleared.\n" - "Do you want to continue?" - ), - cleanup_action=cleanup, - ) + # TODO manage choices referring to it + # TODO manage battles referring to it + del self.participants[participant_id] # Sector methods - def has_sector(self, sector_id: str) -> bool: - return sector_id in self.sectors - - def has_sector_with_objective(self, objective_id: str) -> bool: - return any( - sect.major_objective_id == objective_id - or sect.minor_objective_id == objective_id - or sect.influence_objective_id == objective_id - for sect in self.sectors.values() - ) - def add_sector( self, name: str, round_id: str, major_id: str, minor_id: str, influence_id: str ) -> Sector: @@ -169,75 +126,16 @@ class Campaign: influence_id: str, ) -> None: sect = self.get_sector(sector_id) - old_round_id = sect.round_id - - def apply_update() -> None: - sect.set_name(name) - sect.set_round(round_id) - sect.set_major(major_id) - sect.set_minor(minor_id) - sect.set_influence(influence_id) - - if old_round_id == round_id: - apply_update() - return - affected_rounds: list[Round] = [] - for rnd in self.rounds: - if rnd.id == old_round_id and ( - rnd.has_choice_with_sector(sector_id) - or rnd.has_battle_with_sector(sector_id) - ): - affected_rounds.append(rnd) - if not affected_rounds: - apply_update() - return - - def cleanup_and_update() -> None: - for rnd in affected_rounds: - rnd.clear_sector_references(sector_id) - rnd.remove_battle(sector_id) - apply_update() - - rounds_str = ", ".join( - str(self.get_round_index(rnd.id)) for rnd in affected_rounds - ) - raise UpdateRequiresConfirmation( - message=( - f"Changing the round of this sector will affect round(s): {rounds_str}." - "\nRelated battles and choices will be cleared.\n" - "Do you want to continue?" - ), - apply_update=cleanup_and_update, - ) + sect.set_name(name) + sect.set_round(round_id) + sect.set_major(major_id) + sect.set_minor(minor_id) + sect.set_influence(influence_id) def remove_sector(self, sector_id: str) -> None: - rounds_blocking: list[Round] = [] - for rnd in self.rounds: - if rnd.has_battle_with_sector(sector_id) or rnd.has_choice_with_sector( - sector_id - ): - rounds_blocking.append(rnd) - if not rounds_blocking: - del self.sectors[sector_id] - return - - def cleanup() -> None: - for rnd in rounds_blocking: - rnd.clear_sector_references(sector_id) - rnd.remove_battle(sector_id) - del self.sectors[sector_id] - - rounds_str = ", ".join( - str(self.get_round_index(rnd.id)) for rnd in rounds_blocking - ) - raise DeletionRequiresConfirmation( - message=( - f"This sector is used in round(s): {rounds_str}.\n" - "Battles and choices using this sector will be cleared.\n" - "Do you want to continue?" - ), - cleanup_action=cleanup, - ) + # TODO manage choices referring to it + # TODO manage battles referring to it + del self.sectors[sector_id] def get_sectors_in_round(self, round_id: str) -> List[Sector]: sectors = [s for s in self.sectors.values() if s.round_id == round_id] @@ -329,3 +227,62 @@ class Campaign: def remove_battle(self, round_id: str, sector_id: str) -> None: rnd = self.get_round(round_id) rnd.remove_battle(sector_id) + + +class CampaignParticipant: + def __init__( + self, *, war_participant_id: str, leader: str | None, theme: str | None + ): + self.id: str = str(uuid4()) + self.war_participant_id: str = war_participant_id # ref to War.participants + self.leader: str | None = leader + self.theme: str | None = theme + + def set_id(self, new_id: str) -> None: + self.id = new_id + + def set_war_participant(self, new_participant: str) -> None: + self.war_participant_id = new_participant + + def set_leader(self, new_faction: str) -> None: + self.leader = new_faction + + def set_theme(self, new_theme: str) -> None: + self.theme = new_theme + + +class Sector: + def __init__( + self, + name: str, + round_id: str, + major_id: str | None, + minor_id: str | None, + influence_id: str | None, + ): + self.id: str = str(uuid4()) + self.name: str = name + self.round_id: str = round_id + self.major_objective_id: str | None = major_id # ref to War.objectives + self.minor_objective_id: str | None = minor_id # ref to War.objectives + self.influence_objective_id: str | None = influence_id # ref to War.objectives + self.mission: str | None = None + self.description: str | None = None + + def set_id(self, new_id: str) -> None: + self.id = new_id + + def set_name(self, new_name: str) -> None: + self.name = new_name + + def set_round(self, new_round_id: str) -> None: + self.round_id = new_round_id + + def set_major(self, new_major_id: str) -> None: + self.major_objective_id = new_major_id + + def set_minor(self, new_minor_id: str) -> None: + self.minor_objective_id = new_minor_id + + def set_influence(self, new_influence_id: str) -> None: + self.influence_objective_id = new_influence_id diff --git a/src/warchron/model/campaign_participant.py b/src/warchron/model/campaign_participant.py deleted file mode 100644 index aa98528..0000000 --- a/src/warchron/model/campaign_participant.py +++ /dev/null @@ -1,24 +0,0 @@ -from __future__ import annotations -from uuid import uuid4 - - -class CampaignParticipant: - def __init__( - self, *, war_participant_id: str, leader: str | None, theme: str | None - ): - self.id: str = str(uuid4()) - self.war_participant_id: str = war_participant_id # ref to War.participants - self.leader: str | None = leader - self.theme: str | None = theme - - def set_id(self, new_id: str) -> None: - self.id = new_id - - def set_war_participant(self, new_participant: str) -> None: - self.war_participant_id = new_participant - - def set_leader(self, new_faction: str) -> None: - self.leader = new_faction - - def set_theme(self, new_theme: str) -> None: - self.theme = new_theme diff --git a/src/warchron/model/choice.py b/src/warchron/model/choice.py deleted file mode 100644 index d49ec66..0000000 --- a/src/warchron/model/choice.py +++ /dev/null @@ -1,27 +0,0 @@ -class Choice: - def __init__( - self, - participant_id: str, - priority_sector_id: str | None = None, - secondary_sector_id: str | None = None, - ): - self.participant_id: str = participant_id # ref to Campaign.participants - self.priority_sector_id: str | None = ( - priority_sector_id # ref to Campaign.sectors - ) - self.secondary_sector_id: str | None = ( - secondary_sector_id # ref to Campaign.sectors - ) - self.comment: str | None = None - - def set_id(self, new_id: str) -> None: - self.participant_id = new_id - - def set_priority(self, new_priority_id: str | None) -> None: - self.priority_sector_id = new_priority_id - - def set_secondary(self, new_secondary_id: str | None) -> None: - self.secondary_sector_id = new_secondary_id - - def set_comment(self, new_comment: str | None) -> None: - self.comment = new_comment diff --git a/src/warchron/model/exception.py b/src/warchron/model/exception.py deleted file mode 100644 index be14e13..0000000 --- a/src/warchron/model/exception.py +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Callable - - -class DeletionForbidden(Exception): - def __init__(self, reason: str): - self.reason = reason - super().__init__(reason) - - -class DeletionRequiresConfirmation(Exception): - def __init__( - self, - message: str, - *, - cleanup_action: Callable[[], None], - ): - self.message = message - self.cleanup_action = cleanup_action - super().__init__(message) - - -class UpdateRequiresConfirmation(Exception): - def __init__( - self, - message: str, - *, - apply_update: Callable[[], None], - ): - self.message = message - self.apply_update = apply_update - super().__init__(message) diff --git a/src/warchron/model/model.py b/src/warchron/model/model.py index 1f448b3..1a17563 100644 --- a/src/warchron/model/model.py +++ b/src/warchron/model/model.py @@ -4,17 +4,10 @@ import json import shutil from datetime import datetime -from warchron.model.exception import DeletionForbidden from warchron.model.player import Player -from warchron.model.war import War -from warchron.model.war_participant import WarParticipant -from warchron.model.objective import Objective -from warchron.model.campaign import Campaign -from warchron.model.campaign_participant import CampaignParticipant -from warchron.model.sector import Sector -from warchron.model.round import Round -from warchron.model.choice import Choice -from warchron.model.battle import Battle +from warchron.model.war import War, Objective, WarParticipant +from warchron.model.campaign import Campaign, Sector, CampaignParticipant +from warchron.model.round import Round, Choice, Battle class Model: @@ -85,16 +78,7 @@ class Model: return list(self.players.values()) def remove_player(self, player_id: str) -> None: - wars_using_player: List[str] = [] - for war in self.wars.values(): - if war.has_player(player_id): - wars_using_player.append(war.name) - if wars_using_player: - wars_str = ", ".join(wars_using_player) - raise DeletionForbidden( - f"This player is participating in war(s): {wars_str}.\n" - "Remove it from participants first." - ) + # TODO manage war_participants referring to it del self.players[player_id] # War methods @@ -110,7 +94,6 @@ class Model: def get_war(self, id: str) -> War: return self.wars[id] - # TODO replace multiloops by internal has_* method def get_war_by_campaign(self, campaign_id: str) -> War: for war in self.wars.values(): for camp in war.campaigns: @@ -118,7 +101,6 @@ class Model: return war raise KeyError(f"Campaign {campaign_id} not found in any War") - # TODO replace multiloops by internal has_* method def get_war_by_sector(self, sector_id: str) -> War: for war in self.wars.values(): for camp in war.campaigns: @@ -127,7 +109,6 @@ class Model: return war raise KeyError(f"Sector {sector_id} not found in any War") - # TODO replace multiloops by internal has_* method def get_war_by_round(self, round_id: str) -> War: for war in self.wars.values(): for camp in war.campaigns: @@ -136,7 +117,6 @@ class Model: return war raise KeyError(f"Round {round_id} not found in any War") - # TODO replace multiloops by internal has_* method def get_war_by_objective(self, objective_id: str) -> War: for war in self.wars.values(): for obj in war.objectives.values(): @@ -174,7 +154,6 @@ class Model: war = self.get_war(war_id) return war.add_objective(name, description) - # TODO replace multiloops by internal has_* method def get_objective(self, objective_id: str) -> Objective: for war in self.wars.values(): for obj in war.objectives.values(): @@ -206,7 +185,6 @@ class Model: war = self.get_war(war_id) return war.add_war_participant(player_id, faction) - # TODO replace multiloops by internal has_* method def get_war_participant(self, participant_id: str) -> WarParticipant: for war in self.wars.values(): for part in war.participants.values(): @@ -235,7 +213,6 @@ class Model: war = self.get_war(war_id) return war.add_campaign(name, month) - # TODO replace multiloops by internal has_* method def get_campaign(self, campaign_id: str) -> Campaign: for war in self.wars.values(): for campaign in war.campaigns: @@ -286,7 +263,6 @@ class Model: camp = self.get_campaign(campaign_id) return camp.add_sector(name, round_id, major_id, minor_id, influence_id) - # TODO replace multiloops by internal has_* method def get_sector(self, sector_id: str) -> Sector: for war in self.wars.values(): for camp in war.campaigns: @@ -336,7 +312,6 @@ class Model: war_part = war.get_war_participant(participant_id) return self.players[war_part.player_id].name - # TODO replace multiloops by internal has_* method def get_campaign_participant(self, participant_id: str) -> CampaignParticipant: for war in self.wars.values(): for camp in war.campaigns: @@ -368,10 +343,9 @@ class Model: # Round methods def add_round(self, campaign_id: str) -> Round: - war = self.get_war_by_campaign(campaign_id) - return war.add_round(campaign_id) + camp = self.get_campaign(campaign_id) + return camp.add_round() - # TODO replace multiloops by internal has_* method def get_round(self, round_id: str) -> Round: for war in self.wars.values(): for camp in war.campaigns: diff --git a/src/warchron/model/objective.py b/src/warchron/model/objective.py index d3e5d76..e69de29 100644 --- a/src/warchron/model/objective.py +++ b/src/warchron/model/objective.py @@ -1,18 +0,0 @@ -from __future__ import annotations -from uuid import uuid4 - - -class Objective: - def __init__(self, name: str, description: str): - self.id: str = str(uuid4()) - self.name: str = name - self.description: str = description - - def set_id(self, new_id: str) -> None: - self.id = new_id - - def set_name(self, new_name: str) -> None: - self.name = new_name - - def set_description(self, new_description: str) -> None: - self.description = new_description diff --git a/src/warchron/model/round.py b/src/warchron/model/round.py index 2460d4c..420eea8 100644 --- a/src/warchron/model/round.py +++ b/src/warchron/model/round.py @@ -2,9 +2,6 @@ from __future__ import annotations from uuid import uuid4 from typing import Any, Dict -from warchron.model.choice import Choice -from warchron.model.battle import Battle - class Round: def __init__(self) -> None: @@ -43,18 +40,6 @@ class Round: def get_choice(self, participant_id: str) -> Choice | None: return self.choices.get(participant_id) - def has_choice_with_sector(self, sector_id: str) -> bool: - return any( - choice.priority_sector_id == sector_id - or choice.secondary_sector_id == sector_id - for choice in self.choices.values() - ) - - def has_choice_with_participant(self, participant_id: str) -> bool: - return any( - choice.participant_id == participant_id for choice in self.choices.values() - ) - def create_choice(self, participant_id: str) -> Choice: if participant_id not in self.choices: choice = Choice( @@ -78,13 +63,6 @@ class Round: choice.set_secondary(secondary_sector_id) choice.set_comment(comment) - def clear_sector_references(self, sector_id: str) -> None: - for choice in self.choices.values(): - if choice.priority_sector_id == sector_id: - choice.priority_sector_id = None - if choice.secondary_sector_id == sector_id: - choice.secondary_sector_id = None - def remove_choice(self, participant_id: str) -> None: del self.choices[participant_id] @@ -93,15 +71,6 @@ class Round: def get_battle(self, sector_id: str) -> Battle | None: return self.battles.get(sector_id) - def has_battle_with_sector(self, sector_id: str) -> bool: - return any(bat.sector_id == sector_id for bat in self.battles.values()) - - def has_battle_with_participant(self, participant_id: str) -> bool: - return any( - bat.player_1_id == participant_id or bat.player_2_id == participant_id - for bat in self.battles.values() - ) - def create_battle(self, sector_id: str) -> Battle: if sector_id not in self.battles: battle = Battle(sector_id=sector_id, player_1_id=None, player_2_id=None) @@ -127,14 +96,71 @@ class Round: bat.set_victory_condition(victory_condition) bat.set_comment(comment) - def clear_participant_references(self, participant_id: str) -> None: - for battle in self.battles.values(): - if battle.player_1_id == participant_id: - battle.player_1_id = None - if battle.player_2_id == participant_id: - battle.player_2_id = None - if battle.winner_id == participant_id: - battle.winner_id = None - def remove_battle(self, sector_id: str) -> None: del self.battles[sector_id] + + +class Choice: + def __init__( + self, + participant_id: str, + priority_sector_id: str | None = None, + secondary_sector_id: str | None = None, + ): + self.participant_id: str = participant_id # ref to Campaign.participants + self.priority_sector_id: str | None = ( + priority_sector_id # ref to Campaign.sectors + ) + self.secondary_sector_id: str | None = ( + secondary_sector_id # ref to Campaign.sectors + ) + self.comment: str | None = None + + def set_id(self, new_id: str) -> None: + self.participant_id = new_id + + def set_priority(self, new_priority_id: str | None) -> None: + self.priority_sector_id = new_priority_id + + def set_secondary(self, new_secondary_id: str | None) -> None: + self.secondary_sector_id = new_secondary_id + + def set_comment(self, new_comment: str | None) -> None: + self.comment = new_comment + + +class Battle: + def __init__( + self, + sector_id: str, + player_1_id: str | None = None, + player_2_id: str | None = None, + ): + self.sector_id: str = sector_id # ref to Campaign.sector + self.player_1_id: str | None = player_1_id # ref to Campaign.participants + self.player_2_id: str | None = player_2_id # ref to Campaign.participants + self.winner_id: str | None = None + self.score: str | None = None + self.victory_condition: str | None = None + self.comment: str | None = None + + def set_id(self, new_id: str) -> None: + self.sector_id = new_id + + def set_player_1(self, new_player_id: str | None) -> None: + self.player_1_id = new_player_id + + def set_player_2(self, new_player_id: str | None) -> None: + self.player_2_id = new_player_id + + def set_winner(self, new_player_id: str | None) -> None: + self.winner_id = new_player_id + + def set_score(self, new_score: str | None) -> None: + self.score = new_score + + def set_victory_condition(self, new_victory_condition: str | None) -> None: + self.victory_condition = new_victory_condition + + def set_comment(self, new_comment: str | None) -> None: + self.comment = new_comment diff --git a/src/warchron/model/sector.py b/src/warchron/model/sector.py deleted file mode 100644 index 47cb4a8..0000000 --- a/src/warchron/model/sector.py +++ /dev/null @@ -1,39 +0,0 @@ -from __future__ import annotations -from uuid import uuid4 - - -class Sector: - def __init__( - self, - name: str, - round_id: str, - major_id: str | None, - minor_id: str | None, - influence_id: str | None, - ): - self.id: str = str(uuid4()) - self.name: str = name - self.round_id: str = round_id - self.major_objective_id: str | None = major_id # ref to War.objectives - self.minor_objective_id: str | None = minor_id # ref to War.objectives - self.influence_objective_id: str | None = influence_id # ref to War.objectives - self.mission: str | None = None - self.description: str | None = None - - def set_id(self, new_id: str) -> None: - self.id = new_id - - def set_name(self, new_name: str) -> None: - self.name = new_name - - def set_round(self, new_round_id: str) -> None: - self.round_id = new_round_id - - def set_major(self, new_major_id: str) -> None: - self.major_objective_id = new_major_id - - def set_minor(self, new_minor_id: str) -> None: - self.minor_objective_id = new_minor_id - - def set_influence(self, new_influence_id: str) -> None: - self.influence_objective_id = new_influence_id diff --git a/src/warchron/model/war.py b/src/warchron/model/war.py index 892edeb..70cf6f4 100644 --- a/src/warchron/model/war.py +++ b/src/warchron/model/war.py @@ -3,15 +3,8 @@ from uuid import uuid4 from datetime import datetime from typing import Any, Dict, List -from warchron.model.exception import DeletionForbidden -from warchron.model.war_participant import WarParticipant -from warchron.model.objective import Objective -from warchron.model.campaign_participant import CampaignParticipant -from warchron.model.sector import Sector -from warchron.model.campaign import Campaign -from warchron.model.round import Round -from warchron.model.choice import Choice -from warchron.model.battle import Battle +from warchron.model.campaign import Campaign, Sector, CampaignParticipant +from warchron.model.round import Round, Choice, Battle class War: @@ -83,16 +76,7 @@ class War: obj.set_description(description) def remove_objective(self, objective_id: str) -> None: - camp_using_obj: List[str] = [] - for camp in self.campaigns: - if camp.has_sector_with_objective(objective_id): - camp_using_obj.append(camp.name) - if camp_using_obj: - camps_str = ", ".join(camp_using_obj) - raise DeletionForbidden( - f"This objective is used in campaign(s) sector(s): {camps_str}.\n" - "Remove it from campaign(s) first." - ) + # TODO manage sectors referring to it del self.objectives[objective_id] # War participant methods @@ -119,23 +103,14 @@ class War: def get_all_war_participants(self) -> List[WarParticipant]: return list(self.participants.values()) - def update_war_participant(self, participant_id: str, *, faction: str) -> None: - part = self.get_war_participant(participant_id) + def update_war_participant(self, player_id: str, *, faction: str) -> None: + part = self.get_war_participant(player_id) # Can't change referred Model.players part.set_faction(faction) - def remove_war_participant(self, participant_id: str) -> None: - camp_using_part: List[str] = [] - for camp in self.campaigns: - if camp.has_war_participant(participant_id): - camp_using_part.append(camp.name) - if camp_using_part: - camps_str = ", ".join(camp_using_part) - raise DeletionForbidden( - f"This war participant is used in campaign(s): {camps_str}.\n" - "Remove it from campaign(s) first." - ) - del self.participants[participant_id] + def remove_war_participant(self, player_id: str) -> None: + # TODO manage campaign_participants referring to it + del self.participants[player_id] # Campaign methods @@ -158,15 +133,13 @@ class War: return camp raise KeyError(f"Campaign {campaign_id} not found in War {self.id}") - # TODO replace multiloops by internal has_* method - def get_campaign_by_round(self, round_id: str) -> Campaign | None: + def get_campaign_by_round(self, round_id: str) -> Campaign: for camp in self.campaigns: for rnd in camp.rounds: if rnd.id == round_id: return camp - return None + raise KeyError(f"Round {round_id} not found in any Campaign") - # TODO replace multiloops by internal has_* method def get_campaign_by_sector(self, sector_id: str) -> Campaign: for camp in self.campaigns: for sect in camp.sectors.values(): @@ -206,7 +179,6 @@ class War: camp = self.get_campaign(campaign_id) return camp.add_sector(name, round_id, major_id, minor_id, influence_id) - # TODO replace multiloops by internal has_* method def get_sector(self, sector_id: str) -> Sector: for camp in self.campaigns: for sect in camp.sectors.values(): @@ -254,7 +226,6 @@ class War: camp = self.get_campaign(campaign_id) return camp.add_campaign_participant(participant_id, leader, theme) - # TODO replace multiloops by internal has_* method def get_campaign_participant(self, participant_id: str) -> CampaignParticipant: for camp in self.campaigns: for part in camp.participants.values(): @@ -278,18 +249,19 @@ class War: camp = self.get_campaign(campaign_id) return camp.add_round() + def add_battle(self, campaign_id: str) -> Round: + camp = self.get_campaign(campaign_id) + return camp.add_round() + def remove_round(self, round_id: str) -> None: camp = self.get_campaign_by_round(round_id) - if camp is not None: - camp.remove_round(round_id) + camp.remove_round(round_id) # Choice methods def create_choice(self, round_id: str, participant_id: str) -> Choice: camp = self.get_campaign_by_round(round_id) - if camp is not None: - return camp.create_choice(round_id, participant_id) - raise KeyError("Campaign with round {round_id} doesn't exist") + return camp.create_choice(round_id, participant_id) def update_choice( self, @@ -300,27 +272,19 @@ class War: comment: str | None, ) -> None: camp = self.get_campaign_by_round(round_id) - if camp is not None: - camp.update_choice( - round_id, - participant_id, - priority_sector_id, - secondary_sector_id, - comment, - ) + camp.update_choice( + round_id, participant_id, priority_sector_id, secondary_sector_id, comment + ) def remove_choice(self, round_id: str, participant_id: str) -> None: camp = self.get_campaign_by_round(round_id) - if camp is not None: - camp.remove_choice(round_id, participant_id) + camp.remove_choice(round_id, participant_id) # Battle methods def create_battle(self, round_id: str, sector_id: str) -> Battle: camp = self.get_campaign_by_round(round_id) - if camp is not None: - return camp.create_battle(round_id, sector_id) - raise KeyError("Campaign with round {round_id} doesn't exist") + return camp.create_battle(round_id, sector_id) def update_battle( self, @@ -334,19 +298,49 @@ class War: comment: str | None, ) -> None: camp = self.get_campaign_by_round(round_id) - if camp is not None: - camp.update_battle( - round_id, - sector_id, - player_1_id, - player_2_id, - winner_id, - score, - victory_condition, - comment, - ) + camp.update_battle( + round_id, + sector_id, + player_1_id, + player_2_id, + winner_id, + score, + victory_condition, + comment, + ) def remove_battle(self, round_id: str, sector_id: str) -> None: camp = self.get_campaign_by_round(round_id) - if camp is not None: - camp.remove_battle(round_id, sector_id) + camp.remove_battle(round_id, sector_id) + + +class Objective: + def __init__(self, name: str, description: str): + self.id: str = str(uuid4()) + self.name: str = name + self.description: str = description + + def set_id(self, new_id: str) -> None: + self.id = new_id + + def set_name(self, new_name: str) -> None: + self.name = new_name + + def set_description(self, new_description: str) -> None: + self.description = new_description + + +class WarParticipant: + def __init__(self, *, player_id: str, faction: str): + self.id: str = str(uuid4()) + self.player_id: str = player_id # ref to WarModel.players + self.faction: str = faction + + def set_id(self, new_id: str) -> None: + self.id = new_id + + def set_player(self, new_player: str) -> None: + self.player_id = new_player + + def set_faction(self, new_faction: str) -> None: + self.faction = new_faction diff --git a/src/warchron/model/war_participant.py b/src/warchron/model/war_participant.py index 4b405f0..e69de29 100644 --- a/src/warchron/model/war_participant.py +++ b/src/warchron/model/war_participant.py @@ -1,18 +0,0 @@ -from __future__ import annotations -from uuid import uuid4 - - -class WarParticipant: - def __init__(self, *, player_id: str, faction: str): - self.id: str = str(uuid4()) - self.player_id: str = player_id # ref to WarModel.players - self.faction: str = faction - - def set_id(self, new_id: str) -> None: - self.id = new_id - - def set_player(self, new_player: str) -> None: - self.player_id = new_player - - def set_faction(self, new_faction: str) -> None: - self.faction = new_faction diff --git a/src/warchron/view/battles_dialog.py b/src/warchron/view/battles_dialog.py deleted file mode 100644 index 2ef86a0..0000000 --- a/src/warchron/view/battles_dialog.py +++ /dev/null @@ -1,68 +0,0 @@ -from typing import cast, List - -from PyQt6.QtWidgets import QWidget, QDialog - -from warchron.controller.dtos import ParticipantOption, SectorDTO -from warchron.view.helpers import select_if_exists -from warchron.view.ui.ui_battle_result_dialog import Ui_battleResultDialog - - -class BattlesDialog(QDialog): - def __init__( - self, - parent: QWidget | None = None, - *, - sectors: List[SectorDTO], - default_sector_id: str | None = None, - players: List[ParticipantOption], - default_player_1_id: str | None = None, - default_player_2_id: str | None = None, - default_winner_id: str | None = None, - default_score: str | None = None, - default_victory_condition: str | None = None, - default_comment: str | None = None, - ) -> None: - super().__init__(parent) - self.ui: Ui_battleResultDialog = Ui_battleResultDialog() - self.ui.setupUi(self) # type: ignore - for sect in sectors: - self.ui.sectorComboBox.addItem(sect.name, sect.id) - select_if_exists(self.ui.sectorComboBox, default_sector_id) - self.ui.sectorComboBox.setEnabled(False) - - self.ui.player1ComboBox.addItem("(none)", None) - self.ui.player2ComboBox.addItem("(none)", None) - for play in players: - self.ui.player1ComboBox.addItem(play.name, play.id) - self.ui.player2ComboBox.addItem(play.name, play.id) - select_if_exists(self.ui.player1ComboBox, default_player_1_id) - select_if_exists(self.ui.player2ComboBox, default_player_2_id) - self.ui.winnerComboBox.addItem("(none)", None) - for play in players: - if play.id in (default_player_1_id, default_player_2_id): - self.ui.winnerComboBox.addItem(play.name, play.id) - select_if_exists(self.ui.winnerComboBox, default_winner_id) - self.ui.score.setText(default_score) - self.ui.victoryCondition.setText(default_victory_condition) - self.ui.battleComment.setPlainText(default_comment) - - def get_sector_id(self) -> str: - return cast(str, self.ui.sectorComboBox.currentData()) - - def get_player_1_id(self) -> str: - return cast(str, self.ui.player1ComboBox.currentData()) - - def get_player_2_id(self) -> str: - return cast(str, self.ui.player2ComboBox.currentData()) - - def get_winner_id(self) -> str: - return cast(str, self.ui.winnerComboBox.currentData()) - - def get_score(self) -> str: - return self.ui.score.text().strip() - - def get_victory_condition(self) -> str: - return self.ui.victoryCondition.text().strip() - - def get_comment(self) -> str: - return self.ui.battleComment.toPlainText().strip() diff --git a/src/warchron/view/campaign_dialog.py b/src/warchron/view/campaign_dialog.py deleted file mode 100644 index 185203f..0000000 --- a/src/warchron/view/campaign_dialog.py +++ /dev/null @@ -1,25 +0,0 @@ -from PyQt6.QtWidgets import QDialog - -from warchron.view.ui.ui_campaign_dialog import Ui_campaignDialog -from PyQt6.QtWidgets import QWidget - - -class CampaignDialog(QDialog): - def __init__( - self, - parent: QWidget | None = None, - default_name: str = "", - default_month: int | None = None, - ) -> None: - super().__init__(parent) - self.ui: Ui_campaignDialog = Ui_campaignDialog() - self.ui.setupUi(self) # type: ignore - self.ui.campaignName.setText(default_name) - if default_month is not None: - self.ui.campaignMonth.setValue(default_month) - - def get_campaign_name(self) -> str: - return self.ui.campaignName.text().strip() - - def get_campaign_month(self) -> int: - return int(self.ui.campaignMonth.value()) diff --git a/src/warchron/view/campaign_participant_dialog.py b/src/warchron/view/campaign_participant_dialog.py deleted file mode 100644 index ae0fd86..0000000 --- a/src/warchron/view/campaign_participant_dialog.py +++ /dev/null @@ -1,40 +0,0 @@ -from typing import cast, List - -from PyQt6.QtWidgets import QWidget, QDialog - -from warchron.controller.dtos import ParticipantOption -from warchron.view.helpers import select_if_exists -from warchron.view.ui.ui_campaign_participant_dialog import ( - Ui_campaignParticipantDialog, -) - - -class CampaignParticipantDialog(QDialog): - def __init__( - self, - parent: QWidget | None = None, - *, - participants: List[ParticipantOption], - default_participant_id: str | None = None, - default_leader: str | None = "", - default_theme: str | None = "", - editable_player: bool = True, - ) -> None: - super().__init__(parent) - self.ui: Ui_campaignParticipantDialog = Ui_campaignParticipantDialog() - self.ui.setupUi(self) # type: ignore - for part in participants: - self.ui.playerComboBox.addItem(part.name, part.id) - select_if_exists(self.ui.playerComboBox, default_participant_id) - self.ui.playerComboBox.setEnabled(editable_player) - self.ui.leader.setText(default_leader) - self.ui.theme.setText(default_theme) - - def get_player_id(self) -> str: - return cast(str, self.ui.playerComboBox.currentData()) - - def get_participant_leader(self) -> str: - return self.ui.leader.text().strip() - - def get_participant_theme(self) -> str: - return self.ui.theme.text().strip() diff --git a/src/warchron/view/choices_dialog.py b/src/warchron/view/choices_dialog.py deleted file mode 100644 index afaa79a..0000000 --- a/src/warchron/view/choices_dialog.py +++ /dev/null @@ -1,48 +0,0 @@ -from typing import cast, List - -from PyQt6.QtWidgets import QWidget, QDialog - -from warchron.controller.dtos import ParticipantOption, SectorDTO -from warchron.view.helpers import select_if_exists -from warchron.view.ui.ui_choices_dialog import Ui_choicesDialog - - -class ChoicesDialog(QDialog): - def __init__( - self, - parent: QWidget | None = None, - *, - participants: List[ParticipantOption], - default_participant_id: str | None = None, - sectors: List[SectorDTO], - default_priority_id: str | None = None, - default_secondary_id: str | None = None, - default_comment: str | None = None, - ) -> None: - super().__init__(parent) - self.ui: Ui_choicesDialog = Ui_choicesDialog() - self.ui.setupUi(self) # type: ignore - for part in participants: - self.ui.playerComboBox.addItem(part.name, part.id) - select_if_exists(self.ui.playerComboBox, default_participant_id) - self.ui.playerComboBox.setEnabled(False) - self.ui.priorityComboBox.addItem("(none)", None) - self.ui.secondaryComboBox.addItem("(none)", None) - for sect in sectors: - self.ui.priorityComboBox.addItem(sect.name, sect.id) - self.ui.secondaryComboBox.addItem(sect.name, sect.id) - select_if_exists(self.ui.priorityComboBox, default_priority_id) - select_if_exists(self.ui.secondaryComboBox, default_secondary_id) - self.ui.choiceComment.setPlainText(default_comment) - - def get_participant_id(self) -> str: - return cast(str, self.ui.playerComboBox.currentData()) - - def get_priority_id(self) -> str: - return cast(str, self.ui.priorityComboBox.currentData()) - - def get_secondary_id(self) -> str: - return cast(str, self.ui.secondaryComboBox.currentData()) - - def get_comment(self) -> str: - return self.ui.choiceComment.toPlainText().strip() diff --git a/src/warchron/view/helpers.py b/src/warchron/view/helpers.py deleted file mode 100644 index 3e2f585..0000000 --- a/src/warchron/view/helpers.py +++ /dev/null @@ -1,27 +0,0 @@ -import calendar - -from PyQt6.QtWidgets import QComboBox - -from warchron.controller.dtos import WarDTO, CampaignDTO - - -def select_if_exists(combo: QComboBox, value: str | None) -> None: - if value is None: - return - idx = combo.findData(value) - if idx != -1: - combo.setCurrentIndex(idx) - - -def format_war_label(war: WarDTO) -> str: - return f"{war.name} ({war.year})" - - -def format_campaign_label(camp: CampaignDTO) -> str: - return f"{camp.name} ({calendar.month_name[camp.month]})" - - -def format_round_label(index: int) -> str: - if index is None: - return "" - return f"Round {index}" diff --git a/src/warchron/view/objective_dialog.py b/src/warchron/view/objective_dialog.py deleted file mode 100644 index a414c8b..0000000 --- a/src/warchron/view/objective_dialog.py +++ /dev/null @@ -1,24 +0,0 @@ -from PyQt6.QtWidgets import QWidget, QDialog - -from warchron.view.ui.ui_objective_dialog import Ui_objectiveDialog - - -class ObjectiveDialog(QDialog): - def __init__( - self, - parent: QWidget | None = None, - *, - default_name: str = "", - default_description: str | None = "", - ) -> None: - super().__init__(parent) - self.ui: Ui_objectiveDialog = Ui_objectiveDialog() - self.ui.setupUi(self) # type: ignore - self.ui.objectiveName.setText(default_name) - self.ui.objectiveDescription.setPlainText(default_description) - - def get_objective_name(self) -> str: - return self.ui.objectiveName.text().strip() - - def get_objective_description(self) -> str: - return self.ui.objectiveDescription.toPlainText().strip() diff --git a/src/warchron/view/player_dialog.py b/src/warchron/view/player_dialog.py deleted file mode 100644 index af039e6..0000000 --- a/src/warchron/view/player_dialog.py +++ /dev/null @@ -1,16 +0,0 @@ -from PyQt6.QtWidgets import QWidget, QDialog - -from warchron.view.ui.ui_player_dialog import Ui_playerDialog - - -class PlayerDialog(QDialog): - def __init__( - self, parent: QWidget | None = None, *, default_name: str = "" - ) -> None: - super().__init__(parent) - self.ui: Ui_playerDialog = Ui_playerDialog() - self.ui.setupUi(self) # type: ignore - self.ui.playerName.setText(default_name) - - def get_player_name(self) -> str: - return self.ui.playerName.text().strip() diff --git a/src/warchron/view/sector_dialog.py b/src/warchron/view/sector_dialog.py deleted file mode 100644 index 74312dd..0000000 --- a/src/warchron/view/sector_dialog.py +++ /dev/null @@ -1,54 +0,0 @@ -from typing import cast, List - -from PyQt6.QtWidgets import QWidget, QDialog - -from warchron.controller.dtos import ObjectiveDTO, RoundDTO -from warchron.view.helpers import select_if_exists, format_round_label -from warchron.view.ui.ui_sector_dialog import Ui_sectorDialog - - -class SectorDialog(QDialog): - def __init__( - self, - parent: QWidget | None = None, - *, - default_name: str = "", - rounds: List[RoundDTO], - default_round_id: str | None = None, - objectives: List[ObjectiveDTO], - default_major_id: str | None = None, - default_minor_id: str | None = None, - default_influence_id: str | None = None, - ) -> None: - super().__init__(parent) - self.ui: Ui_sectorDialog = Ui_sectorDialog() - self.ui.setupUi(self) # type: ignore - self.ui.majorComboBox.addItem("(none)", None) - self.ui.minorComboBox.addItem("(none)", None) - self.ui.influenceComboBox.addItem("(none)", None) - self.ui.sectorName.setText(default_name) - for index, rnd in enumerate(rounds, start=1): - self.ui.roundComboBox.addItem(format_round_label(index), rnd.id) - select_if_exists(self.ui.roundComboBox, default_round_id) - for obj in objectives: - self.ui.majorComboBox.addItem(obj.name, obj.id) - self.ui.minorComboBox.addItem(obj.name, obj.id) - self.ui.influenceComboBox.addItem(obj.name, obj.id) - select_if_exists(self.ui.majorComboBox, default_major_id) - select_if_exists(self.ui.minorComboBox, default_minor_id) - select_if_exists(self.ui.influenceComboBox, default_influence_id) - - def get_sector_name(self) -> str: - return self.ui.sectorName.text().strip() - - def get_round_id(self) -> str: - return cast(str, self.ui.roundComboBox.currentData()) - - def get_major_id(self) -> str: - return cast(str, self.ui.majorComboBox.currentData()) - - def get_minor_id(self) -> str: - return cast(str, self.ui.minorComboBox.currentData()) - - def get_influence_id(self) -> str: - return cast(str, self.ui.influenceComboBox.currentData()) diff --git a/src/warchron/view/view.py b/src/warchron/view/view.py index 8a86271..3b34fcf 100644 --- a/src/warchron/view/view.py +++ b/src/warchron/view/view.py @@ -1,10 +1,17 @@ -from typing import Callable, List +from typing import cast, Callable, List from pathlib import Path import calendar from PyQt6 import QtWidgets from PyQt6.QtCore import Qt, QPoint -from PyQt6.QtWidgets import QWidget, QFileDialog, QTreeWidgetItem, QMenu +from PyQt6.QtWidgets import ( + QWidget, + QDialog, + QFileDialog, + QTreeWidgetItem, + QMenu, + QComboBox, +) from PyQt6.QtGui import QCloseEvent from warchron.constants import ROLE_TYPE, ROLE_ID, ItemType @@ -14,17 +21,49 @@ from warchron.controller.dtos import ( WarDTO, WarParticipantDTO, ObjectiveDTO, + CampaignDTO, CampaignParticipantDTO, SectorDTO, + RoundDTO, ChoiceDTO, BattleDTO, ) -from warchron.view.helpers import ( - format_campaign_label, - format_round_label, - format_war_label, -) 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 +from warchron.view.ui.ui_objective_dialog import Ui_objectiveDialog +from warchron.view.ui.ui_war_participant_dialog import Ui_warParticipantDialog +from warchron.view.ui.ui_campaign_participant_dialog import ( + Ui_campaignParticipantDialog, +) +from warchron.view.ui.ui_sector_dialog import Ui_sectorDialog +from warchron.view.ui.ui_choices_dialog import Ui_choicesDialog +from warchron.view.ui.ui_battle_result_dialog import Ui_battleResultDialog + +# utils... + + +def select_if_exists(combo: QComboBox, value: str | None) -> None: + if value is None: + return + idx = combo.findData(value) + if idx != -1: + combo.setCurrentIndex(idx) + + +def format_war_label(war: WarDTO) -> str: + return f"{war.name} ({war.year})" + + +def format_campaign_label(camp: CampaignDTO) -> str: + return f"{camp.name} ({calendar.month_name[camp.month]})" + + +def format_round_label(index: int) -> str: + if index is None: + return "" + return f"Round {index}" class View(QtWidgets.QMainWindow, Ui_MainWindow): @@ -478,3 +517,285 @@ class View(QtWidgets.QMainWindow, Ui_MainWindow): table.setItem(row, 1, player_1_item) table.setItem(row, 2, player_2_item) table.resizeColumnsToContents() + + +class PlayerDialog(QDialog): + def __init__( + self, parent: QWidget | None = None, *, default_name: str = "" + ) -> None: + super().__init__(parent) + self.ui: Ui_playerDialog = Ui_playerDialog() + self.ui.setupUi(self) # type: ignore + self.ui.playerName.setText(default_name) + + def get_player_name(self) -> str: + return self.ui.playerName.text().strip() + + +class WarDialog(QDialog): + def __init__( + self, + parent: QWidget | None = None, + default_name: str = "", + default_year: int | None = None, + ) -> None: + super().__init__(parent) + self.ui: Ui_warDialog = Ui_warDialog() + self.ui.setupUi(self) # type: ignore + self.ui.warName.setText(default_name) + if default_year is not None: + self.ui.warYear.setValue(default_year) + + def get_war_name(self) -> str: + return self.ui.warName.text().strip() + + def get_war_year(self) -> int: + return int(self.ui.warYear.value()) + + +class CampaignDialog(QDialog): + def __init__( + self, + parent: QWidget | None = None, + default_name: str = "", + default_month: int | None = None, + ) -> None: + super().__init__(parent) + self.ui: Ui_campaignDialog = Ui_campaignDialog() + self.ui.setupUi(self) # type: ignore + self.ui.campaignName.setText(default_name) + if default_month is not None: + self.ui.campaignMonth.setValue(default_month) + + def get_campaign_name(self) -> str: + return self.ui.campaignName.text().strip() + + def get_campaign_month(self) -> int: + return int(self.ui.campaignMonth.value()) + + +class ObjectiveDialog(QDialog): + def __init__( + self, + parent: QWidget | None = None, + *, + default_name: str = "", + default_description: str | None = "", + ) -> None: + super().__init__(parent) + self.ui: Ui_objectiveDialog = Ui_objectiveDialog() + self.ui.setupUi(self) # type: ignore + self.ui.objectiveName.setText(default_name) + self.ui.objectiveDescription.setPlainText(default_description) + + def get_objective_name(self) -> str: + return self.ui.objectiveName.text().strip() + + def get_objective_description(self) -> str: + return self.ui.objectiveDescription.toPlainText().strip() + + +class WarParticipantDialog(QDialog): + def __init__( + self, + parent: QWidget | None = None, + *, + players: List[ParticipantOption], + default_player_id: str | None = None, + default_faction: str | None = "", + editable_player: bool = True, + ): + super().__init__(parent) + self.ui: Ui_warParticipantDialog = Ui_warParticipantDialog() + self.ui.setupUi(self) # type: ignore + for player in players: + self.ui.playerComboBox.addItem(player.name, player.id) + select_if_exists(self.ui.playerComboBox, default_player_id) + self.ui.playerComboBox.setEnabled(editable_player) + self.ui.faction.setText(default_faction) + + def get_player_id(self) -> str: + return cast(str, self.ui.playerComboBox.currentData()) + + def get_participant_faction(self) -> str: + return self.ui.faction.text().strip() + + +class CampaignParticipantDialog(QDialog): + def __init__( + self, + parent: QWidget | None = None, + *, + participants: List[ParticipantOption], + default_participant_id: str | None = None, + default_leader: str | None = "", + default_theme: str | None = "", + editable_player: bool = True, + ) -> None: + super().__init__(parent) + self.ui: Ui_campaignParticipantDialog = Ui_campaignParticipantDialog() + self.ui.setupUi(self) # type: ignore + for part in participants: + self.ui.playerComboBox.addItem(part.name, part.id) + select_if_exists(self.ui.playerComboBox, default_participant_id) + self.ui.playerComboBox.setEnabled(editable_player) + self.ui.leader.setText(default_leader) + self.ui.theme.setText(default_theme) + + def get_player_id(self) -> str: + return cast(str, self.ui.playerComboBox.currentData()) + + def get_participant_leader(self) -> str: + return self.ui.leader.text().strip() + + def get_participant_theme(self) -> str: + return self.ui.theme.text().strip() + + +class SectorDialog(QDialog): + def __init__( + self, + parent: QWidget | None = None, + *, + default_name: str = "", + rounds: List[RoundDTO], + default_round_id: str | None = None, + objectives: List[ObjectiveDTO], + default_major_id: str | None = None, + default_minor_id: str | None = None, + default_influence_id: str | None = None, + ) -> None: + super().__init__(parent) + self.ui: Ui_sectorDialog = Ui_sectorDialog() + self.ui.setupUi(self) # type: ignore + self.ui.majorComboBox.addItem("(none)", None) + self.ui.minorComboBox.addItem("(none)", None) + self.ui.influenceComboBox.addItem("(none)", None) + self.ui.sectorName.setText(default_name) + for index, rnd in enumerate(rounds, start=1): + self.ui.roundComboBox.addItem(format_round_label(index), rnd.id) + select_if_exists(self.ui.roundComboBox, default_round_id) + for obj in objectives: + self.ui.majorComboBox.addItem(obj.name, obj.id) + self.ui.minorComboBox.addItem(obj.name, obj.id) + self.ui.influenceComboBox.addItem(obj.name, obj.id) + select_if_exists(self.ui.majorComboBox, default_major_id) + select_if_exists(self.ui.minorComboBox, default_minor_id) + select_if_exists(self.ui.influenceComboBox, default_influence_id) + + def get_sector_name(self) -> str: + return self.ui.sectorName.text().strip() + + def get_round_id(self) -> str: + return cast(str, self.ui.roundComboBox.currentData()) + + def get_major_id(self) -> str: + return cast(str, self.ui.majorComboBox.currentData()) + + def get_minor_id(self) -> str: + return cast(str, self.ui.minorComboBox.currentData()) + + def get_influence_id(self) -> str: + return cast(str, self.ui.influenceComboBox.currentData()) + + +class ChoicesDialog(QDialog): + def __init__( + self, + parent: QWidget | None = None, + *, + participants: List[ParticipantOption], + default_participant_id: str | None = None, + sectors: List[SectorDTO], + default_priority_id: str | None = None, + default_secondary_id: str | None = None, + default_comment: str | None = None, + ) -> None: + super().__init__(parent) + self.ui: Ui_choicesDialog = Ui_choicesDialog() + self.ui.setupUi(self) # type: ignore + for part in participants: + self.ui.playerComboBox.addItem(part.name, part.id) + select_if_exists(self.ui.playerComboBox, default_participant_id) + self.ui.playerComboBox.setEnabled(False) + self.ui.priorityComboBox.addItem("(none)", None) + self.ui.secondaryComboBox.addItem("(none)", None) + for sect in sectors: + self.ui.priorityComboBox.addItem(sect.name, sect.id) + self.ui.secondaryComboBox.addItem(sect.name, sect.id) + select_if_exists(self.ui.priorityComboBox, default_priority_id) + select_if_exists(self.ui.secondaryComboBox, default_secondary_id) + self.ui.choiceComment.setPlainText(default_comment) + + def get_participant_id(self) -> str: + return cast(str, self.ui.playerComboBox.currentData()) + + def get_priority_id(self) -> str: + return cast(str, self.ui.priorityComboBox.currentData()) + + def get_secondary_id(self) -> str: + return cast(str, self.ui.secondaryComboBox.currentData()) + + def get_comment(self) -> str: + return self.ui.choiceComment.toPlainText().strip() + + +class BattlesDialog(QDialog): + def __init__( + self, + parent: QWidget | None = None, + *, + sectors: List[SectorDTO], + default_sector_id: str | None = None, + players: List[ParticipantOption], + default_player_1_id: str | None = None, + default_player_2_id: str | None = None, + default_winner_id: str | None = None, + default_score: str | None = None, + default_victory_condition: str | None = None, + default_comment: str | None = None, + ) -> None: + super().__init__(parent) + self.ui: Ui_battleResultDialog = Ui_battleResultDialog() + self.ui.setupUi(self) # type: ignore + for sect in sectors: + self.ui.sectorComboBox.addItem(sect.name, sect.id) + select_if_exists(self.ui.sectorComboBox, default_sector_id) + self.ui.sectorComboBox.setEnabled(False) + + self.ui.player1ComboBox.addItem("(none)", None) + self.ui.player2ComboBox.addItem("(none)", None) + for play in players: + self.ui.player1ComboBox.addItem(play.name, play.id) + self.ui.player2ComboBox.addItem(play.name, play.id) + select_if_exists(self.ui.player1ComboBox, default_player_1_id) + select_if_exists(self.ui.player2ComboBox, default_player_2_id) + self.ui.winnerComboBox.addItem("(none)", None) + for play in players: + if play.id in (default_player_1_id, default_player_2_id): + self.ui.winnerComboBox.addItem(play.name, play.id) + select_if_exists(self.ui.winnerComboBox, default_winner_id) + self.ui.score.setText(default_score) + self.ui.victoryCondition.setText(default_victory_condition) + self.ui.battleComment.setPlainText(default_comment) + + def get_sector_id(self) -> str: + return cast(str, self.ui.sectorComboBox.currentData()) + + def get_player_1_id(self) -> str: + return cast(str, self.ui.player1ComboBox.currentData()) + + def get_player_2_id(self) -> str: + return cast(str, self.ui.player2ComboBox.currentData()) + + def get_winner_id(self) -> str: + return cast(str, self.ui.winnerComboBox.currentData()) + + def get_score(self) -> str: + return self.ui.score.text().strip() + + def get_victory_condition(self) -> str: + return self.ui.victoryCondition.text().strip() + + def get_comment(self) -> str: + return self.ui.battleComment.toPlainText().strip() diff --git a/src/warchron/view/war_dialog.py b/src/warchron/view/war_dialog.py deleted file mode 100644 index 3d17a3f..0000000 --- a/src/warchron/view/war_dialog.py +++ /dev/null @@ -1,24 +0,0 @@ -from PyQt6.QtWidgets import QWidget, QDialog - -from warchron.view.ui.ui_war_dialog import Ui_warDialog - - -class WarDialog(QDialog): - def __init__( - self, - parent: QWidget | None = None, - default_name: str = "", - default_year: int | None = None, - ) -> None: - super().__init__(parent) - self.ui: Ui_warDialog = Ui_warDialog() - self.ui.setupUi(self) # type: ignore - self.ui.warName.setText(default_name) - if default_year is not None: - self.ui.warYear.setValue(default_year) - - def get_war_name(self) -> str: - return self.ui.warName.text().strip() - - def get_war_year(self) -> int: - return int(self.ui.warYear.value()) diff --git a/src/warchron/view/war_participant_dialog.py b/src/warchron/view/war_participant_dialog.py deleted file mode 100644 index 9718602..0000000 --- a/src/warchron/view/war_participant_dialog.py +++ /dev/null @@ -1,33 +0,0 @@ -from typing import cast, List - -from PyQt6.QtWidgets import QWidget, QDialog - -from warchron.controller.dtos import ParticipantOption -from warchron.view.helpers import select_if_exists -from warchron.view.ui.ui_war_participant_dialog import Ui_warParticipantDialog - - -class WarParticipantDialog(QDialog): - def __init__( - self, - parent: QWidget | None = None, - *, - players: List[ParticipantOption], - default_player_id: str | None = None, - default_faction: str | None = "", - editable_player: bool = True, - ): - super().__init__(parent) - self.ui: Ui_warParticipantDialog = Ui_warParticipantDialog() - self.ui.setupUi(self) # type: ignore - for player in players: - self.ui.playerComboBox.addItem(player.name, player.id) - select_if_exists(self.ui.playerComboBox, default_player_id) - self.ui.playerComboBox.setEnabled(editable_player) - self.ui.faction.setText(default_faction) - - def get_player_id(self) -> str: - return cast(str, self.ui.playerComboBox.currentData()) - - def get_participant_faction(self) -> str: - return self.ui.faction.text().strip()