"""QWizard contenedor + builder de Project a partir del estado del wizard. Sprint 1: pasos 1-4 funcionales, 5-7 placeholders, 8 confirm. Sprint 2: pasos 5-7 funcionales con rule engine + auto-assigner. """ from __future__ import annotations import logging from PySide6.QtWidgets import QWidget, QWizard from vmssailor.core import ( Equipment, Project, SystemId, Vessel, VesselSubtype, VesselType, ) from vmssailor.core.vessel import Bulkhead, Deck from vmssailor.shared.ids import make_project_id from vmssailor.studio.theme import C_ABYSS, C_SAND from vmssailor.studio.wizard.step_01_vessel_type import Step01VesselType from vmssailor.studio.wizard.step_02_template import Step02Template from vmssailor.studio.wizard.step_03_dimensions import Step03Dimensions from vmssailor.studio.wizard.step_04_systems import Step04Systems from vmssailor.studio.wizard.step_05_equipment import Step05Equipment from vmssailor.studio.wizard.step_06_refinement import Step06Refinement from vmssailor.studio.wizard.step_07_topology import Step07Topology from vmssailor.studio.wizard.step_08_confirm import Step08Confirm logger = logging.getLogger(__name__) # Wizard field keys used across steps F_PROJECT_NAME = "project.name" F_CUSTOMER = "project.customer" F_VESSEL_TYPE = "vessel.type" F_VESSEL_SUBTYPE = "vessel.subtype" F_TEMPLATE_ID = "vessel.template_id" F_VESSEL_NAME = "vessel.name" F_LOA = "vessel.length_overall_m" F_BEAM = "vessel.beam_max_m" F_DRAFT = "vessel.draft_m" F_BULKHEAD_FWD = "vessel.bulkhead_fwd_m" F_BULKHEAD_AFT = "vessel.bulkhead_aft_m" F_SYSTEMS = "systems.enabled" F_PROPOSALS = "equipment.proposals" F_ASSIGNMENT = "topology.assignment" class VesselWizard(QWizard): """Wizard 8 pasos para crear un nuevo Project desde cero.""" def __init__(self, parent: QWidget | None = None) -> None: super().__init__(parent) self.setWindowTitle("VMS-Sailor · Nuevo proyecto") self.setMinimumSize(900, 640) self.setWizardStyle(QWizard.ModernStyle) self.setOption(QWizard.NoBackButtonOnStartPage, True) self.setOption(QWizard.HaveHelpButton, False) self.setOption(QWizard.IndependentPages, False) # Add pages self.addPage(Step01VesselType()) self.addPage(Step02Template()) self.addPage(Step03Dimensions()) self.addPage(Step04Systems()) self.addPage(Step05Equipment()) self.addPage(Step06Refinement()) self.addPage(Step07Topology()) self.addPage(Step08Confirm()) # Style self.setStyleSheet( f""" QWizard {{ background: {C_ABYSS}; }} QWidget {{ background: {C_ABYSS}; color: {C_SAND}; }} QWizard QPushButton {{ min-width: 100px; }} """ ) self.setButtonText(QWizard.NextButton, "Siguiente >") self.setButtonText(QWizard.BackButton, "< Atrás") self.setButtonText(QWizard.FinishButton, "Crear proyecto") self.setButtonText(QWizard.CancelButton, "Cancelar") # ----- Project construction ----------------------------------------- def build_project(self) -> Project: """Construye un `Project` a partir de los datos capturados por el wizard.""" project_name = self.field(F_PROJECT_NAME) or "Proyecto sin nombre" customer = self.field(F_CUSTOMER) or "" vessel_name = self.field(F_VESSEL_NAME) or project_name v_type = self.field(F_VESSEL_TYPE) or VesselType.YACHT_MOTOR.value v_sub = self.field(F_VESSEL_SUBTYPE) or VesselSubtype.PLANING.value loa = float(self.field(F_LOA) or 24.0) beam = float(self.field(F_BEAM) or 5.5) draft = float(self.field(F_DRAFT) or 1.8) bh_fwd = float(self.field(F_BULKHEAD_FWD) or (loa * 0.30)) bh_aft = float(self.field(F_BULKHEAD_AFT) or (loa * 0.15)) systems_raw = self.field(F_SYSTEMS) or [SystemId.MAIN_ENGINE.value] decks = [ Deck(id="lower", name="Cubierta inferior", z_bl_bottom=0.4, z_bl_top=draft + 1.0), Deck( id="main", name="Cubierta principal", z_bl_bottom=draft + 1.0, z_bl_top=draft + 3.0, ), ] bulkheads = [ Bulkhead(id="er_aft", name="Mamparo popa SM", x_pp=bh_aft), Bulkhead(id="er_fwd", name="Mamparo proa SM", x_pp=bh_fwd), ] vessel = Vessel( id=f"wizard_{int(loa * 10)}m", name=vessel_name, type=VesselType(v_type), subtype=VesselSubtype(v_sub), length_overall_m=loa, beam_max_m=beam, draft_m=draft, decks=decks, bulkheads=bulkheads, data_source="user_input", ) try: systems_enabled = [SystemId(s) for s in systems_raw] except ValueError: systems_enabled = [SystemId.MAIN_ENGINE] # Sprint 2: materializar Equipment desde las propuestas aceptadas proposals = self.field(F_PROPOSALS) or [] equipment_list: list[Equipment] = [] for idx, p in enumerate(proposals): equipment_list.append( Equipment( id=f"eq_{idx:03d}_{p.tag_prefix.lower()}", model_ref=p.model_ref, tag_prefix=p.tag_prefix, display_name=p.display_name, location=p.to_ship_coord(), system_id=p.system_id, ) ) # Topología + tags del auto-assigner assignment = self.field(F_ASSIGNMENT) topology = assignment.topology() if assignment is not None else None tags = list(assignment.tags) if assignment is not None else [] project_id = make_project_id(customer or "cliente", vessel.id) if topology is not None: return Project( id=project_id, name=project_name, customer=customer, vessel=vessel, systems_enabled=systems_enabled, equipment=equipment_list, tags=tags, topology=topology, notes="Creado desde wizard (Sprint 2 — rule engine + auto-assigner).", ) return Project( id=project_id, name=project_name, customer=customer, vessel=vessel, systems_enabled=systems_enabled, equipment=equipment_list, tags=tags, notes="Creado desde wizard (Sprint 2 — rule engine + auto-assigner).", )