add/edit/delet objectives and participants in war

This commit is contained in:
Maxime Réaux 2026-01-28 16:25:40 +01:00
parent e33dec40be
commit 495a5adb98
14 changed files with 1088 additions and 322 deletions

View file

@ -30,7 +30,7 @@
"name": "Llael War 2025", "name": "Llael War 2025",
"year": 2025, "year": 2025,
"entrants": { "participants": {
"e7844fbb-8366-44e4-bb43-89b9eef6ef64": { "e7844fbb-8366-44e4-bb43-89b9eef6ef64": {
"war_points": 0, "war_points": 0,
"influence_tokens": 1 "influence_tokens": 1

View file

@ -1,14 +1,24 @@
from enum import StrEnum from enum import StrEnum
from enum import Enum, auto
from PyQt6.QtCore import Qt from PyQt6.QtCore import Qt
# --- Tree / Table roles ---
ROLE_TYPE = Qt.ItemDataRole.UserRole ROLE_TYPE = Qt.ItemDataRole.UserRole
ROLE_ID = Qt.ItemDataRole.UserRole + 1 ROLE_ID = Qt.ItemDataRole.UserRole + 1
# --- Domain object types ---
class ItemType(StrEnum): class ItemType(StrEnum):
PLAYER = "player" PLAYER = "player"
WAR = "war" WAR = "war"
CAMPAIGN = "campaign" CAMPAIGN = "campaign"
ROUND = "round" ROUND = "round"
OBJECTIVE = "objective"
WAR_PARTICIPANT = "war_participant"
class RefreshScope(Enum):
NONE = auto()
PLAYERS_LIST = auto()
WARS_TREE = auto()
WAR_DETAILS = auto()
CAMPAIGN_DETAILS = auto()
ROUND_DETAILS = auto()

View file

@ -5,8 +5,8 @@ from PyQt6.QtWidgets import QMessageBox, QDialog
from warchron.model.model import Model from warchron.model.model import Model
from warchron.view.view import View from warchron.view.view import View
from warchron.constants import ItemType from warchron.constants import ItemType, RefreshScope
from warchron.view.view import PlayerDialog, WarDialog, CampaignDialog from warchron.view.view import PlayerDialog, WarDialog, CampaignDialog, ObjectiveDialog, ParticipantDialog
class Controller: class Controller:
def __init__(self, model: Model, view: View): def __init__(self, model: Model, view: View):
@ -35,6 +35,8 @@ class Controller:
self.view.actionSave_as.triggered.connect(self.save_as) self.view.actionSave_as.triggered.connect(self.save_as)
self.view.addPlayerBtn.clicked.connect(self.add_player) self.view.addPlayerBtn.clicked.connect(self.add_player)
self.view.addWarBtn.clicked.connect(self.add_war) self.view.addWarBtn.clicked.connect(self.add_war)
self.view.addObjectiveBtn.clicked.connect(self.add_objective)
self.view.addWarParticipantBtn.clicked.connect(self.add_war_participant)
self.view.on_edit_item = self.edit_item self.view.on_edit_item = self.edit_item
self.view.on_delete_item = self.delete_item self.view.on_delete_item = self.delete_item
@ -52,6 +54,8 @@ class Controller:
return False return False
return True return True
# Menu bar methods
def new(self): def new(self):
if self.is_dirty: if self.is_dirty:
reply = QMessageBox.question( reply = QMessageBox.question(
@ -106,6 +110,8 @@ class Controller:
self.is_dirty = False self.is_dirty = False
self.update_window_title() self.update_window_title()
# Display methods
def update_window_title(self): def update_window_title(self):
base = "WarChron" base = "WarChron"
if self.current_file: if self.current_file:
@ -124,17 +130,17 @@ class Controller:
wars = self.model.get_all_wars() wars = self.model.get_all_wars()
self.view.display_wars_tree(wars) self.view.display_wars_tree(wars)
def refresh_views(self):
current = self.view.get_current_tab()
if current == "players":
self.refresh_players_view()
elif current == "wars":
self.refresh_wars_view()
def _fill_war_details(self, war_id: str): def _fill_war_details(self, war_id: str):
war = self.model.get_war(war_id) war = self.model.get_war(war_id)
self.view.warName.setText(war.name) self.view.show_war_details(name=war.name, year=war.year)
self.view.warYear.setText(str(war.year)) objectives = war.get_all_objectives()
self.view.display_war_objectives(objectives)
participants = war.get_all_war_participants()
participants_for_display = [
(self.model.get_player_name(p.id), p.faction, p.id)
for p in participants
]
self.view.display_war_participants(participants_for_display)
def _fill_campaign_details(self, campaign_id: str): def _fill_campaign_details(self, campaign_id: str):
camp = self.model.get_campaign(campaign_id) camp = self.model.get_campaign(campaign_id)
@ -173,6 +179,118 @@ class Controller:
self.view.set_add_campaign_enabled(self.selected_war_id is not None) self.view.set_add_campaign_enabled(self.selected_war_id is not None)
self.view.set_add_round_enabled(self.selected_campaign_id is not None) self.view.set_add_round_enabled(self.selected_campaign_id is not None)
def refresh(self, scope: RefreshScope):
match scope:
case RefreshScope.PLAYERS_LIST:
self.refresh_players_view()
case RefreshScope.WARS_TREE:
self.refresh_wars_view()
case RefreshScope.WAR_DETAILS:
if self.selected_war_id:
self.view.show_details(ItemType.WAR)
self._fill_war_details(self.selected_war_id)
case RefreshScope.CAMPAIGN_DETAILS:
if self.selected_campaign_id:
self.view.show_details(ItemType.CAMPAIGN)
self._fill_campaign_details(self.selected_campaign_id)
case RefreshScope.ROUND_DETAILS:
if self.selected_round_id:
self.view.show_details(ItemType.ROUND)
self._fill_round_details(self.selected_round_id)
self.update_window_title()
# Common command methods
def refresh_and_select(self, scope: RefreshScope, *, item_type: ItemType, item_id: str):
self.refresh(scope)
self.view.select_tree_item(item_type=item_type, item_id=item_id)
def edit_item(self, item_type: str, item_id: str):
if item_type == ItemType.PLAYER:
play = self.model.get_player(item_id)
dialog = PlayerDialog(self.view, default_name=play.name)
if dialog.exec() == QDialog.DialogCode.Accepted:
name = 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:
war = self.model.get_war(item_id)
dialog = WarDialog(self.view, default_name=war.name, default_year=war.year)
if dialog.exec() == QDialog.DialogCode.Accepted:
name = dialog.get_war_name()
year = 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)
dialog = CampaignDialog(self.view, default_name=camp.name, default_month=camp.month)
if dialog.exec() == QDialog.DialogCode.Accepted:
name = dialog.get_campaign_name()
month = 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)
dialog = ObjectiveDialog(self.view, default_name=obj.name, default_description=obj.description)
if dialog.exec() == QDialog.DialogCode.Accepted:
name = dialog.get_objective_name()
description = 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:
part = self.model.get_war_participant(item_id)
player = self.model.get_player(part.id)
dialog = ParticipantDialog(self.view, players=[player], default_player_id=part.id, default_faction=part.faction)
if dialog.exec() == QDialog.DialogCode.Accepted:
id = dialog.get_player_id()
faction = dialog.get_participant_faction()
self.model.update_war_participant(item_id, faction=faction)
self.refresh(RefreshScope.WAR_DETAILS)
self.is_dirty = True
def delete_item(self, item_type: str, item_id: str):
reply = QMessageBox.question(
self.view,
"Confirm deletion",
"Are you sure you want to delete this item?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
if reply != QMessageBox.StandardButton.Yes:
return
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.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
# Player methods
def _validate_player_inputs(self, name: str) -> bool: def _validate_player_inputs(self, name: str) -> bool:
if not name.strip(): if not name.strip():
QMessageBox.warning( QMessageBox.warning(
@ -192,8 +310,9 @@ class Controller:
return return
self.model.add_player(name) self.model.add_player(name)
self.is_dirty = True self.is_dirty = True
self.refresh_players_view() self.refresh(RefreshScope.PLAYERS_LIST)
self.update_window_title()
# War methods
def _validate_war_inputs(self, name: str, year: int) -> bool: def _validate_war_inputs(self, name: str, year: int) -> bool:
if not name.strip(): if not name.strip():
@ -220,10 +339,54 @@ class Controller:
year = dialog.get_war_year() year = dialog.get_war_year()
if not self._validate_war_inputs(name, year): if not self._validate_war_inputs(name, year):
return return
self.model.add_war(name, year) war = self.model.add_war(name, year)
self.is_dirty = True self.is_dirty = True
self.refresh_wars_view() self.refresh_and_select(RefreshScope.WARS_TREE, item_type=ItemType.WAR, item_id=war.id)
self.update_window_title()
# Objective methods
def _validate_objective_inputs(self, name: str, description: int) -> bool:
if not name.strip():
QMessageBox.warning(
self.view,
"Invalid name",
"Campaign name cannot be empty."
)
return False
return True
def add_objective(self):
if not self.selected_war_id:
return
dialog = ObjectiveDialog(self.view)
if dialog.exec() != QDialog.DialogCode.Accepted:
return
name = dialog.get_objective_name()
description = dialog.get_objective_description()
if not name:
return
self.model.add_objective(self.selected_war_id, name, description)
self.is_dirty = True
self.refresh(RefreshScope.WAR_DETAILS)
# War participant methods
def add_war_participant(self):
if not self.selected_war_id:
return
players = self.model.get_available_players(self.selected_war_id)
dialog = ParticipantDialog(self.view, players=players)
if dialog.exec() != QDialog.DialogCode.Accepted:
return
player_id = dialog.get_player_id()
faction = dialog.get_participant_faction()
if not player_id:
return
self.model.add_war_participant(self.selected_war_id, player_id, faction)
self.is_dirty = True
self.refresh(RefreshScope.WAR_DETAILS)
# Campaign methods
def _validate_campaign_inputs(self, name: str, month: int) -> bool: def _validate_campaign_inputs(self, name: str, month: int) -> bool:
if not name.strip(): if not name.strip():
@ -252,66 +415,15 @@ class Controller:
month = dialog.get_campaign_month() month = dialog.get_campaign_month()
if not self._validate_campaign_inputs(name, month): if not self._validate_campaign_inputs(name, month):
return return
self.model.add_campaign(self.selected_war_id, name, month) camp = self.model.add_campaign(self.selected_war_id, name, month)
self.is_dirty = True self.is_dirty = True
self.refresh_wars_view() self.refresh_and_select(RefreshScope.WARS_TREE, item_type=ItemType.CAMPAIGN, item_id=camp.id)
self.update_window_title()
# Round methods
def add_round(self): def add_round(self):
if not self.selected_campaign_id: if not self.selected_campaign_id:
return return
self.model.add_round(self.selected_campaign_id) rnd = self.model.add_round(self.selected_campaign_id)
self.is_dirty = True self.is_dirty = True
self.refresh_wars_view() self.refresh_and_select(RefreshScope.WARS_TREE, item_type=ItemType.ROUND, item_id=rnd.id)
self.update_window_title()
def edit_item(self, item_type: str, item_id: str):
if item_type == "player":
play = self.model.get_player(item_id)
dialog = PlayerDialog(self.view, default_name=play.name)
if dialog.exec() == QDialog.DialogCode.Accepted:
name = dialog.get_player_name()
if not self._validate_player_inputs(name):
return
self.model.update_player(item_id, name=name)
elif item_type == "war":
war = self.model.get_war(item_id)
dialog = WarDialog(self.view, default_name=war.name, default_year=war.year)
if dialog.exec() == QDialog.DialogCode.Accepted:
name = dialog.get_war_name()
year = dialog.get_war_year()
if not self._validate_war_inputs(name, year):
return
self.model.update_war(item_id, name=name, year=year)
elif item_type == "campaign":
camp = self.model.get_campaign(item_id)
dialog = CampaignDialog(self.view, default_name=camp.name, default_month=camp.month)
if dialog.exec() == QDialog.DialogCode.Accepted:
name = dialog.get_campaign_name()
month = dialog.get_campaign_month()
if not self._validate_campaign_inputs(name, month):
return
self.model.update_campaign(item_id, name=name, month=month)
self.is_dirty = True
self.refresh_views()
def delete_item(self, item_type: str, item_id: str):
reply = QMessageBox.question(
self.view,
"Confirm deletion",
"Are you sure you want to delete this item?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
if reply != QMessageBox.StandardButton.Yes:
return
if item_type == "player":
self.model.remove_player(item_id)
elif item_type == "war":
self.model.remove_war(item_id)
elif item_type == "campaign":
self.model.remove_campaign(item_id)
elif item_type == "round":
self.model.remove_round(item_id)
self.is_dirty = True
self.refresh_views()

View file

@ -1,27 +1,29 @@
from __future__ import annotations
from uuid import uuid4 from uuid import uuid4
from datetime import datetime from datetime import datetime
from warchron.model.round import Round from warchron.model.round import Round
class Campaign: class Campaign:
def __init__(self, name, month): def __init__(self, name: str, month: int):
self.id = str(uuid4()) self.id: str = str(uuid4())
self.name = name self.name: str = name
self.month = month self.month: int = month
self.entrants = {} self.participants = {}
self.sectors = {}
self.rounds = [] self.rounds = []
self.is_over = False self.is_over = False
def set_id(self, new_id): def set_id(self, new_id: str):
self.id = new_id self.id = new_id
def set_name(self, new_name): def set_name(self, new_name: str):
self.name = new_name self.name = new_name
def set_month(self, new_month): def set_month(self, new_month: int):
self.month = new_month self.month = new_month
def set_state(self, new_state): def set_state(self, new_state: bool):
self.is_over = new_state self.is_over = new_state
def toDict(self): def toDict(self):
@ -29,7 +31,7 @@ class Campaign:
"id" : self.id, "id" : self.id,
"name" : self.name, "name" : self.name,
"month" : self.month, "month" : self.month,
# "entrants" : self.entrants, # "participants" : self.participants,
"rounds": [rnd.toDict() for rnd in self.rounds], "rounds": [rnd.toDict() for rnd in self.rounds],
"is_over": self.is_over "is_over": self.is_over
} }
@ -38,13 +40,16 @@ class Campaign:
def fromDict(data: dict): def fromDict(data: dict):
camp = Campaign(name=data["name"], month=data["month"]) camp = Campaign(name=data["name"], month=data["month"])
camp.set_id(data["id"]) camp.set_id(data["id"])
# camp.entrants = data.get("entrants", {}) # camp.participants = data.get("participants", {})
for rnd_data in data.get("rounds", []): for rnd_data in data.get("rounds", []):
camp.rounds.append(Round.fromDict(rnd_data)) camp.rounds.append(Round.fromDict(rnd_data))
camp.set_state(data.get("is_over", False)) camp.set_state(data.get("is_over", False))
return camp return camp
def get_round(self, round_id) -> Round: def has_round(self, round_id: str) -> bool:
return any(r.id == round_id for r in self.rounds)
def get_round(self, round_id: str) -> Round:
return self.rounds[round_id] return self.rounds[round_id]
def get_all_rounds(self) -> list[Round]: def get_all_rounds(self) -> list[Round]:
@ -65,3 +70,19 @@ class Campaign:
if rnd.id == round_id: if rnd.id == round_id:
return index return index
raise KeyError("Round not found in campaign") raise KeyError("Round not found in campaign")
class CampaignParticipant:
def __init__(self,war_participant_id: str, leader: str):
self.id: str = war_participant_id # ref to War.participants
self.leader: str = leader
self.victory_points = 0
self.objective_points = {}
class Sector:
def __init__(self, name: str, round_id: str, major_id: str, minor_id: str, influence_id: str):
self.id: str = str(uuid4())
self.name: str = name
self.major_objective_id: str = major_id
self.minor_objective_id: str = minor_id
self.influence_objective_id: str = influence_id
self.round_id: str = round_id

View file

@ -4,14 +4,16 @@ import shutil
from datetime import datetime from datetime import datetime
from warchron.model.player import Player from warchron.model.player import Player
from warchron.model.war import War from warchron.model.war import War, Objective, WarParticipant
from warchron.model.campaign import Campaign from warchron.model.campaign import Campaign
from warchron.model.round import Round from warchron.model.round import Round
class Model: class Model:
def __init__(self): def __init__(self):
self.players = {} self.players: dict[str, Player] = {}
self.wars = {} self.wars: dict[str, War] = {}
# File management methods
def new(self): def new(self):
self.players.clear() self.players.clear()
@ -53,6 +55,8 @@ class Model:
with open(path, "w", encoding="utf-8") as f: with open(path, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2) json.dump(data, f, indent=2)
# Player methods
def add_player(self, name): def add_player(self, name):
player = Player(name) player = Player(name)
self.players[player.id] = player self.players[player.id] = player
@ -61,16 +65,21 @@ class Model:
def get_player(self, id): def get_player(self, id):
return self.players[id] return self.players[id]
def get_player_name(self, player_id: str) -> str:
return self.players[player_id].name
def update_player(self, player_id: str, *, name: str): def update_player(self, player_id: str, *, name: str):
player = self.get_player(player_id) player = self.get_player(player_id)
player.set_name(name) player.set_name(name)
def delete_player(self, id):
del self.players[id]
def get_all_players(self) -> list[Player]: def get_all_players(self) -> list[Player]:
return list(self.players.values()) return list(self.players.values())
def remove_player(self, player_id: str):
del self.players[player_id]
# War methods
def get_default_war_values(self) -> dict: def get_default_war_values(self) -> dict:
return { return {
"year": datetime.now().year "year": datetime.now().year
@ -91,6 +100,20 @@ 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")
def get_war_by_objective(self, objective_id: str) -> War:
for war in self.wars.values():
for obj in war.objectives.values():
if obj.id == objective_id:
return war
raise KeyError(f"Objective {objective_id} not found in any War")
def get_war_by_war_participant(self, participant_id: str) -> War:
for war in self.wars.values():
for part in war.participants.values():
if part.id == participant_id:
return war
raise KeyError(f"Participant {participant_id} not found in any War")
def update_war(self, war_id: str, *, name: str, year: int): def update_war(self, war_id: str, *, name: str, year: int):
war = self.get_war(war_id) war = self.get_war(war_id)
war.set_name(name) war.set_name(name)
@ -99,6 +122,61 @@ class Model:
def get_all_wars(self) -> list[War]: def get_all_wars(self) -> list[War]:
return list(self.wars.values()) return list(self.wars.values())
def remove_war(self, war_id: str):
del self.wars[war_id]
# Objective methods
def add_objective(self, war_id: str, name: str, description: str) -> Objective:
war = self.get_war(war_id)
return war.add_objective(name, description)
def get_objective(self, objective_id) -> Objective:
for war in self.wars.values():
for obj in war.objectives.values():
if obj.id == objective_id:
return obj
raise KeyError("Objective not found")
def update_objective(self, objective_id: str, *, name: str, description: str):
war = self.get_war_by_objective(objective_id)
war.update_objective(objective_id, name=name, description=description)
def remove_objective(self, objective_id: str):
war = self.get_war_by_objective(objective_id)
war.remove_objective(objective_id)
# War participant methods
def get_available_players(self, war_id: str) -> list[Player]:
war = self.get_war(war_id)
return [
player
for player in self.players.values()
if not war.has_participant(player.id)
]
def add_war_participant(self, war_id: str, player_id: str, faction: str) -> Objective:
war = self.get_war(war_id)
return war.add_war_participant(player_id, faction)
def get_war_participant(self, participant_id) -> WarParticipant:
for war in self.wars.values():
for part in war.participants.values():
if part.id == participant_id:
return part
raise KeyError("Participant not found")
def update_war_participant(self, participant_id: str, *, faction: str):
war = self.get_war_by_war_participant(participant_id)
war.update_war_participant(participant_id, faction=faction)
def remove_war_participant(self, participant_id: str):
war = self.get_war_by_war_participant(participant_id)
war.remove_war_participant(participant_id)
# Campaign methods
def get_default_campaign_values(self, war_id: str) -> dict: def get_default_campaign_values(self, war_id: str) -> dict:
war = self.get_war(war_id) war = self.get_war(war_id)
return war.get_default_campaign_values() return war.get_default_campaign_values()
@ -125,6 +203,12 @@ class Model:
war = self.get_war_by_campaign(campaign_id) war = self.get_war_by_campaign(campaign_id)
war.update_campaign(campaign_id, name=name, month=month) war.update_campaign(campaign_id, name=name, month=month)
def remove_campaign(self, campaign_id: str):
war = self.get_war_by_campaign(campaign_id)
war.remove_campaign(campaign_id)
# Round methods
def add_round(self, campaign_id: str) -> Round: def add_round(self, campaign_id: str) -> Round:
campaign = self.get_campaign(campaign_id) campaign = self.get_campaign(campaign_id)
return campaign.add_round() return campaign.add_round()
@ -141,16 +225,6 @@ class Model:
camp = self.get_campaign_by_round(round_id) camp = self.get_campaign_by_round(round_id)
return camp.get_round_index(round_id) return camp.get_round_index(round_id)
def remove_player(self, player_id: str):
del self.players[player_id]
def remove_war(self, war_id: str):
del self.wars[war_id]
def remove_campaign(self, campaign_id: str):
war = self.get_war_by_campaign(campaign_id)
war.remove_campaign(campaign_id)
def remove_round(self, round_id: str): def remove_round(self, round_id: str):
camp = self.get_campaign_by_round(round_id) camp = self.get_campaign_by_round(round_id)
camp.remove_round(round_id) camp.remove_round(round_id)

View file

@ -2,16 +2,16 @@ from uuid import uuid4
class Round: class Round:
def __init__(self): def __init__(self):
self.id = str(uuid4()) self.id: str = str(uuid4())
self.sectors = {} self.sectors = {}
self.choices = {} self.choices = {}
self.battles = {} self.battles = {}
self.is_over = False self.is_over: bool = False
def set_id(self, new_id): def set_id(self, new_id: str):
self.id = new_id self.id = new_id
def set_state(self, new_state): def set_state(self, new_state: bool):
self.is_over = new_state self.is_over = new_state
def toDict(self): def toDict(self):

View file

@ -1,27 +1,30 @@
from __future__ import annotations
from uuid import uuid4 from uuid import uuid4
from datetime import datetime from datetime import datetime
from warchron.model.campaign import Campaign from warchron.model.campaign import Campaign
class War:
def __init__(self, name, year):
self.id = str(uuid4())
self.name = name
self.year = year
self.entrants = {}
self.campaigns = []
self.is_over = False
def set_id(self, new_id): class War:
def __init__(self, name: str, year: int):
self.id: str = str(uuid4())
self.name: str = name
self.year: int = year
self.participants: dict[str, WarParticipant] = {}
self.objectives: dict[str, Objective] = {}
self.campaigns = []
self.is_over: bool = False
def set_id(self, new_id: str):
self.id = new_id self.id = new_id
def set_name(self, new_name): def set_name(self, new_name: str):
self.name = new_name self.name = new_name
def set_year(self, new_year): def set_year(self, new_year: int):
self.year = new_year self.year = new_year
def set_state(self, new_state): def set_state(self, new_state: bool):
self.is_over = new_state self.is_over = new_state
def toDict(self): def toDict(self):
@ -29,7 +32,7 @@ class War:
"id" : self.id, "id" : self.id,
"name" : self.name, "name" : self.name,
"year" : self.year, "year" : self.year,
# "entrants" : self.entrants, # "participants" : self.participants,
"campaigns": [camp.toDict() for camp in self.campaigns], "campaigns": [camp.toDict() for camp in self.campaigns],
"is_over": self.is_over "is_over": self.is_over
} }
@ -38,12 +41,66 @@ class War:
def fromDict(data: dict): def fromDict(data: dict):
war = War(name=data["name"], year=data["year"]) war = War(name=data["name"], year=data["year"])
war.set_id(data["id"]) war.set_id(data["id"])
# war.entrants = data.get("entrants", {}) # war.participants = data.get("participants", {})
for camp_data in data.get("campaigns", []): for camp_data in data.get("campaigns", []):
war.campaigns.append(Campaign.fromDict(camp_data)) war.campaigns.append(Campaign.fromDict(camp_data))
war.set_state(data.get("is_over", False)) war.set_state(data.get("is_over", False))
return war return war
# Objective methods
def add_objective(self, name: str, description: str) -> Objective:
objective = Objective(name, description)
self.objectives[objective.id] = objective
return objective
def get_objective(self, id: str) -> Objective:
return self.objectives[id]
def get_all_objectives(self) -> list[Objective]:
return list(self.objectives.values())
def update_objective(self, objective_id: str, *, name: str, description: str):
obj = self.get_objective(objective_id)
obj.set_name(name)
obj.set_description(description)
def remove_objective(self, objective_id: str):
del self.objectives[objective_id]
# War participant methods
def get_all_war_participants_ids(self) -> set[str]:
return set(self.participants.keys())
def has_participant(self, player_id: str) -> bool:
return player_id in self.participants
def add_war_participant(self, player_id: str, faction: str) -> WarParticipant:
if player_id in self.participants:
raise ValueError("Player already registered in this war")
participant = WarParticipant(player_id, faction)
self.participants[participant.id] = participant
return participant
def get_war_participant(self, id: str) -> WarParticipant:
return self.participants[id]
def get_all_war_participants(self) -> list[WarParticipant]:
return list(self.participants.values())
def update_war_participant(self, player_id: str, *, faction: str):
part = self.get_war_participant(player_id)
part.set_faction(faction)
def remove_war_participant(self, player_id: str):
del self.participants[player_id]
# Campaign methods
def has_campaign(self, campaign_id: str) -> bool:
return any(c.id == campaign_id for c in self.campaigns)
def get_default_campaign_values(self) -> dict: def get_default_campaign_values(self) -> dict:
return { return {
"month": datetime.now().month "month": datetime.now().month
@ -56,7 +113,7 @@ class War:
self.campaigns.append(campaign) self.campaigns.append(campaign)
return campaign return campaign
def get_campaign(self, campaign_id) -> Campaign: def get_campaign(self, campaign_id: str) -> Campaign:
for camp in self.campaigns: for camp in self.campaigns:
if camp.id == campaign_id: if camp.id == campaign_id:
return camp return camp
@ -80,3 +137,30 @@ class War:
def remove_campaign(self, campaign_id: str): def remove_campaign(self, campaign_id: str):
camp = self.get_campaign(campaign_id) camp = self.get_campaign(campaign_id)
self.campaigns.remove(camp) self.campaigns.remove(camp)
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):
self.id = new_id
def set_name(self, new_name: str):
self.name = new_name
def set_description(self, new_description: str):
self.description = new_description
class WarParticipant:
def __init__(self, player_id: str, faction: str):
self.id: str = player_id # ref to Model.players
self.faction: str = faction
def set_id(self, new_id: str):
self.id = new_id
def set_faction(self, new_faction: str):
self.faction = new_faction

View file

@ -81,44 +81,50 @@ class Ui_MainWindow(object):
font.setPointSize(12) font.setPointSize(12)
self.warYear.setFont(font) self.warYear.setFont(font)
self.warYear.setObjectName("warYear") self.warYear.setObjectName("warYear")
self.labelEntrants = QtWidgets.QLabel(parent=self.pageWar) self.labelParticipants = QtWidgets.QLabel(parent=self.pageWar)
self.labelEntrants.setGeometry(QtCore.QRect(10, 150, 111, 16)) self.labelParticipants.setGeometry(QtCore.QRect(10, 150, 111, 16))
self.labelEntrants.setObjectName("labelEntrants") self.labelParticipants.setObjectName("labelParticipants")
self.addEntrantBtn = QtWidgets.QPushButton(parent=self.pageWar) self.addWarParticipantBtn = QtWidgets.QPushButton(parent=self.pageWar)
self.addEntrantBtn.setGeometry(QtCore.QRect(420, 270, 81, 23)) self.addWarParticipantBtn.setGeometry(QtCore.QRect(420, 270, 81, 23))
self.addEntrantBtn.setObjectName("addEntrantBtn") self.addWarParticipantBtn.setObjectName("addWarParticipantBtn")
self.playersTable_2 = QtWidgets.QTableWidget(parent=self.pageWar) self.warParticipantsTable = QtWidgets.QTableWidget(parent=self.pageWar)
self.playersTable_2.setGeometry(QtCore.QRect(10, 170, 401, 211)) self.warParticipantsTable.setGeometry(QtCore.QRect(10, 170, 401, 211))
self.playersTable_2.setObjectName("playersTable_2") self.warParticipantsTable.setObjectName("warParticipantsTable")
self.playersTable_2.setColumnCount(5) self.warParticipantsTable.setColumnCount(5)
self.playersTable_2.setRowCount(0) self.warParticipantsTable.setRowCount(0)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_2.setHorizontalHeaderItem(0, item) self.warParticipantsTable.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_2.setHorizontalHeaderItem(1, item) self.warParticipantsTable.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_2.setHorizontalHeaderItem(2, item) self.warParticipantsTable.setHorizontalHeaderItem(2, item)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_2.setHorizontalHeaderItem(3, item) self.warParticipantsTable.setHorizontalHeaderItem(3, item)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_2.setHorizontalHeaderItem(4, item) self.warParticipantsTable.setHorizontalHeaderItem(4, item)
self.addRoundBtn_8 = QtWidgets.QPushButton(parent=self.pageWar) self.endWarBtn = QtWidgets.QPushButton(parent=self.pageWar)
self.addRoundBtn_8.setEnabled(True) self.endWarBtn.setEnabled(True)
self.addRoundBtn_8.setGeometry(QtCore.QRect(230, 400, 61, 23)) self.endWarBtn.setGeometry(QtCore.QRect(230, 400, 61, 23))
self.addRoundBtn_8.setObjectName("addRoundBtn_8") self.endWarBtn.setObjectName("endWarBtn")
self.listObjectives = QtWidgets.QListWidget(parent=self.pageWar) self.objectivesTable = QtWidgets.QTableWidget(parent=self.pageWar)
self.listObjectives.setGeometry(QtCore.QRect(10, 60, 161, 71)) self.objectivesTable.setGeometry(QtCore.QRect(10, 60, 401, 71))
self.listObjectives.setObjectName("listObjectives") self.objectivesTable.setObjectName("objectivesTable")
self.objectivesTable.setColumnCount(2)
self.objectivesTable.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.objectivesTable.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.objectivesTable.setHorizontalHeaderItem(1, item)
self.labelObjectives = QtWidgets.QLabel(parent=self.pageWar) self.labelObjectives = QtWidgets.QLabel(parent=self.pageWar)
self.labelObjectives.setGeometry(QtCore.QRect(10, 40, 111, 20)) self.labelObjectives.setGeometry(QtCore.QRect(10, 40, 111, 20))
self.labelObjectives.setObjectName("labelObjectives") self.labelObjectives.setObjectName("labelObjectives")
self.addCampaignBtn_3 = QtWidgets.QPushButton(parent=self.pageWar) self.addObjectiveBtn = QtWidgets.QPushButton(parent=self.pageWar)
self.addCampaignBtn_3.setEnabled(True) self.addObjectiveBtn.setEnabled(True)
self.addCampaignBtn_3.setGeometry(QtCore.QRect(180, 80, 91, 23)) self.addObjectiveBtn.setGeometry(QtCore.QRect(420, 80, 91, 23))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(10) font.setPointSize(10)
self.addCampaignBtn_3.setFont(font) self.addObjectiveBtn.setFont(font)
self.addCampaignBtn_3.setObjectName("addCampaignBtn_3") self.addObjectiveBtn.setObjectName("addObjectiveBtn")
self.selectedDetailsStack.addWidget(self.pageWar) self.selectedDetailsStack.addWidget(self.pageWar)
self.pageCampaign = QtWidgets.QWidget() self.pageCampaign = QtWidgets.QWidget()
self.pageCampaign.setObjectName("pageCampaign") self.pageCampaign.setObjectName("pageCampaign")
@ -128,49 +134,49 @@ class Ui_MainWindow(object):
font.setPointSize(12) font.setPointSize(12)
self.campaignName.setFont(font) self.campaignName.setFont(font)
self.campaignName.setObjectName("campaignName") self.campaignName.setObjectName("campaignName")
self.labelRound = QtWidgets.QLabel(parent=self.pageCampaign) self.labelSectors = QtWidgets.QLabel(parent=self.pageCampaign)
self.labelRound.setGeometry(QtCore.QRect(10, 40, 91, 16)) self.labelSectors.setGeometry(QtCore.QRect(10, 40, 91, 16))
self.labelRound.setObjectName("labelRound") self.labelSectors.setObjectName("labelSectors")
self.addEntrantBtn_2 = QtWidgets.QPushButton(parent=self.pageCampaign) self.addCampaignParticipantBtn = QtWidgets.QPushButton(parent=self.pageCampaign)
self.addEntrantBtn_2.setGeometry(QtCore.QRect(420, 270, 75, 23)) self.addCampaignParticipantBtn.setGeometry(QtCore.QRect(420, 270, 75, 23))
self.addEntrantBtn_2.setObjectName("addEntrantBtn_2") self.addCampaignParticipantBtn.setObjectName("addCampaignParticipantBtn")
self.campaignMonth = QtWidgets.QLabel(parent=self.pageCampaign) self.campaignMonth = QtWidgets.QLabel(parent=self.pageCampaign)
self.campaignMonth.setGeometry(QtCore.QRect(280, 10, 121, 16)) self.campaignMonth.setGeometry(QtCore.QRect(280, 10, 121, 16))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(12) font.setPointSize(12)
self.campaignMonth.setFont(font) self.campaignMonth.setFont(font)
self.campaignMonth.setObjectName("campaignMonth") self.campaignMonth.setObjectName("campaignMonth")
self.labelEntrants_2 = QtWidgets.QLabel(parent=self.pageCampaign) self.labelParticipants_2 = QtWidgets.QLabel(parent=self.pageCampaign)
self.labelEntrants_2.setGeometry(QtCore.QRect(10, 180, 47, 13)) self.labelParticipants_2.setGeometry(QtCore.QRect(10, 180, 47, 13))
self.labelEntrants_2.setObjectName("labelEntrants_2") self.labelParticipants_2.setObjectName("labelParticipants_2")
self.playersTable_3 = QtWidgets.QTableWidget(parent=self.pageCampaign) self.campaignParticipantsTable = QtWidgets.QTableWidget(parent=self.pageCampaign)
self.playersTable_3.setGeometry(QtCore.QRect(10, 200, 401, 181)) self.campaignParticipantsTable.setGeometry(QtCore.QRect(10, 200, 401, 181))
self.playersTable_3.setObjectName("playersTable_3") self.campaignParticipantsTable.setObjectName("campaignParticipantsTable")
self.playersTable_3.setColumnCount(4) self.campaignParticipantsTable.setColumnCount(4)
self.playersTable_3.setRowCount(0) self.campaignParticipantsTable.setRowCount(0)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_3.setHorizontalHeaderItem(0, item) self.campaignParticipantsTable.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_3.setHorizontalHeaderItem(1, item) self.campaignParticipantsTable.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_3.setHorizontalHeaderItem(2, item) self.campaignParticipantsTable.setHorizontalHeaderItem(2, item)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_3.setHorizontalHeaderItem(3, item) self.campaignParticipantsTable.setHorizontalHeaderItem(3, item)
self.playersTable_4 = QtWidgets.QTableWidget(parent=self.pageCampaign) self.sectorsTable = QtWidgets.QTableWidget(parent=self.pageCampaign)
self.playersTable_4.setGeometry(QtCore.QRect(10, 60, 401, 101)) self.sectorsTable.setGeometry(QtCore.QRect(10, 60, 401, 101))
self.playersTable_4.setObjectName("playersTable_4") self.sectorsTable.setObjectName("sectorsTable")
self.playersTable_4.setColumnCount(5) self.sectorsTable.setColumnCount(5)
self.playersTable_4.setRowCount(0) self.sectorsTable.setRowCount(0)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_4.setHorizontalHeaderItem(0, item) self.sectorsTable.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_4.setHorizontalHeaderItem(1, item) self.sectorsTable.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_4.setHorizontalHeaderItem(2, item) self.sectorsTable.setHorizontalHeaderItem(2, item)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_4.setHorizontalHeaderItem(3, item) self.sectorsTable.setHorizontalHeaderItem(3, item)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_4.setHorizontalHeaderItem(4, item) self.sectorsTable.setHorizontalHeaderItem(4, item)
self.addSectorBtn = QtWidgets.QPushButton(parent=self.pageCampaign) self.addSectorBtn = QtWidgets.QPushButton(parent=self.pageCampaign)
self.addSectorBtn.setEnabled(True) self.addSectorBtn.setEnabled(True)
self.addSectorBtn.setGeometry(QtCore.QRect(420, 110, 71, 23)) self.addSectorBtn.setGeometry(QtCore.QRect(420, 110, 71, 23))
@ -202,32 +208,32 @@ class Ui_MainWindow(object):
font.setPointSize(12) font.setPointSize(12)
self.roundNb.setFont(font) self.roundNb.setFont(font)
self.roundNb.setObjectName("roundNb") self.roundNb.setObjectName("roundNb")
self.resolveBtn = QtWidgets.QPushButton(parent=self.pageRound) self.resolvePairingBtn = QtWidgets.QPushButton(parent=self.pageRound)
self.resolveBtn.setEnabled(True) self.resolvePairingBtn.setEnabled(True)
self.resolveBtn.setGeometry(QtCore.QRect(320, 110, 91, 23)) self.resolvePairingBtn.setGeometry(QtCore.QRect(320, 110, 91, 23))
self.resolveBtn.setObjectName("resolveBtn") self.resolvePairingBtn.setObjectName("resolvePairingBtn")
self.playersTable_6 = QtWidgets.QTableWidget(parent=self.pageRound) self.battlesTable = QtWidgets.QTableWidget(parent=self.pageRound)
self.playersTable_6.setGeometry(QtCore.QRect(10, 240, 301, 111)) self.battlesTable.setGeometry(QtCore.QRect(10, 240, 301, 111))
self.playersTable_6.setObjectName("playersTable_6") self.battlesTable.setObjectName("battlesTable")
self.playersTable_6.setColumnCount(3) self.battlesTable.setColumnCount(3)
self.playersTable_6.setRowCount(0) self.battlesTable.setRowCount(0)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_6.setHorizontalHeaderItem(0, item) self.battlesTable.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_6.setHorizontalHeaderItem(1, item) self.battlesTable.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem() item = QtWidgets.QTableWidgetItem()
self.playersTable_6.setHorizontalHeaderItem(2, item) self.battlesTable.setHorizontalHeaderItem(2, item)
self.resultBtn = QtWidgets.QPushButton(parent=self.pageRound) self.enterResultBtn = QtWidgets.QPushButton(parent=self.pageRound)
self.resultBtn.setEnabled(True) self.enterResultBtn.setEnabled(True)
self.resultBtn.setGeometry(QtCore.QRect(320, 290, 91, 23)) self.enterResultBtn.setGeometry(QtCore.QRect(320, 290, 91, 23))
self.resultBtn.setObjectName("resultBtn") self.enterResultBtn.setObjectName("enterResultBtn")
self.endRoundBtn = QtWidgets.QPushButton(parent=self.pageRound) self.endRoundBtn = QtWidgets.QPushButton(parent=self.pageRound)
self.endRoundBtn.setEnabled(True) self.endRoundBtn.setEnabled(True)
self.endRoundBtn.setGeometry(QtCore.QRect(220, 400, 71, 23)) self.endRoundBtn.setGeometry(QtCore.QRect(220, 400, 71, 23))
self.endRoundBtn.setObjectName("endRoundBtn") self.endRoundBtn.setObjectName("endRoundBtn")
self.labelChoices_2 = QtWidgets.QLabel(parent=self.pageRound) self.labelBattles = QtWidgets.QLabel(parent=self.pageRound)
self.labelChoices_2.setGeometry(QtCore.QRect(10, 220, 91, 16)) self.labelBattles.setGeometry(QtCore.QRect(10, 220, 91, 16))
self.labelChoices_2.setObjectName("labelChoices_2") self.labelBattles.setObjectName("labelBattles")
self.selectedDetailsStack.addWidget(self.pageRound) self.selectedDetailsStack.addWidget(self.pageRound)
icon2 = QtGui.QIcon() icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(".\\src\\warchron\\view\\ui\\../resources/swords-small.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) icon2.addPixmap(QtGui.QPixmap(".\\src\\warchron\\view\\ui\\../resources/swords-small.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
@ -331,43 +337,47 @@ class Ui_MainWindow(object):
self.labelSelect.setText(_translate("MainWindow", "Select an element within the tree to show/edit details.")) self.labelSelect.setText(_translate("MainWindow", "Select an element within the tree to show/edit details."))
self.warName.setText(_translate("MainWindow", "warName")) self.warName.setText(_translate("MainWindow", "warName"))
self.warYear.setText(_translate("MainWindow", "warYear")) self.warYear.setText(_translate("MainWindow", "warYear"))
self.labelEntrants.setText(_translate("MainWindow", "Entrants")) self.labelParticipants.setText(_translate("MainWindow", "Participants"))
self.addEntrantBtn.setText(_translate("MainWindow", "Add entrant")) self.addWarParticipantBtn.setText(_translate("MainWindow", "Add participant"))
item = self.playersTable_2.horizontalHeaderItem(0) item = self.warParticipantsTable.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "Name")) item.setText(_translate("MainWindow", "Name"))
item = self.playersTable_2.horizontalHeaderItem(1) item = self.warParticipantsTable.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "Faction")) item.setText(_translate("MainWindow", "Faction"))
item = self.playersTable_2.horizontalHeaderItem(2) item = self.warParticipantsTable.horizontalHeaderItem(2)
item.setText(_translate("MainWindow", "Campaigns")) item.setText(_translate("MainWindow", "Campaigns"))
item = self.playersTable_2.horizontalHeaderItem(3) item = self.warParticipantsTable.horizontalHeaderItem(3)
item.setText(_translate("MainWindow", "Victory pts.")) item.setText(_translate("MainWindow", "Victory pts."))
item = self.playersTable_2.horizontalHeaderItem(4) item = self.warParticipantsTable.horizontalHeaderItem(4)
item.setText(_translate("MainWindow", "Theme pts")) item.setText(_translate("MainWindow", "Theme pts"))
self.addRoundBtn_8.setText(_translate("MainWindow", "End war")) self.endWarBtn.setText(_translate("MainWindow", "End war"))
item = self.objectivesTable.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "Name"))
item = self.objectivesTable.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "Description"))
self.labelObjectives.setText(_translate("MainWindow", "Objectives")) self.labelObjectives.setText(_translate("MainWindow", "Objectives"))
self.addCampaignBtn_3.setText(_translate("MainWindow", "Add objective")) self.addObjectiveBtn.setText(_translate("MainWindow", "Add objective"))
self.campaignName.setText(_translate("MainWindow", "campaignName")) self.campaignName.setText(_translate("MainWindow", "campaignName"))
self.labelRound.setText(_translate("MainWindow", "Sectors")) self.labelSectors.setText(_translate("MainWindow", "Sectors"))
self.addEntrantBtn_2.setText(_translate("MainWindow", "Add entrant")) self.addCampaignParticipantBtn.setText(_translate("MainWindow", "Add participant"))
self.campaignMonth.setText(_translate("MainWindow", "campaignMonth")) self.campaignMonth.setText(_translate("MainWindow", "campaignMonth"))
self.labelEntrants_2.setText(_translate("MainWindow", "Entrants")) self.labelParticipants_2.setText(_translate("MainWindow", "Participants"))
item = self.playersTable_3.horizontalHeaderItem(0) item = self.campaignParticipantsTable.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "Name")) item.setText(_translate("MainWindow", "Name"))
item = self.playersTable_3.horizontalHeaderItem(1) item = self.campaignParticipantsTable.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "Leader")) item.setText(_translate("MainWindow", "Leader"))
item = self.playersTable_3.horizontalHeaderItem(2) item = self.campaignParticipantsTable.horizontalHeaderItem(2)
item.setText(_translate("MainWindow", "Victory pts.")) item.setText(_translate("MainWindow", "Victory pts."))
item = self.playersTable_3.horizontalHeaderItem(3) item = self.campaignParticipantsTable.horizontalHeaderItem(3)
item.setText(_translate("MainWindow", "Theme pts.")) item.setText(_translate("MainWindow", "Theme pts."))
item = self.playersTable_4.horizontalHeaderItem(0) item = self.sectorsTable.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "Name")) item.setText(_translate("MainWindow", "Name"))
item = self.playersTable_4.horizontalHeaderItem(1) item = self.sectorsTable.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "Round")) item.setText(_translate("MainWindow", "Round"))
item = self.playersTable_4.horizontalHeaderItem(2) item = self.sectorsTable.horizontalHeaderItem(2)
item.setText(_translate("MainWindow", "Major obj.")) item.setText(_translate("MainWindow", "Major obj."))
item = self.playersTable_4.horizontalHeaderItem(3) item = self.sectorsTable.horizontalHeaderItem(3)
item.setText(_translate("MainWindow", "Minor opp.")) item.setText(_translate("MainWindow", "Minor opp."))
item = self.playersTable_4.horizontalHeaderItem(4) item = self.sectorsTable.horizontalHeaderItem(4)
item.setText(_translate("MainWindow", "Influence imp.")) item.setText(_translate("MainWindow", "Influence imp."))
self.addSectorBtn.setText(_translate("MainWindow", "Add Sector")) self.addSectorBtn.setText(_translate("MainWindow", "Add Sector"))
self.endCampaignBtn.setText(_translate("MainWindow", "End campaign")) self.endCampaignBtn.setText(_translate("MainWindow", "End campaign"))
@ -379,16 +389,16 @@ class Ui_MainWindow(object):
item = self.choicesTable.horizontalHeaderItem(2) item = self.choicesTable.horizontalHeaderItem(2)
item.setText(_translate("MainWindow", "Secondary")) item.setText(_translate("MainWindow", "Secondary"))
self.roundNb.setText(_translate("MainWindow", "Round Nb")) self.roundNb.setText(_translate("MainWindow", "Round Nb"))
self.resolveBtn.setText(_translate("MainWindow", "Resolve pairing")) self.resolvePairingBtn.setText(_translate("MainWindow", "Resolve pairing"))
item = self.playersTable_6.horizontalHeaderItem(0) item = self.battlesTable.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "Sector")) item.setText(_translate("MainWindow", "Sector"))
item = self.playersTable_6.horizontalHeaderItem(1) item = self.battlesTable.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "Player 1")) item.setText(_translate("MainWindow", "Player 1"))
item = self.playersTable_6.horizontalHeaderItem(2) item = self.battlesTable.horizontalHeaderItem(2)
item.setText(_translate("MainWindow", "Player 2")) item.setText(_translate("MainWindow", "Player 2"))
self.resultBtn.setText(_translate("MainWindow", "Enter results")) self.enterResultBtn.setText(_translate("MainWindow", "Enter results"))
self.endRoundBtn.setText(_translate("MainWindow", "End round")) self.endRoundBtn.setText(_translate("MainWindow", "End round"))
self.labelChoices_2.setText(_translate("MainWindow", "Battles")) self.labelBattles.setText(_translate("MainWindow", "Battles"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.warsTab), _translate("MainWindow", "Wars")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.warsTab), _translate("MainWindow", "Wars"))
self.menuFile.setTitle(_translate("MainWindow", "File")) self.menuFile.setTitle(_translate("MainWindow", "File"))
self.menuEdit.setTitle(_translate("MainWindow", "Edit")) self.menuEdit.setTitle(_translate("MainWindow", "Edit"))

