Compare commits

...

4 commits

Author SHA1 Message Date
Maxime Réaux
df846b8e4b manage deleted refered player, participant, objective, sector 2026-02-05 16:17:18 +01:00
Maxime Réaux
7afbb5ea1d split edit methods in controller 2026-02-05 10:57:22 +01:00
Maxime Réaux
4593400fd4 fix round listing from different wars 2026-02-05 10:19:14 +01:00
Maxime Réaux
019e62565f split dialogs and war/campaign/round classes to files 2026-02-05 08:42:38 +01:00
23 changed files with 1028 additions and 696 deletions

View file

@ -4,6 +4,11 @@ from pathlib import Path
from PyQt6.QtWidgets import QMessageBox, QDialog from PyQt6.QtWidgets import QMessageBox, QDialog
from warchron.model.model import Model from warchron.model.model import Model
from warchron.model.exception import (
DeletionForbidden,
DeletionRequiresConfirmation,
UpdateRequiresConfirmation,
)
from warchron.view.view import View from warchron.view.view import View
from warchron.constants import ItemType, RefreshScope from warchron.constants import ItemType, RefreshScope
from warchron.controller.dtos import ( from warchron.controller.dtos import (
@ -19,17 +24,15 @@ from warchron.controller.dtos import (
ChoiceDTO, ChoiceDTO,
BattleDTO, BattleDTO,
) )
from warchron.view.view import ( from warchron.view.player_dialog import PlayerDialog
PlayerDialog, from warchron.view.war_dialog import WarDialog
WarDialog, from warchron.view.campaign_dialog import CampaignDialog
CampaignDialog, from warchron.view.objective_dialog import ObjectiveDialog
ObjectiveDialog, from warchron.view.war_participant_dialog import WarParticipantDialog
WarParticipantDialog, from warchron.view.campaign_participant_dialog import CampaignParticipantDialog
CampaignParticipantDialog, from warchron.view.sector_dialog import SectorDialog
SectorDialog, from warchron.view.choices_dialog import ChoicesDialog
ChoicesDialog, from warchron.view.battles_dialog import BattlesDialog
BattlesDialog,
)
class Controller: class Controller:
@ -364,134 +367,49 @@ class Controller:
self.view.select_tree_item(item_type=item_type, item_id=item_id) self.view.select_tree_item(item_type=item_type, item_id=item_id)
def edit_item(self, item_type: str, item_id: str) -> None: def edit_item(self, item_type: str, item_id: str) -> None:
if item_type == ItemType.PLAYER: try:
play = self.model.get_player(item_id) if item_type == ItemType.PLAYER:
player_dialog = PlayerDialog(self.view, default_name=play.name) self.edit_player(item_id)
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) self.refresh(RefreshScope.PLAYERS_LIST)
elif item_type == ItemType.WAR: elif item_type == ItemType.WAR:
war = self.model.get_war(item_id) self.edit_war(item_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(item_id, name=name, year=year)
self.refresh_and_select( self.refresh_and_select(
RefreshScope.WARS_TREE, item_type=ItemType.WAR, item_id=war.id RefreshScope.WARS_TREE, item_type=ItemType.WAR, item_id=item_id
) )
elif item_type == ItemType.CAMPAIGN: elif item_type == ItemType.CAMPAIGN:
camp = self.model.get_campaign(item_id) self.edit_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( self.refresh_and_select(
RefreshScope.WARS_TREE, item_type=ItemType.CAMPAIGN, item_id=camp.id RefreshScope.WARS_TREE, item_type=ItemType.CAMPAIGN, item_id=item_id
) )
elif item_type == ItemType.OBJECTIVE: elif item_type == ItemType.OBJECTIVE:
obj = self.model.get_objective(item_id) self.edit_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) self.refresh(RefreshScope.WAR_DETAILS)
elif item_type == ItemType.WAR_PARTICIPANT: elif item_type == ItemType.WAR_PARTICIPANT:
war_part = self.model.get_war_participant(item_id) self.edit_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) self.refresh(RefreshScope.WAR_DETAILS)
elif item_type == ItemType.SECTOR: elif item_type == ItemType.SECTOR:
sect = self.model.get_sector(item_id) self.edit_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) self.refresh(RefreshScope.CAMPAIGN_DETAILS)
elif item_type == ItemType.CAMPAIGN_PARTICIPANT: elif item_type == ItemType.CAMPAIGN_PARTICIPANT:
camp_part = self.model.get_campaign_participant(item_id) self.edit_campaign_participant(item_id)
war_part = self.model.get_war_participant(camp_part.war_participant_id) self.refresh(RefreshScope.CAMPAIGN_DETAILS)
player = self.model.get_player(war_part.player_id) elif item_type == ItemType.CHOICE:
part_opt = [ParticipantOption(id=player.id, name=player.name)] self.edit_round_choice(item_id)
camp_part_dialog = CampaignParticipantDialog( self.refresh(RefreshScope.ROUND_DETAILS)
self.view, elif item_type == ItemType.BATTLE:
participants=part_opt, self.edit_round_battle(item_id)
default_participant_id=camp_part.id, self.refresh(RefreshScope.ROUND_DETAILS)
default_leader=camp_part.leader, self.is_dirty = True
default_theme=camp_part.theme, except UpdateRequiresConfirmation as e:
editable_player=False, reply = QMessageBox.question(
) self.view,
if camp_part_dialog.exec() == QDialog.DialogCode.Accepted: "Confirm update",
leader = camp_part_dialog.get_participant_leader() e.message,
theme = camp_part_dialog.get_participant_theme() QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
self.model.update_campaign_participant( )
item_id, leader=leader, theme=theme if reply == QMessageBox.StandardButton.Yes:
) e.apply_update()
self.refresh(RefreshScope.CAMPAIGN_DETAILS) 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: def delete_item(self, item_type: str, item_id: str) -> None:
reply = QMessageBox.question( reply = QMessageBox.question(
@ -502,39 +420,56 @@ class Controller:
) )
if reply != QMessageBox.StandardButton.Yes: if reply != QMessageBox.StandardButton.Yes:
return return
if item_type == ItemType.PLAYER: try:
self.model.remove_player(item_id) if item_type == ItemType.PLAYER:
self.refresh(RefreshScope.PLAYERS_LIST) self.model.remove_player(item_id)
elif item_type == ItemType.WAR: self.refresh(RefreshScope.PLAYERS_LIST)
self.model.remove_war(item_id) elif item_type == ItemType.WAR:
self.refresh(RefreshScope.WARS_TREE) self.model.remove_war(item_id)
elif item_type == ItemType.CAMPAIGN: self.refresh(RefreshScope.WARS_TREE)
war = self.model.get_war_by_campaign(item_id) elif item_type == ItemType.CAMPAIGN:
war_id = war.id war = self.model.get_war_by_campaign(item_id)
self.model.remove_campaign(item_id) war_id = war.id
self.refresh_and_select( self.model.remove_campaign(item_id)
RefreshScope.WARS_TREE, item_type=ItemType.WAR, item_id=war_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,
) )
elif item_type == ItemType.OBJECTIVE: except DeletionRequiresConfirmation as e:
self.model.remove_objective(item_id) reply = QMessageBox.question(
self.refresh(RefreshScope.WAR_DETAILS) self.view,
elif item_type == ItemType.WAR_PARTICIPANT: "Confirm deletion",
self.model.remove_war_participant(item_id) e.message,
self.refresh(RefreshScope.WAR_DETAILS) QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
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 if reply == QMessageBox.StandardButton.Yes:
e.cleanup_action()
self.refresh(RefreshScope.CAMPAIGN_DETAILS)
# Player methods # Player methods
@ -557,6 +492,15 @@ class Controller:
self.is_dirty = True self.is_dirty = True
self.refresh(RefreshScope.PLAYERS_LIST) 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 # War methods
def _validate_war_inputs(self, name: str, year: int) -> bool: def _validate_war_inputs(self, name: str, year: int) -> bool:
@ -586,6 +530,16 @@ class Controller:
RefreshScope.WARS_TREE, item_type=ItemType.WAR, item_id=war.id 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 # Objective methods
def _validate_objective_inputs(self, name: str, description: str) -> bool: def _validate_objective_inputs(self, name: str, description: str) -> bool:
@ -610,6 +564,20 @@ class Controller:
self.is_dirty = True self.is_dirty = True
self.refresh(RefreshScope.WAR_DETAILS) 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 # War participant methods
def add_war_participant(self) -> None: def add_war_participant(self) -> None:
@ -630,6 +598,21 @@ class Controller:
self.is_dirty = True self.is_dirty = True
self.refresh(RefreshScope.WAR_DETAILS) 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 # Campaign methods
def _validate_campaign_inputs(self, name: str, month: int) -> bool: def _validate_campaign_inputs(self, name: str, month: int) -> bool:
@ -666,6 +649,18 @@ class Controller:
RefreshScope.WARS_TREE, item_type=ItemType.CAMPAIGN, item_id=camp.id 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 # Campaign participant methods
def add_campaign_participant(self) -> None: def add_campaign_participant(self) -> None:
@ -692,6 +687,26 @@ class Controller:
self.is_dirty = True self.is_dirty = True
self.refresh(RefreshScope.CAMPAIGN_DETAILS) 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 # Sector methods
def _validate_sector_inputs( def _validate_sector_inputs(
@ -740,6 +755,44 @@ class Controller:
self.is_dirty = True self.is_dirty = True
self.refresh(RefreshScope.CAMPAIGN_DETAILS) 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 # Round methods
def add_round(self) -> None: def add_round(self) -> None:

View file

@ -0,0 +1,35 @@
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

View file

@ -2,7 +2,15 @@ from __future__ import annotations
from uuid import uuid4 from uuid import uuid4
from typing import Any, Dict, List from typing import Any, Dict, List
from warchron.model.round import Round, Choice, Battle 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
class Campaign: class Campaign:
@ -90,12 +98,47 @@ class Campaign:
part.set_theme(theme) part.set_theme(theme)
def remove_campaign_participant(self, participant_id: str) -> None: def remove_campaign_participant(self, participant_id: str) -> None:
# TODO manage choices referring to it rounds_blocking: list[Round] = []
# TODO manage battles referring to it for rnd in self.rounds:
del self.participants[participant_id] 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,
)
# Sector methods # 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( def add_sector(
self, name: str, round_id: str, major_id: str, minor_id: str, influence_id: str self, name: str, round_id: str, major_id: str, minor_id: str, influence_id: str
) -> Sector: ) -> Sector:
@ -126,16 +169,75 @@ class Campaign:
influence_id: str, influence_id: str,
) -> None: ) -> None:
sect = self.get_sector(sector_id) sect = self.get_sector(sector_id)
sect.set_name(name) old_round_id = sect.round_id
sect.set_round(round_id)
sect.set_major(major_id) def apply_update() -> None:
sect.set_minor(minor_id) sect.set_name(name)
sect.set_influence(influence_id) 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,
)
def remove_sector(self, sector_id: str) -> None: def remove_sector(self, sector_id: str) -> None:
# TODO manage choices referring to it rounds_blocking: list[Round] = []
# TODO manage battles referring to it for rnd in self.rounds:
del self.sectors[sector_id] 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,
)
def get_sectors_in_round(self, round_id: str) -> List[Sector]: 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] sectors = [s for s in self.sectors.values() if s.round_id == round_id]
@ -227,62 +329,3 @@ class Campaign:
def remove_battle(self, round_id: str, sector_id: str) -> None: def remove_battle(self, round_id: str, sector_id: str) -> None:
rnd = self.get_round(round_id) rnd = self.get_round(round_id)
rnd.remove_battle(sector_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

View file

@ -0,0 +1,24 @@
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

View file

@ -0,0 +1,27 @@
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

View file

@ -0,0 +1,31 @@
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)

