class QPackageDialog(QDialog): """Base package management dialog. The dialogs for creating a new package and editing an existing dialog are very similar, and this implements the shared behavior. """ #: Emitted when a change is made to the package. package_changed = Signal() def __init__(self, game_model: GameModel, model: PackageModel, parent=None) -> None: super().__init__(parent) self.game_model = game_model self.package_model = model self.add_flight_dialog: Optional[QFlightCreator] = None self.setMinimumSize(1000, 440) self.setWindowTitle( f"Mission Package: {self.package_model.mission_target.name}") self.setWindowIcon(EVENT_ICONS["strike"]) self.layout = QVBoxLayout() self.summary_row = QHBoxLayout() self.layout.addLayout(self.summary_row) self.package_type_column = QHBoxLayout() self.summary_row.addLayout(self.package_type_column) self.package_type_label = QLabel("Package Type:") self.package_type_text = QLabel(self.package_model.description) # noinspection PyUnresolvedReferences self.package_changed.connect(lambda: self.package_type_text.setText( self.package_model.description)) self.package_type_column.addWidget(self.package_type_label) self.package_type_column.addWidget(self.package_type_text) self.summary_row.addStretch(1) self.tot_column = QHBoxLayout() self.summary_row.addLayout(self.tot_column) self.tot_label = QLabel("Time Over Target:") self.tot_column.addWidget(self.tot_label) self.tot_spinner = QTimeEdit(self.tot_qtime()) self.tot_spinner.setMinimumTime(QTime(0, 0)) self.tot_spinner.setDisplayFormat("T+hh:mm:ss") self.tot_spinner.timeChanged.connect(self.save_tot) self.tot_spinner.setToolTip("Package TOT relative to mission TOT") self.tot_spinner.setEnabled(not self.package_model.package.auto_asap) self.tot_column.addWidget(self.tot_spinner) self.auto_asap = QCheckBox("ASAP") self.auto_asap.setToolTip( "Sets the package TOT to the earliest time that all flights can " "arrive at the target.") self.auto_asap.setChecked(self.package_model.package.auto_asap) self.auto_asap.toggled.connect(self.set_asap) self.tot_column.addWidget(self.auto_asap) self.tot_help_label = QLabel( "<a href=\"https://github.com/Khopa/dcs_liberation/wiki/Mission-planning\"><span style=\"color:#FFFFFF;\">Help</span></a>" ) self.tot_help_label.setAlignment(Qt.AlignCenter) self.tot_help_label.setOpenExternalLinks(True) self.tot_column.addWidget(self.tot_help_label) self.package_view = QFlightList(self.game_model, self.package_model) self.package_view.selectionModel().selectionChanged.connect( self.on_selection_changed) self.layout.addWidget(self.package_view) self.button_layout = QHBoxLayout() self.layout.addLayout(self.button_layout) self.add_flight_button = QPushButton("Add Flight") self.add_flight_button.clicked.connect(self.on_add_flight) self.button_layout.addWidget(self.add_flight_button) self.delete_flight_button = QPushButton("Delete Selected") self.delete_flight_button.setProperty("style", "btn-danger") self.delete_flight_button.clicked.connect(self.on_delete_flight) self.delete_flight_button.setEnabled(model.rowCount() > 0) self.button_layout.addWidget(self.delete_flight_button) self.package_model.tot_changed.connect(self.update_tot) self.button_layout.addStretch() self.setLayout(self.layout) self.accepted.connect(self.on_save) self.finished.connect(self.on_close) self.rejected.connect(self.on_cancel) @property def game(self) -> Game: return self.game_model.game def tot_qtime(self) -> QTime: delay = int( self.package_model.package.time_over_target.total_seconds()) hours = delay // 3600 minutes = delay // 60 % 60 seconds = delay % 60 return QTime(hours, minutes, seconds) def on_cancel(self) -> None: pass @staticmethod def on_close(_result) -> None: GameUpdateSignal.get_instance().redraw_flight_paths() def on_save(self) -> None: self.save_tot() def save_tot(self) -> None: time = self.tot_spinner.time() seconds = time.hour() * 3600 + time.minute() * 60 + time.second() self.package_model.set_tot(timedelta(seconds=seconds)) def set_asap(self, checked: bool) -> None: self.package_model.set_asap(checked) self.tot_spinner.setEnabled(not self.package_model.package.auto_asap) self.update_tot() def update_tot(self) -> None: self.tot_spinner.setTime(self.tot_qtime()) def on_selection_changed(self, selected: QItemSelection, _deselected: QItemSelection) -> None: """Updates the state of the delete button.""" self.delete_flight_button.setEnabled(not selected.empty()) def on_add_flight(self) -> None: """Opens the new flight dialog.""" self.add_flight_dialog = QFlightCreator(self.game, self.package_model.package, parent=self.window()) self.add_flight_dialog.created.connect(self.add_flight) self.add_flight_dialog.show() def add_flight(self, flight: Flight) -> None: """Adds the new flight to the package.""" self.game.aircraft_inventory.claim_for_flight(flight) self.package_model.add_flight(flight) planner = FlightPlanBuilder(self.game, self.package_model.package, is_player=True) try: planner.populate_flight_plan(flight) except PlanningError as ex: self.game.aircraft_inventory.return_from_flight(flight) self.package_model.delete_flight(flight) logging.exception("Could not create flight") QMessageBox.critical(self, "Could not create flight", str(ex), QMessageBox.Ok) self.package_model.update_tot() # noinspection PyUnresolvedReferences self.package_changed.emit() def on_delete_flight(self) -> None: """Removes the selected flight from the package.""" flight = self.package_view.selected_item if flight is None: logging.error(f"Cannot delete flight when no flight is selected.") return self.game.aircraft_inventory.return_from_flight(flight) self.package_model.delete_flight(flight) # noinspection PyUnresolvedReferences self.package_changed.emit()
class StartHandicapDialog(QDialog): def __init__(self): super().__init__(GlobalAccess().get_main_window()) self.time_format = 'hh:mm:ss' self.setWindowTitle(_('Handicap start time')) self.setWindowIcon(QIcon(config.ICON)) self.setSizeGripEnabled(False) self.setModal(True) self.layout = QFormLayout(self) self.handicap_mode = QRadioButton(_('Handicap mode')) self.reverse_mode = QRadioButton(_('Reverse mode')) self.layout.addRow(self.handicap_mode) self.layout.addRow(self.reverse_mode) self.zero_time_label = QLabel(_('Start time')) self.zero_time = QTimeEdit() self.zero_time.setDisplayFormat(self.time_format) self.layout.addRow(self.zero_time_label, self.zero_time) self.max_gap_label = QLabel(_('Max gap from leader')) self.max_gap = QTimeEdit() self.max_gap.setDisplayFormat(self.time_format) self.layout.addRow(self.max_gap_label, self.max_gap) self.second_start_time_label = QLabel(_('Start time for 2 group')) self.second_time = QTimeEdit() self.second_time.setDisplayFormat(self.time_format) self.layout.addRow(self.second_start_time_label, self.second_time) self.interval_time_label = QLabel(_('Start interval')) self.interval_time = QTimeEdit() self.interval_time.setDisplayFormat(self.time_format) self.layout.addRow(self.interval_time_label, self.interval_time) self.dsq_offset_label = QLabel(_('Offset after DSQ')) self.dsq_offset = QTimeEdit() self.dsq_offset.setDisplayFormat(self.time_format) self.layout.addRow(self.dsq_offset_label, self.dsq_offset) def mode_changed(): status = self.handicap_mode.isChecked() self.max_gap.setEnabled(status) self.second_time.setEnabled(status) self.dsq_offset.setDisabled(status) self.handicap_mode.toggled.connect(mode_changed) self.reverse_mode.toggled.connect(mode_changed) def cancel_changes(): self.close() def apply_changes(): try: self.apply_changes_impl() except Exception as e: logging.error(str(e)) logging.exception(e) self.close() button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = button_box.button(QDialogButtonBox.Ok) self.button_ok.setText(_('OK')) self.button_ok.clicked.connect(apply_changes) self.button_cancel = button_box.button(QDialogButtonBox.Cancel) self.button_cancel.setText(_('Cancel')) self.button_cancel.clicked.connect(cancel_changes) self.layout.addRow(button_box) self.set_values() self.show() def set_values(self): obj = race() if obj.get_setting('handicap_mode', True): self.handicap_mode.toggle() else: self.reverse_mode.toggle() self.zero_time.setTime(OTime(msec=obj.get_setting('handicap_start', OTime(0, 11).to_msec())).to_time()) self.max_gap.setTime(OTime(msec=obj.get_setting('handicap_max_gap', OTime(0, 0, 30).to_msec())).to_time()) self.second_time.setTime( OTime(msec=obj.get_setting('handicap_second_start', OTime(0, 11, 30).to_msec())).to_time()) self.interval_time.setTime(OTime(msec=obj.get_setting('handicap_interval', OTime(0, 0, 1).to_msec())).to_time()) self.dsq_offset.setTime(OTime(msec=obj.get_setting('handicap_dsq_offset', OTime(0, 0, 10).to_msec())).to_time()) def apply_changes_impl(self): obj = race() obj.set_setting('handicap_mode', self.handicap_mode.isChecked()) obj.set_setting('handicap_start', time_to_otime(self.zero_time.time()).to_msec()) obj.set_setting('handicap_max_gap', time_to_otime(self.max_gap.time()).to_msec()) obj.set_setting('handicap_second_start', time_to_otime(self.second_time.time()).to_msec()) obj.set_setting('handicap_interval', time_to_otime(self.interval_time.time()).to_msec()) obj.set_setting('handicap_dsq_offset', time_to_otime(self.dsq_offset.time()).to_msec()) if obj.get_setting('handicap_mode', True): handicap_start_time() else: reverse_start_time()