View file

@ -214,7 +214,7 @@
<string>warYear</string> <string>warYear</string>
</property> </property>
</widget> </widget>
<widget class="QLabel" name="labelEntrants"> <widget class="QLabel" name="labelParticipants">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>10</x>
@ -224,10 +224,10 @@
</rect> </rect>
</property> </property>
<property name="text"> <property name="text">
<string>Entrants</string> <string>Participants</string>
</property> </property>
</widget> </widget>
<widget class="QPushButton" name="addEntrantBtn"> <widget class="QPushButton" name="addWarParticipantBtn">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>420</x> <x>420</x>
@ -237,10 +237,10 @@
</rect> </rect>
</property> </property>
<property name="text"> <property name="text">
<string>Add entrant</string> <string>Add participant</string>
</property> </property>
</widget> </widget>
<widget class="QTableWidget" name="playersTable_2"> <widget class="QTableWidget" name="warParticipantsTable">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>10</x>
@ -275,7 +275,7 @@
</property> </property>
</column> </column>
</widget> </widget>
<widget class="QPushButton" name="addRoundBtn_8"> <widget class="QPushButton" name="endWarBtn">
<property name="enabled"> <property name="enabled">
<bool>true</bool> <bool>true</bool>
</property> </property>
@ -291,15 +291,25 @@
<string>End war</string> <string>End war</string>
</property> </property>
</widget> </widget>
<widget class="QListWidget" name="listObjectives"> <widget class="QTableWidget" name="objectivesTable">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>10</x>
<y>60</y> <y>60</y>
<width>161</width> <width>401</width>
<height>71</height> <height>71</height>
</rect> </rect>
</property> </property>
<column>
<property name="text">
<string>Name</string>
</property>
</column>
<column>
<property name="text">
<string>Description</string>
</property>
</column>
</widget> </widget>
<widget class="QLabel" name="labelObjectives"> <widget class="QLabel" name="labelObjectives">
<property name="geometry"> <property name="geometry">
@ -314,13 +324,13 @@
<string>Objectives</string> <string>Objectives</string>
</property> </property>
</widget> </widget>
<widget class="QPushButton" name="addCampaignBtn_3"> <widget class="QPushButton" name="addObjectiveBtn">
<property name="enabled"> <property name="enabled">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>180</x> <x>420</x>
<y>80</y> <y>80</y>
<width>91</width> <width>91</width>
<height>23</height> <height>23</height>
@ -355,7 +365,7 @@
<string>campaignName</string> <string>campaignName</string>
</property> </property>
</widget> </widget>
<widget class="QLabel" name="labelRound"> <widget class="QLabel" name="labelSectors">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>10</x>
@ -368,7 +378,7 @@
<string>Sectors</string> <string>Sectors</string>
</property> </property>
</widget> </widget>
<widget class="QPushButton" name="addEntrantBtn_2"> <widget class="QPushButton" name="addCampaignParticipantBtn">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>420</x> <x>420</x>
@ -378,7 +388,7 @@
</rect> </rect>
</property> </property>
<property name="text"> <property name="text">
<string>Add entrant</string> <string>Add participant</string>
</property> </property>
</widget> </widget>
<widget class="QLabel" name="campaignMonth"> <widget class="QLabel" name="campaignMonth">
@ -399,7 +409,7 @@
<string>campaignMonth</string> <string>campaignMonth</string>
</property> </property>
</widget> </widget>
<widget class="QLabel" name="labelEntrants_2"> <widget class="QLabel" name="labelParticipants_2">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>10</x>
@ -409,10 +419,10 @@
</rect> </rect>
</property> </property>
<property name="text"> <property name="text">
<string>Entrants</string> <string>Participants</string>
</property> </property>
</widget> </widget>
<widget class="QTableWidget" name="playersTable_3"> <widget class="QTableWidget" name="campaignParticipantsTable">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>10</x>
@ -442,7 +452,7 @@
</property> </property>
</column> </column>
</widget> </widget>
<widget class="QTableWidget" name="playersTable_4"> <widget class="QTableWidget" name="sectorsTable">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>10</x>
@ -567,7 +577,7 @@
<string>Round Nb</string> <string>Round Nb</string>
</property> </property>
</widget> </widget>
<widget class="QPushButton" name="resolveBtn"> <widget class="QPushButton" name="resolvePairingBtn">
<property name="enabled"> <property name="enabled">
<bool>true</bool> <bool>true</bool>
</property> </property>
@ -583,7 +593,7 @@
<string>Resolve pairing</string> <string>Resolve pairing</string>
</property> </property>
</widget> </widget>
<widget class="QTableWidget" name="playersTable_6"> <widget class="QTableWidget" name="battlesTable">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>10</x>
@ -608,7 +618,7 @@
</property> </property>
</column> </column>
</widget> </widget>
<widget class="QPushButton" name="resultBtn"> <widget class="QPushButton" name="enterResultBtn">
<property name="enabled"> <property name="enabled">
<bool>true</bool> <bool>true</bool>
</property> </property>
@ -640,7 +650,7 @@
<string>End round</string> <string>End round</string>
</property> </property>
</widget> </widget>
<widget class="QLabel" name="labelChoices_2"> <widget class="QLabel" name="labelBattles">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>10</x>