View file

@ -4,10 +4,17 @@ import json
import shutil import shutil
from datetime import datetime from datetime import datetime
from warchron.model.exception import DeletionForbidden
from warchron.model.player import Player from warchron.model.player import Player
from warchron.model.war import War, Objective, WarParticipant from warchron.model.war import War
from warchron.model.campaign import Campaign, Sector, CampaignParticipant from warchron.model.war_participant import WarParticipant
from warchron.model.round import Round, Choice, Battle 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
class Model: class Model:
@ -78,7 +85,16 @@ class Model:
return list(self.players.values()) return list(self.players.values())
def remove_player(self, player_id: str) -> None: def remove_player(self, player_id: str) -> None:
# TODO manage war_participants referring to it 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."
)
del self.players[player_id] del self.players[player_id]
# War methods # War methods
@ -94,6 +110,7 @@ class Model:
def get_war(self, id: str) -> War: def get_war(self, id: str) -> War:
return self.wars[id] return self.wars[id]
# TODO replace multiloops by internal has_* method
def get_war_by_campaign(self, campaign_id: str) -> War: def get_war_by_campaign(self, campaign_id: str) -> War:
for war in self.wars.values(): for war in self.wars.values():
for camp in war.campaigns: for camp in war.campaigns:
@ -101,6 +118,7 @@ class Model:
return war return war
raise KeyError(f"Campaign {campaign_id} not found in any 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: def get_war_by_sector(self, sector_id: str) -> War:
for war in self.wars.values(): for war in self.wars.values():
for camp in war.campaigns: for camp in war.campaigns:
@ -109,6 +127,7 @@ class Model:
return war return war
raise KeyError(f"Sector {sector_id} not found in any 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: def get_war_by_round(self, round_id: str) -> War:
for war in self.wars.values(): for war in self.wars.values():
for camp in war.campaigns: for camp in war.campaigns:
@ -117,6 +136,7 @@ class Model:
return war return war
raise KeyError(f"Round {round_id} not found in any 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: def get_war_by_objective(self, objective_id: str) -> War:
for war in self.wars.values(): for war in self.wars.values():
for obj in war.objectives.values(): for obj in war.objectives.values():
@ -154,6 +174,7 @@ class Model:
war = self.get_war(war_id) war = self.get_war(war_id)
return war.add_objective(name, description) return war.add_objective(name, description)
# TODO replace multiloops by internal has_* method
def get_objective(self, objective_id: str) -> Objective: def get_objective(self, objective_id: str) -> Objective:
for war in self.wars.values(): for war in self.wars.values():
for obj in war.objectives.values(): for obj in war.objectives.values():
@ -185,6 +206,7 @@ class Model:
war = self.get_war(war_id) war = self.get_war(war_id)
return war.add_war_participant(player_id, faction) return war.add_war_participant(player_id, faction)
# TODO replace multiloops by internal has_* method
def get_war_participant(self, participant_id: str) -> WarParticipant: def get_war_participant(self, participant_id: str) -> WarParticipant:
for war in self.wars.values(): for war in self.wars.values():
for part in war.participants.values(): for part in war.participants.values():
@ -213,6 +235,7 @@ class Model:
war = self.get_war(war_id) war = self.get_war(war_id)
return war.add_campaign(name, month) return war.add_campaign(name, month)
# TODO replace multiloops by internal has_* method
def get_campaign(self, campaign_id: str) -> Campaign: def get_campaign(self, campaign_id: str) -> Campaign:
for war in self.wars.values(): for war in self.wars.values():
for campaign in war.campaigns: for campaign in war.campaigns:
@ -263,6 +286,7 @@ class Model:
camp = self.get_campaign(campaign_id) camp = self.get_campaign(campaign_id)
return camp.add_sector(name, round_id, major_id, minor_id, influence_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: def get_sector(self, sector_id: str) -> Sector:
for war in self.wars.values(): for war in self.wars.values():
for camp in war.campaigns: for camp in war.campaigns:
@ -312,6 +336,7 @@ class Model:
war_part = war.get_war_participant(participant_id) war_part = war.get_war_participant(participant_id)
return self.players[war_part.player_id].name return self.players[war_part.player_id].name
# TODO replace multiloops by internal has_* method
def get_campaign_participant(self, participant_id: str) -> CampaignParticipant: def get_campaign_participant(self, participant_id: str) -> CampaignParticipant:
for war in self.wars.values(): for war in self.wars.values():
for camp in war.campaigns: for camp in war.campaigns:
@ -343,9 +368,10 @@ class Model:
# Round methods # Round methods
def add_round(self, campaign_id: str) -> Round: def add_round(self, campaign_id: str) -> Round:
camp = self.get_campaign(campaign_id) war = self.get_war_by_campaign(campaign_id)
return camp.add_round() return war.add_round(campaign_id)
# TODO replace multiloops by internal has_* method
def get_round(self, round_id: str) -> Round: def get_round(self, round_id: str) -> Round:
for war in self.wars.values(): for war in self.wars.values():
for camp in war.campaigns: for camp in war.campaigns:

View file

@ -0,0 +1,18 @@
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

View file

@ -2,6 +2,9 @@ from __future__ import annotations
from uuid import uuid4 from uuid import uuid4
from typing import Any, Dict from typing import Any, Dict
from warchron.model.choice import Choice
from warchron.model.battle import Battle
class Round: class Round:
def __init__(self) -> None: def __init__(self) -> None:
@ -40,6 +43,18 @@ class Round:
def get_choice(self, participant_id: str) -> Choice | None: def get_choice(self, participant_id: str) -> Choice | None:
return self.choices.get(participant_id) 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: def create_choice(self, participant_id: str) -> Choice:
if participant_id not in self.choices: if participant_id not in self.choices:
choice = Choice( choice = Choice(
@ -63,6 +78,13 @@ class Round:
choice.set_secondary(secondary_sector_id) choice.set_secondary(secondary_sector_id)
choice.set_comment(comment) 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: def remove_choice(self, participant_id: str) -> None:
del self.choices[participant_id] del self.choices[participant_id]
@ -71,6 +93,15 @@ class Round:
def get_battle(self, sector_id: str) -> Battle | None: def get_battle(self, sector_id: str) -> Battle | None:
return self.battles.get(sector_id) 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: def create_battle(self, sector_id: str) -> Battle:
if sector_id not in self.battles: if sector_id not in self.battles:
battle = Battle(sector_id=sector_id, player_1_id=None, player_2_id=None) battle = Battle(sector_id=sector_id, player_1_id=None, player_2_id=None)
@ -96,71 +127,14 @@ class Round:
bat.set_victory_condition(victory_condition) bat.set_victory_condition(victory_condition)
bat.set_comment(comment) 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: def remove_battle(self, sector_id: str) -> None:
del self.battles[sector_id] 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

View file

@ -0,0 +1,39 @@
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

View file

@ -3,8 +3,15 @@ from uuid import uuid4
from datetime import datetime from datetime import datetime
from typing import Any, Dict, List from typing import Any, Dict, List
from warchron.model.campaign import Campaign, Sector, CampaignParticipant from warchron.model.exception import DeletionForbidden
from warchron.model.round import Round, Choice, Battle 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
class War: class War:
@ -76,7 +83,16 @@ class War:
obj.set_description(description) obj.set_description(description)
def remove_objective(self, objective_id: str) -> None: def remove_objective(self, objective_id: str) -> None:
# TODO manage sectors referring to it 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."
)
del self.objectives[objective_id] del self.objectives[objective_id]
# War participant methods # War participant methods
@ -103,14 +119,23 @@ class War:
def get_all_war_participants(self) -> List[WarParticipant]: def get_all_war_participants(self) -> List[WarParticipant]:
return list(self.participants.values()) return list(self.participants.values())
def update_war_participant(self, player_id: str, *, faction: str) -> None: def update_war_participant(self, participant_id: str, *, faction: str) -> None:
part = self.get_war_participant(player_id) part = self.get_war_participant(participant_id)
# Can't change referred Model.players # Can't change referred Model.players
part.set_faction(faction) part.set_faction(faction)
def remove_war_participant(self, player_id: str) -> None: def remove_war_participant(self, participant_id: str) -> None:
# TODO manage campaign_participants referring to it camp_using_part: List[str] = []
del self.participants[player_id] 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]
# Campaign methods # Campaign methods
@ -133,13 +158,15 @@ class War:
return camp return camp
raise KeyError(f"Campaign {campaign_id} not found in War {self.id}") raise KeyError(f"Campaign {campaign_id} not found in War {self.id}")
def get_campaign_by_round(self, round_id: str) -> Campaign: # TODO replace multiloops by internal has_* method
def get_campaign_by_round(self, round_id: str) -> Campaign | None:
for camp in self.campaigns: for camp in self.campaigns:
for rnd in camp.rounds: for rnd in camp.rounds:
if rnd.id == round_id: if rnd.id == round_id:
return camp return camp
raise KeyError(f"Round {round_id} not found in any Campaign") return None
# TODO replace multiloops by internal has_* method
def get_campaign_by_sector(self, sector_id: str) -> Campaign: def get_campaign_by_sector(self, sector_id: str) -> Campaign:
for camp in self.campaigns: for camp in self.campaigns:
for sect in camp.sectors.values(): for sect in camp.sectors.values():
@ -179,6 +206,7 @@ class War:
camp = self.get_campaign(campaign_id) camp = self.get_campaign(campaign_id)
return camp.add_sector(name, round_id, major_id, minor_id, influence_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: def get_sector(self, sector_id: str) -> Sector:
for camp in self.campaigns: for camp in self.campaigns:
for sect in camp.sectors.values(): for sect in camp.sectors.values():
@ -226,6 +254,7 @@ class War:
camp = self.get_campaign(campaign_id) camp = self.get_campaign(campaign_id)
return camp.add_campaign_participant(participant_id, leader, theme) 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: def get_campaign_participant(self, participant_id: str) -> CampaignParticipant:
for camp in self.campaigns: for camp in self.campaigns:
for part in camp.participants.values(): for part in camp.participants.values():
@ -249,19 +278,18 @@ class War:
camp = self.get_campaign(campaign_id) camp = self.get_campaign(campaign_id)
return camp.add_round() 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: def remove_round(self, round_id: str) -> None:
camp = self.get_campaign_by_round(round_id) camp = self.get_campaign_by_round(round_id)
camp.remove_round(round_id) if camp is not None:
camp.remove_round(round_id)
# Choice methods # Choice methods
def create_choice(self, round_id: str, participant_id: str) -> Choice: def create_choice(self, round_id: str, participant_id: str) -> Choice:
camp = self.get_campaign_by_round(round_id) camp = self.get_campaign_by_round(round_id)
return camp.create_choice(round_id, participant_id) if camp is not None:
return camp.create_choice(round_id, participant_id)
raise KeyError("Campaign with round {round_id} doesn't exist")
def update_choice( def update_choice(
self, self,
@ -272,19 +300,27 @@ class War:
comment: str | None, comment: str | None,
) -> None: ) -> None:
camp = self.get_campaign_by_round(round_id) camp = self.get_campaign_by_round(round_id)
camp.update_choice( if camp is not None:
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: def remove_choice(self, round_id: str, participant_id: str) -> None:
camp = self.get_campaign_by_round(round_id) camp = self.get_campaign_by_round(round_id)
camp.remove_choice(round_id, participant_id) if camp is not None:
camp.remove_choice(round_id, participant_id)
# Battle methods # Battle methods
def create_battle(self, round_id: str, sector_id: str) -> Battle: def create_battle(self, round_id: str, sector_id: str) -> Battle:
camp = self.get_campaign_by_round(round_id) camp = self.get_campaign_by_round(round_id)
return camp.create_battle(round_id, sector_id) if camp is not None:
return camp.create_battle(round_id, sector_id)
raise KeyError("Campaign with round {round_id} doesn't exist")
def update_battle( def update_battle(
self, self,
@ -298,49 +334,19 @@ class War:
comment: str | None, comment: str | None,
) -> None: ) -> None:
camp = self.get_campaign_by_round(round_id) camp = self.get_campaign_by_round(round_id)
camp.update_battle( if camp is not None:
round_id, camp.update_battle(
sector_id, round_id,
player_1_id, sector_id,
player_2_id, player_1_id,
winner_id, player_2_id,
score, winner_id,
victory_condition, score,
comment, victory_condition,
) comment,
)
def remove_battle(self, round_id: str, sector_id: str) -> None: def remove_battle(self, round_id: str, sector_id: str) -> None:
camp = self.get_campaign_by_round(round_id) camp = self.get_campaign_by_round(round_id)
camp.remove_battle(round_id, sector_id) if camp is not None:
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

View file

@ -0,0 +1,18 @@
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

View file

@ -0,0 +1,68 @@
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()

View file

@ -0,0 +1,25 @@
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())

View file

@ -0,0 +1,40 @@
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()

View file

@ -0,0 +1,48 @@
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()

View file

@ -0,0 +1,27 @@
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}"

View file

@ -0,0 +1,24 @@
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()

View file

@ -0,0 +1,16 @@
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()

View file

@ -0,0 +1,54 @@
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())

View file

@ -1,17 +1,10 @@
from typing import cast, Callable, List from typing import Callable, List
from pathlib import Path from pathlib import Path
import calendar import calendar
from PyQt6 import QtWidgets from PyQt6 import QtWidgets
from PyQt6.QtCore import Qt, QPoint from PyQt6.QtCore import Qt, QPoint
from PyQt6.QtWidgets import ( from PyQt6.QtWidgets import QWidget, QFileDialog, QTreeWidgetItem, QMenu
QWidget,
QDialog,
QFileDialog,
QTreeWidgetItem,
QMenu,
QComboBox,
)
from PyQt6.QtGui import QCloseEvent from PyQt6.QtGui import QCloseEvent
from warchron.constants import ROLE_TYPE, ROLE_ID, ItemType from warchron.constants import ROLE_TYPE, ROLE_ID, ItemType
@ -21,49 +14,17 @@ from warchron.controller.dtos import (
WarDTO, WarDTO,
WarParticipantDTO, WarParticipantDTO,
ObjectiveDTO, ObjectiveDTO,
CampaignDTO,
CampaignParticipantDTO, CampaignParticipantDTO,
SectorDTO, SectorDTO,
RoundDTO,
ChoiceDTO, ChoiceDTO,
BattleDTO, BattleDTO,
) )
from warchron.view.ui.ui_main_window import Ui_MainWindow from warchron.view.helpers import (
from warchron.view.ui.ui_player_dialog import Ui_playerDialog format_campaign_label,
from warchron.view.ui.ui_war_dialog import Ui_warDialog format_round_label,
from warchron.view.ui.ui_campaign_dialog import Ui_campaignDialog format_war_label,
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_main_window import Ui_MainWindow
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): class View(QtWidgets.QMainWindow, Ui_MainWindow):
@ -517,285 +478,3 @@ class View(QtWidgets.QMainWindow, Ui_MainWindow):
table.setItem(row, 1, player_1_item) table.setItem(row, 1, player_1_item)
table.setItem(row, 2, player_2_item) table.setItem(row, 2, player_2_item)
table.resizeColumnsToContents() 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()

View file

@ -0,0 +1,24 @@
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())

View file

@ -0,0 +1,33 @@
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()