View file

@ -0,0 +1,59 @@
# Form implementation generated from reading ui file '.\src\warchron\view\ui\ui_objective_dialog.ui'
#
# Created by: PyQt6 UI code generator 6.7.1
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_objectiveDialog(object):
def setupUi(self, objectiveDialog):
objectiveDialog.setObjectName("objectiveDialog")
objectiveDialog.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
objectiveDialog.resize(394, 148)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(".\\src\\warchron\\view\\ui\\../resources/warchron_logo.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
objectiveDialog.setWindowIcon(icon)
self.gridLayout = QtWidgets.QGridLayout(objectiveDialog)
self.gridLayout.setObjectName("gridLayout")
self.label = QtWidgets.QLabel(parent=objectiveDialog)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.objectiveName = QtWidgets.QLineEdit(parent=objectiveDialog)
self.objectiveName.setObjectName("objectiveName")
self.gridLayout.addWidget(self.objectiveName, 0, 1, 1, 1)
self.label_2 = QtWidgets.QLabel(parent=objectiveDialog)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
self.objectiveDescription = QtWidgets.QTextEdit(parent=objectiveDialog)
self.objectiveDescription.setObjectName("objectiveDescription")
self.gridLayout.addWidget(self.objectiveDescription, 1, 1, 1, 1)
self.buttonBox = QtWidgets.QDialogButtonBox(parent=objectiveDialog)
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok)
self.buttonBox.setObjectName("buttonBox")
self.gridLayout.addWidget(self.buttonBox, 2, 0, 1, 2)
self.retranslateUi(objectiveDialog)
self.buttonBox.accepted.connect(objectiveDialog.accept) # type: ignore
self.buttonBox.rejected.connect(objectiveDialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(objectiveDialog)
def retranslateUi(self, objectiveDialog):
_translate = QtCore.QCoreApplication.translate
objectiveDialog.setWindowTitle(_translate("objectiveDialog", "Objective"))
self.label.setText(_translate("objectiveDialog", "Name"))
self.label_2.setText(_translate("objectiveDialog", "Description"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
objectiveDialog = QtWidgets.QDialog()
ui = Ui_objectiveDialog()
ui.setupUi(objectiveDialog)
objectiveDialog.show()
sys.exit(app.exec())

View file

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>objectiveDialog</class>
<widget class="QDialog" name="objectiveDialog">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>394</width>
<height>148</height>
</rect>
</property>
<property name="windowTitle">
<string>Objective</string>
</property>
<property name="windowIcon">
<iconset>
<normaloff>../resources/warchron_logo.png</normaloff>../resources/warchron_logo.png</iconset>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="objectiveName"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Description</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QTextEdit" name="objectiveDescription"/>
</item>
<item row="2" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>objectiveDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>objectiveDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -0,0 +1,64 @@
# Form implementation generated from reading ui file '.\src\warchron\view\ui\ui_participant_dialog.ui'
#
# Created by: PyQt6 UI code generator 6.7.1
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_participantDialog(object):
def setupUi(self, participantDialog):
participantDialog.setObjectName("participantDialog")
participantDialog.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal)
participantDialog.resize(394, 148)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(".\\src\\warchron\\view\\ui\\../resources/warchron_logo.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
participantDialog.setWindowIcon(icon)
self.gridLayout = QtWidgets.QGridLayout(participantDialog)
self.gridLayout.setObjectName("gridLayout")
self.label = QtWidgets.QLabel(parent=participantDialog)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.playerComboBox = QtWidgets.QComboBox(parent=participantDialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.playerComboBox.sizePolicy().hasHeightForWidth())
self.playerComboBox.setSizePolicy(sizePolicy)
self.playerComboBox.setObjectName("playerComboBox")
self.gridLayout.addWidget(self.playerComboBox, 0, 1, 1, 1)
self.label_2 = QtWidgets.QLabel(parent=participantDialog)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
self.faction = QtWidgets.QLineEdit(parent=participantDialog)
self.faction.setObjectName("faction")
self.gridLayout.addWidget(self.faction, 1, 1, 1, 1)
self.buttonBox = QtWidgets.QDialogButtonBox(parent=participantDialog)
self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok)
self.buttonBox.setObjectName("buttonBox")
self.gridLayout.addWidget(self.buttonBox, 2, 0, 1, 2)
self.retranslateUi(participantDialog)
self.buttonBox.accepted.connect(participantDialog.accept) # type: ignore
self.buttonBox.rejected.connect(participantDialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(participantDialog)
def retranslateUi(self, participantDialog):
_translate = QtCore.QCoreApplication.translate
participantDialog.setWindowTitle(_translate("participantDialog", "Participant"))
self.label.setText(_translate("participantDialog", "Player"))
self.label_2.setText(_translate("participantDialog", "Faction"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
participantDialog = QtWidgets.QDialog()
ui = Ui_participantDialog()
ui.setupUi(participantDialog)
participantDialog.show()
sys.exit(app.exec())

View file

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>participantDialog</class>
<widget class="QDialog" name="participantDialog">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>394</width>
<height>148</height>
</rect>
</property>
<property name="windowTitle">
<string>Participant</string>
</property>
<property name="windowIcon">
<iconset>
<normaloff>../resources/warchron_logo.png</normaloff>../resources/warchron_logo.png</iconset>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Player</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="playerComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Faction</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="faction"/>
</item>
<item row="2" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>participantDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>participantDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -11,6 +11,8 @@ 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_player_dialog import Ui_playerDialog
from warchron.view.ui.ui_war_dialog import Ui_warDialog 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_campaign_dialog import Ui_campaignDialog
from warchron.view.ui.ui_objective_dialog import Ui_objectiveDialog
from warchron.view.ui.ui_participant_dialog import Ui_participantDialog
class View(QtWidgets.QMainWindow, Ui_MainWindow): class View(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None): def __init__(self, parent=None):
@ -25,6 +27,10 @@ class View(QtWidgets.QMainWindow, Ui_MainWindow):
self.show_details(None) self.show_details(None)
self.playersTable.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) self.playersTable.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.playersTable.customContextMenuRequested.connect(self._on_players_table_context_menu) self.playersTable.customContextMenuRequested.connect(self._on_players_table_context_menu)
self.warParticipantsTable.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.warParticipantsTable.customContextMenuRequested.connect(self._on_war_participants_table_context_menu)
self.objectivesTable.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.objectivesTable.customContextMenuRequested.connect(self._on_objectives_table_context_menu)
self.warsTree.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) self.warsTree.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.warsTree.customContextMenuRequested.connect(self._on_wars_tree_context_menu) self.warsTree.customContextMenuRequested.connect(self._on_wars_tree_context_menu)
self.addCampaignBtn.clicked.connect(self._on_add_campaign_clicked) self.addCampaignBtn.clicked.connect(self._on_add_campaign_clicked)
@ -41,46 +47,15 @@ class View(QtWidgets.QMainWindow, Ui_MainWindow):
"id": current.data(0, ROLE_ID), "id": current.data(0, ROLE_ID),
}) })
def _on_players_table_context_menu(self, pos): def get_current_tab(self) -> str:
item = self.playersTable.itemAt(pos) index = self.tabWidget.currentIndex()
if not item: if index == 0:
return return "players"
player_id = item.data(Qt.ItemDataRole.UserRole) elif index == 1:
menu = QMenu(self) return "wars"
edit_action = menu.addAction("Edit") return ""
delete_action = menu.addAction("Delete")
action = menu.exec(self.playersTable.viewport().mapToGlobal(pos))
if action == edit_action and self.on_edit_item:
self.on_edit_item(ItemType.PLAYER, player_id)
elif action == delete_action and self.on_delete_item:
self.on_delete_item(ItemType.PLAYER, player_id)
def _on_wars_tree_context_menu(self, pos): # General popups
item = self.warsTree.itemAt(pos)
if not item:
return
item_type = item.data(0, ROLE_TYPE)
item_id = item.data(0, ROLE_ID)
menu = QMenu(self)
edit_action = None
if item_type != ItemType.ROUND:
edit_action = menu.addAction("Edit")
delete_action = menu.addAction("Delete")
action = menu.exec(self.warsTree.viewport().mapToGlobal(pos))
if action == edit_action:
if self.on_edit_item:
self.on_edit_item(item_type, item_id)
elif action == delete_action:
if self.on_delete_item:
self.on_delete_item(item_type, item_id)
def _on_add_campaign_clicked(self):
if self.on_add_campaign:
self.on_add_campaign()
def _on_add_round_clicked(self):
if self.on_add_round:
self.on_add_round()
def closeEvent(self, event: QCloseEvent): def closeEvent(self, event: QCloseEvent):
if self.on_close_callback: if self.on_close_callback:
@ -108,6 +83,26 @@ class View(QtWidgets.QMainWindow, Ui_MainWindow):
) )
return Path(filename) if filename else None return Path(filename) if filename else None
# Players view
def _on_players_table_context_menu(self, pos):
item = self.playersTable.itemAt(pos)
if not item:
return
row = item.row()
name_item = self.playersTable.item(row, 0)
if not name_item:
return
player_id = name_item.data(Qt.ItemDataRole.UserRole)
menu = QMenu(self)
edit_action = menu.addAction("Edit")
delete_action = menu.addAction("Delete")
action = menu.exec(self.playersTable.viewport().mapToGlobal(pos))
if action == edit_action and self.on_edit_item:
self.on_edit_item(ItemType.PLAYER, player_id)
elif action == delete_action and self.on_delete_item:
self.on_delete_item(ItemType.PLAYER, player_id)
def display_players(self, players: list): def display_players(self, players: list):
table = self.playersTable table = self.playersTable
table.setRowCount(len(players)) table.setRowCount(len(players))
@ -117,8 +112,43 @@ class View(QtWidgets.QMainWindow, Ui_MainWindow):
table.setItem(row, 0, play_item) table.setItem(row, 0, play_item)
table.resizeColumnsToContents() table.resizeColumnsToContents()
# Wars view
def _on_add_campaign_clicked(self):
if self.on_add_campaign:
self.on_add_campaign()
def _on_add_round_clicked(self):
if self.on_add_round:
self.on_add_round()
def set_add_campaign_enabled(self, enabled: bool):
self.addCampaignBtn.setEnabled(enabled)
def set_add_round_enabled(self, enabled: bool):
self.addRoundBtn.setEnabled(enabled)
def _on_wars_tree_context_menu(self, pos):
item = self.warsTree.itemAt(pos)
if not item:
return
item_type = item.data(0, ROLE_TYPE)
item_id = item.data(0, ROLE_ID)
menu = QMenu(self)
edit_action = None
if item_type != ItemType.ROUND:
edit_action = menu.addAction("Edit")
delete_action = menu.addAction("Delete")
action = menu.exec(self.warsTree.viewport().mapToGlobal(pos))
if action == edit_action:
if self.on_edit_item:
self.on_edit_item(item_type, item_id)
elif action == delete_action:
if self.on_delete_item:
self.on_delete_item(item_type, item_id)
def _format_war_label(self, war) -> str: def _format_war_label(self, war) -> str:
return f"{war.name} ({war.name} ({war.year}))" return f"{war.name} ({war.year})"
def _format_campaign_label(self, camp) -> str: def _format_campaign_label(self, camp) -> str:
return f"{camp.name} ({calendar.month_name[camp.month]})" return f"{camp.name} ({calendar.month_name[camp.month]})"
@ -149,26 +179,21 @@ class View(QtWidgets.QMainWindow, Ui_MainWindow):
tree.currentItemChanged.connect(self._emit_selection_changed) tree.currentItemChanged.connect(self._emit_selection_changed)
tree.expandAll() tree.expandAll()
def show_details(self, item_type: str | None): def select_tree_item(self, *, item_type: ItemType, item_id: str):
if item_type == ItemType.WAR: def walk(item: QTreeWidgetItem):
self.selectedDetailsStack.setCurrentWidget(self.pageWar) if (
elif item_type == ItemType.CAMPAIGN: item.data(0, ROLE_TYPE) == item_type
self.selectedDetailsStack.setCurrentWidget(self.pageCampaign) and item.data(0, ROLE_ID) == item_id
elif item_type == ItemType.ROUND: ):
self.selectedDetailsStack.setCurrentWidget(self.pageRound) self.warsTree.setCurrentItem(item)
else: return True
self.selectedDetailsStack.setCurrentWidget(self.pageEmpty) for i in range(item.childCount()):
if walk(item.child(i)):
def show_war_details(self, *, name: str, year: int): return True
self.warName.setText(name) return False
self.warYear.setText(year) for i in range(self.warsTree.topLevelItemCount()):
if walk(self.warsTree.topLevelItem(i)):
def show_campaign_details(self, *, name: str, month: int): return
self.campaignName.setText(name)
self.campaignMonth.setText(calendar.month_name[month])
def show_round_details(self, *, index: int):
self.roundNb.setText(f"Round {index}")
def get_selected_tree_item(self): def get_selected_tree_item(self):
item = self.warsTree.currentItem() item = self.warsTree.currentItem()
@ -179,19 +204,93 @@ class View(QtWidgets.QMainWindow, Ui_MainWindow):
"id": item.data(0, ROLE_ID) "id": item.data(0, ROLE_ID)
} }
def set_add_campaign_enabled(self, enabled: bool): def show_details(self, item_type: str | None):
self.addCampaignBtn.setEnabled(enabled) if item_type == ItemType.WAR:
self.selectedDetailsStack.setCurrentWidget(self.pageWar)
elif item_type == ItemType.CAMPAIGN:
self.selectedDetailsStack.setCurrentWidget(self.pageCampaign)
elif item_type == ItemType.ROUND:
self.selectedDetailsStack.setCurrentWidget(self.pageRound)
else:
self.selectedDetailsStack.setCurrentWidget(self.pageEmpty)
def set_add_round_enabled(self, enabled: bool): # War page
self.addRoundBtn.setEnabled(enabled)
def _on_objectives_table_context_menu(self, pos):
item = self.objectivesTable.itemAt(pos)
if not item:
return
row = item.row()
name_item = self.objectivesTable.item(row, 0)
if not name_item:
return
objective_id = name_item.data(Qt.ItemDataRole.UserRole)
menu = QMenu(self)
edit_action = menu.addAction("Edit")
delete_action = menu.addAction("Delete")
action = menu.exec(self.objectivesTable.viewport().mapToGlobal(pos))
if action == edit_action and self.on_edit_item:
self.on_edit_item(ItemType.OBJECTIVE, objective_id)
elif action == delete_action and self.on_delete_item:
self.on_delete_item(ItemType.OBJECTIVE, objective_id)
def _on_war_participants_table_context_menu(self, pos):
item = self.warParticipantsTable.itemAt(pos)
if not item:
return
row = item.row()
name_item = self.warParticipantsTable.item(row, 0)
if not name_item:
return
participant_id = name_item.data(Qt.ItemDataRole.UserRole)
menu = QMenu(self)
edit_action = menu.addAction("Edit")
delete_action = menu.addAction("Delete")
action = menu.exec(self.warParticipantsTable.viewport().mapToGlobal(pos))
if action == edit_action and self.on_edit_item:
self.on_edit_item(ItemType.WAR_PARTICIPANT, participant_id)
elif action == delete_action and self.on_delete_item:
self.on_delete_item(ItemType.WAR_PARTICIPANT, participant_id)
def show_war_details(self, *, name: str, year: int):
self.warName.setText(name)
self.warYear.setText(str(year))
def display_war_objectives(self, objectives: list):
table = self.objectivesTable
table.clearContents()
table.setRowCount(len(objectives))
for row, obj in enumerate(objectives):
name_item = QtWidgets.QTableWidgetItem(obj.name)
desc_item = QtWidgets.QTableWidgetItem(obj.description)
name_item.setData(Qt.ItemDataRole.UserRole, obj.id)
table.setItem(row, 0, name_item)
table.setItem(row, 1, desc_item)
table.resizeColumnsToContents()
def display_war_participants(self, participants: list[tuple[str, str, str]]):
table = self.warParticipantsTable
table.clearContents()
table.setRowCount(len(participants))
for row, (name, faction, pid) in enumerate(participants):
name_item = QtWidgets.QTableWidgetItem(name)
fact_item = QtWidgets.QTableWidgetItem(faction)
name_item.setData(Qt.ItemDataRole.UserRole, pid)
table.setItem(row, 0, name_item)
table.setItem(row, 1, fact_item)
table.resizeColumnsToContents()
# Campaign page
def show_campaign_details(self, *, name: str, month: int):
self.campaignName.setText(name)
self.campaignMonth.setText(calendar.month_name[month])
# Round page
def show_round_details(self, *, index: int):
self.roundNb.setText(f"Round {index}")
def get_current_tab(self) -> str:
index = self.tabWidget.currentIndex()
if index == 0:
return "players"
elif index == 1:
return "wars"
return ""
class PlayerDialog(QDialog): class PlayerDialog(QDialog):
def __init__(self, parent=None, *, default_name: str = ""): def __init__(self, parent=None, *, default_name: str = ""):
@ -232,3 +331,37 @@ class CampaignDialog(QDialog):
def get_campaign_month(self) -> int: def get_campaign_month(self) -> int:
return int(self.ui.campaignMonth.value()) return int(self.ui.campaignMonth.value())
class ObjectiveDialog(QDialog):
def __init__(self, parent=None, *, default_name="", default_description=""):
super().__init__(parent)
self.ui = Ui_objectiveDialog()
self.ui.setupUi(self)
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 ParticipantDialog(QDialog):
def __init__(self, parent=None, *, players: list, default_player_id=None, default_faction="", editable_player=True):
super().__init__(parent)
self.ui = Ui_participantDialog()
self.ui.setupUi(self)
for player in players:
self.ui.playerComboBox.addItem(player.name, player.id)
if default_player_id:
index = self.ui.playerComboBox.findData(default_player_id)
if index != -1:
self.ui.playerComboBox.setCurrentIndex(index)
self.ui.playerComboBox.setEnabled(editable_player)
self.ui.faction.setText(default_faction)
def get_player_id(self) -> str:
return self.ui.playerComboBox.currentData()
def get_participant_faction(self) -> str:
return self.ui.faction.text().strip()