mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Move FlightJs out of MapModel.
This commit is contained in:
@@ -169,9 +169,6 @@ class PackageModel(QAbstractListModel):
|
||||
"""Removes the given flight from the package."""
|
||||
index = self.package.flights.index(flight)
|
||||
self.beginRemoveRows(QModelIndex(), index, index)
|
||||
if flight.cargo is not None:
|
||||
flight.cargo.transport = None
|
||||
flight.return_pilots_and_aircraft()
|
||||
self.package.remove_flight(flight)
|
||||
self.endRemoveRows()
|
||||
self.update_tot()
|
||||
@@ -253,6 +250,8 @@ class AtoModel(QAbstractListModel):
|
||||
"""Adds a package to the ATO."""
|
||||
self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
|
||||
self.ato.add_package(package)
|
||||
# We do not need to send events for new flights in the package here. Events were
|
||||
# already sent when the flights were added to the in-progress package.
|
||||
self.endInsertRows()
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.client_slots_changed.emit()
|
||||
@@ -264,14 +263,11 @@ class AtoModel(QAbstractListModel):
|
||||
|
||||
def delete_package(self, package: Package) -> None:
|
||||
"""Removes the given package from the ATO."""
|
||||
EventStream.put_nowait(GameUpdateEvents().delete_flights_in_package(package))
|
||||
self.package_models.release(package)
|
||||
index = self.ato.packages.index(package)
|
||||
self.beginRemoveRows(QModelIndex(), index, index)
|
||||
self.ato.remove_package(package)
|
||||
for flight in package.flights:
|
||||
flight.return_pilots_and_aircraft()
|
||||
if flight.cargo is not None:
|
||||
flight.cargo.transport = None
|
||||
self.endRemoveRows()
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.client_slots_changed.emit()
|
||||
@@ -280,9 +276,7 @@ class AtoModel(QAbstractListModel):
|
||||
def on_packages_changed(self) -> None:
|
||||
if self.game is not None:
|
||||
self.game.compute_unculled_zones()
|
||||
events = GameUpdateEvents()
|
||||
events.update_unculled_zones()
|
||||
EventStream.put_nowait(events)
|
||||
EventStream.put_nowait(GameUpdateEvents().update_unculled_zones())
|
||||
|
||||
def package_at_index(self, index: QModelIndex) -> Package:
|
||||
"""Returns the package at the given index."""
|
||||
|
||||
@@ -27,7 +27,8 @@ from PySide2.QtWidgets import (
|
||||
|
||||
from game.ato.flight import Flight
|
||||
from game.ato.package import Package
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
from game.server import EventStream
|
||||
from game.sim import GameUpdateEvents
|
||||
from ..delegates import TwoColumnRowDelegate
|
||||
from ..models import AtoModel, GameModel, NullListModel, PackageModel
|
||||
|
||||
@@ -128,8 +129,10 @@ class QFlightList(QListView):
|
||||
)
|
||||
|
||||
def delete_flight(self, index: QModelIndex) -> None:
|
||||
EventStream.put_nowait(
|
||||
GameUpdateEvents().delete_flight(self.package_model.flight_at_index(index))
|
||||
)
|
||||
self.package_model.delete_flight_at_index(index)
|
||||
GameUpdateSignal.get_instance().redraw_flight_paths()
|
||||
|
||||
def contextMenuEvent(self, event: QContextMenuEvent) -> None:
|
||||
index = self.indexAt(event.pos())
|
||||
@@ -209,13 +212,13 @@ class QFlightPanel(QGroupBox):
|
||||
self.delete_button.setEnabled(enabled)
|
||||
self.change_map_flight_selection(index)
|
||||
|
||||
@staticmethod
|
||||
def change_map_flight_selection(index: QModelIndex) -> None:
|
||||
def change_map_flight_selection(self, index: QModelIndex) -> None:
|
||||
events = GameUpdateEvents()
|
||||
if not index.isValid():
|
||||
GameUpdateSignal.get_instance().select_flight(None)
|
||||
return
|
||||
|
||||
GameUpdateSignal.get_instance().select_flight(index.row())
|
||||
events.deselect_flight()
|
||||
else:
|
||||
events.select_flight(self.package_model.flight_at_index(index))
|
||||
EventStream.put_nowait(events)
|
||||
|
||||
def on_edit(self) -> None:
|
||||
"""Opens the flight edit dialog."""
|
||||
@@ -303,7 +306,6 @@ class QPackageList(QListView):
|
||||
|
||||
def delete_package(self, index: QModelIndex) -> None:
|
||||
self.ato_model.delete_package_at_index(index)
|
||||
GameUpdateSignal.get_instance().redraw_flight_paths()
|
||||
|
||||
def on_new_packages(self, _parent: QModelIndex, first: int, _last: int) -> None:
|
||||
# Select the newly created pacakges. This should only ever happen due to
|
||||
@@ -390,14 +392,18 @@ class QPackagePanel(QGroupBox):
|
||||
|
||||
def change_map_package_selection(self, index: QModelIndex) -> None:
|
||||
if not index.isValid():
|
||||
GameUpdateSignal.get_instance().select_package(None)
|
||||
EventStream.put_nowait(GameUpdateEvents().deselect_flight())
|
||||
return
|
||||
|
||||
package = self.ato_model.get_package_model(index)
|
||||
if package.rowCount() == 0:
|
||||
GameUpdateSignal.get_instance().select_package(None)
|
||||
EventStream.put_nowait(GameUpdateEvents().deselect_flight())
|
||||
else:
|
||||
GameUpdateSignal.get_instance().select_package(index.row())
|
||||
EventStream.put_nowait(
|
||||
GameUpdateEvents().select_flight(
|
||||
package.flight_at_index(package.index(0))
|
||||
)
|
||||
)
|
||||
|
||||
def on_edit(self) -> None:
|
||||
"""Opens the package edit dialog."""
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from PySide2.QtCore import Property, QObject, Signal, Slot
|
||||
|
||||
from game.ato import Flight
|
||||
from game.ato.flightstate import InFlight
|
||||
from game.server.leaflet import LeafletLatLon
|
||||
from qt_ui.models import AtoModel
|
||||
|
||||
|
||||
class FlightJs(QObject):
|
||||
idChanged = Signal()
|
||||
positionChanged = Signal()
|
||||
blueChanged = Signal()
|
||||
selectedChanged = Signal()
|
||||
|
||||
def __init__(self, flight: Flight, selected: bool, ato_model: AtoModel) -> None:
|
||||
super().__init__()
|
||||
self.flight = flight
|
||||
self._selected = selected
|
||||
self.ato_model = ato_model
|
||||
|
||||
@Property(str, notify=idChanged)
|
||||
def id(self) -> str:
|
||||
return str(self.flight.id)
|
||||
|
||||
@Property(list, notify=positionChanged)
|
||||
def position(self) -> LeafletLatLon:
|
||||
if isinstance(self.flight.state, InFlight):
|
||||
return self.flight.state.estimate_position().latlng().as_list()
|
||||
return []
|
||||
|
||||
@Property(bool, notify=blueChanged)
|
||||
def blue(self) -> bool:
|
||||
return self.flight.departure.captured
|
||||
|
||||
@Property(bool, notify=selectedChanged)
|
||||
def selected(self) -> bool:
|
||||
return self._selected
|
||||
|
||||
@Slot(result=bool)
|
||||
def flightIsInAto(self) -> bool:
|
||||
if self.flight.package not in self.flight.squadron.coalition.ato.packages:
|
||||
return False
|
||||
if self.flight not in self.flight.package.flights:
|
||||
return False
|
||||
return True
|
||||
|
||||
def set_selected(self, value: bool) -> None:
|
||||
self._selected = value
|
||||
self.selectedChanged.emit()
|
||||
@@ -1,13 +1,11 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import List, Optional, Tuple
|
||||
from typing import List, Optional
|
||||
|
||||
from PySide2.QtCore import Property, QObject, Signal
|
||||
from dcs.mapping import LatLng
|
||||
|
||||
from game import Game
|
||||
from game.ato.airtaaskingorder import AirTaskingOrder
|
||||
from game.profiling import logged_duration
|
||||
from game.server.leaflet import LeafletLatLon
|
||||
from game.server.security import ApiKeyManager
|
||||
@@ -17,7 +15,6 @@ from game.theater import (
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
from .controlpointjs import ControlPointJs
|
||||
from .flightjs import FlightJs
|
||||
from .frontlinejs import FrontLineJs
|
||||
from .groundobjectjs import GroundObjectJs
|
||||
from .supplyroutejs import SupplyRouteJs
|
||||
@@ -47,9 +44,8 @@ class MapModel(QObject):
|
||||
controlPointsChanged = Signal()
|
||||
groundObjectsChanged = Signal()
|
||||
supplyRoutesChanged = Signal()
|
||||
flightsChanged = Signal()
|
||||
frontLinesChanged = Signal()
|
||||
selectedFlightChanged = Signal(str)
|
||||
mapReset = Signal()
|
||||
|
||||
def __init__(self, game_model: GameModel) -> None:
|
||||
super().__init__()
|
||||
@@ -58,79 +54,18 @@ class MapModel(QObject):
|
||||
self._control_points = []
|
||||
self._ground_objects = []
|
||||
self._supply_routes = []
|
||||
self._flights: dict[tuple[bool, int, int], FlightJs] = {}
|
||||
self._front_lines = []
|
||||
|
||||
self._selected_flight_index: Optional[Tuple[int, int]] = None
|
||||
|
||||
GameUpdateSignal.get_instance().game_loaded.connect(self.on_game_load)
|
||||
GameUpdateSignal.get_instance().flight_paths_changed.connect(self.reset_atos)
|
||||
GameUpdateSignal.get_instance().package_selection_changed.connect(
|
||||
self.set_package_selection
|
||||
)
|
||||
GameUpdateSignal.get_instance().flight_selection_changed.connect(
|
||||
self.set_flight_selection
|
||||
)
|
||||
self.reset()
|
||||
|
||||
def clear(self) -> None:
|
||||
self._control_points = []
|
||||
self._supply_routes = []
|
||||
self._ground_objects = []
|
||||
self._flights = {}
|
||||
self._front_lines = []
|
||||
self.cleared.emit()
|
||||
|
||||
def set_package_selection(self, index: int) -> None:
|
||||
self.deselect_current_flight()
|
||||
# Optional[int] isn't a valid type for a Qt signal. None will be converted to
|
||||
# zero automatically. We use -1 to indicate no selection.
|
||||
if index == -1:
|
||||
self._selected_flight_index = None
|
||||
else:
|
||||
self._selected_flight_index = index, 0
|
||||
self.select_current_flight()
|
||||
|
||||
def set_flight_selection(self, index: int) -> None:
|
||||
self.deselect_current_flight()
|
||||
if self._selected_flight_index is None:
|
||||
if index != -1:
|
||||
# We don't know what order update_package_selection and
|
||||
# update_flight_selection will be called in when the last
|
||||
# package is removed. If no flight is selected, it's not a
|
||||
# problem to also have no package selected.
|
||||
logging.error("Flight was selected with no package selected")
|
||||
return
|
||||
|
||||
# Optional[int] isn't a valid type for a Qt signal. None will be converted to
|
||||
# zero automatically. We use -1 to indicate no selection.
|
||||
if index == -1:
|
||||
self._selected_flight_index = self._selected_flight_index[0], None
|
||||
self._selected_flight_index = self._selected_flight_index[0], index
|
||||
self.select_current_flight()
|
||||
|
||||
@property
|
||||
def _selected_flight(self) -> Optional[FlightJs]:
|
||||
if self._selected_flight_index is None:
|
||||
return None
|
||||
package_index, flight_index = self._selected_flight_index
|
||||
blue = True
|
||||
return self._flights.get((blue, package_index, flight_index))
|
||||
|
||||
def deselect_current_flight(self) -> None:
|
||||
flight = self._selected_flight
|
||||
if flight is None:
|
||||
return None
|
||||
flight.set_selected(False)
|
||||
|
||||
def select_current_flight(self):
|
||||
flight = self._selected_flight
|
||||
if flight is None:
|
||||
self.selectedFlightChanged.emit(None)
|
||||
return None
|
||||
flight.set_selected(True)
|
||||
self.selectedFlightChanged.emit(str(flight.flight.id))
|
||||
|
||||
def reset(self) -> None:
|
||||
if self.game_model.game is None:
|
||||
self.clear()
|
||||
@@ -139,8 +74,8 @@ class MapModel(QObject):
|
||||
self.reset_control_points()
|
||||
self.reset_ground_objects()
|
||||
self.reset_routes()
|
||||
self.reset_atos()
|
||||
self.reset_front_lines()
|
||||
self.mapReset.emit()
|
||||
|
||||
def on_game_load(self, game: Optional[Game]) -> None:
|
||||
if game is not None:
|
||||
@@ -158,29 +93,6 @@ class MapModel(QObject):
|
||||
def mapCenter(self) -> LeafletLatLon:
|
||||
return self._map_center.as_list()
|
||||
|
||||
def _flights_in_ato(
|
||||
self, ato: AirTaskingOrder, blue: bool
|
||||
) -> dict[tuple[bool, int, int], FlightJs]:
|
||||
flights = {}
|
||||
for p_idx, package in enumerate(ato.packages):
|
||||
for f_idx, flight in enumerate(package.flights):
|
||||
flights[blue, p_idx, f_idx] = FlightJs(
|
||||
flight,
|
||||
selected=blue and (p_idx, f_idx) == self._selected_flight_index,
|
||||
ato_model=self.game_model.ato_model_for(blue),
|
||||
)
|
||||
return flights
|
||||
|
||||
def reset_atos(self) -> None:
|
||||
self._flights = self._flights_in_ato(
|
||||
self.game.blue.ato, blue=True
|
||||
) | self._flights_in_ato(self.game.red.ato, blue=False)
|
||||
self.flightsChanged.emit()
|
||||
|
||||
@Property(list, notify=flightsChanged)
|
||||
def flights(self) -> list[FlightJs]:
|
||||
return list(self._flights.values())
|
||||
|
||||
def reset_control_points(self) -> None:
|
||||
self._control_points = [
|
||||
ControlPointJs(c, self.game_model, self.game.theater)
|
||||
|
||||
@@ -17,28 +17,12 @@ class GameUpdateSignal(QObject):
|
||||
|
||||
game_loaded = Signal(Game)
|
||||
|
||||
flight_paths_changed = Signal()
|
||||
package_selection_changed = Signal(int) # -1 indicates no selection.
|
||||
flight_selection_changed = Signal(int) # -1 indicates no selection.
|
||||
|
||||
def __init__(self):
|
||||
super(GameUpdateSignal, self).__init__()
|
||||
GameUpdateSignal.instance = self
|
||||
|
||||
self.game_loaded.connect(self.updateGame)
|
||||
|
||||
def select_package(self, index: Optional[int]) -> None:
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.package_selection_changed.emit(-1 if index is None else index)
|
||||
|
||||
def select_flight(self, index: Optional[int]) -> None:
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.flight_selection_changed.emit(-1 if index is None else index)
|
||||
|
||||
def redraw_flight_paths(self) -> None:
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.flight_paths_changed.emit()
|
||||
|
||||
def updateGame(self, game: Optional[Game]):
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.gameupdated.emit(game)
|
||||
|
||||
@@ -5,9 +5,10 @@ from PySide2.QtWidgets import (
|
||||
)
|
||||
|
||||
from game.ato.flight import Flight
|
||||
from game.server import EventStream
|
||||
from game.sim import GameUpdateEvents
|
||||
from qt_ui.models import GameModel, PackageModel
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
from qt_ui.windows.mission.flight.QFlightPlanner import QFlightPlanner
|
||||
|
||||
|
||||
@@ -24,6 +25,7 @@ class QEditFlightDialog(QDialog):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.game_model = game_model
|
||||
self.flight = flight
|
||||
|
||||
self.setWindowTitle("Edit flight")
|
||||
self.setWindowIcon(EVENT_ICONS["strike"])
|
||||
@@ -37,5 +39,5 @@ class QEditFlightDialog(QDialog):
|
||||
self.finished.connect(self.on_close)
|
||||
|
||||
def on_close(self, _result) -> None:
|
||||
GameUpdateSignal.get_instance().redraw_flight_paths()
|
||||
EventStream.put_nowait(GameUpdateEvents().update_flight(self.flight))
|
||||
self.game_model.ato_model.client_slots_changed.emit()
|
||||
|
||||
@@ -16,14 +16,15 @@ from PySide2.QtWidgets import (
|
||||
)
|
||||
|
||||
from game.ato.flight import Flight
|
||||
from game.ato.flightplan import FlightPlanBuilder, PlanningError
|
||||
from game.ato.package import Package
|
||||
from game.game import Game
|
||||
from game.server import EventStream
|
||||
from game.sim import GameUpdateEvents
|
||||
from game.theater.missiontarget import MissionTarget
|
||||
from game.ato.flightplan import FlightPlanBuilder, PlanningError
|
||||
from qt_ui.models import AtoModel, GameModel, PackageModel
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
from qt_ui.widgets.ato import QFlightList
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
from qt_ui.windows.mission.flight.QFlightCreator import QFlightCreator
|
||||
|
||||
|
||||
@@ -141,9 +142,10 @@ class QPackageDialog(QDialog):
|
||||
def on_cancel(self) -> None:
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def on_close(_result) -> None:
|
||||
GameUpdateSignal.get_instance().redraw_flight_paths()
|
||||
def on_close(self, _result) -> None:
|
||||
EventStream.put_nowait(
|
||||
GameUpdateEvents().update_flights_in_package(self.package_model.package)
|
||||
)
|
||||
|
||||
def on_save(self) -> None:
|
||||
self.save_tot()
|
||||
@@ -183,13 +185,14 @@ class QPackageDialog(QDialog):
|
||||
)
|
||||
try:
|
||||
planner.populate_flight_plan(flight)
|
||||
self.package_model.update_tot()
|
||||
EventStream.put_nowait(GameUpdateEvents().new_flight(flight))
|
||||
except PlanningError as ex:
|
||||
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()
|
||||
|
||||
@@ -252,7 +255,7 @@ class QNewPackageDialog(QPackageDialog):
|
||||
def on_cancel(self) -> None:
|
||||
super().on_cancel()
|
||||
for flight in self.package_model.package.flights:
|
||||
flight.return_pilots_and_aircraft()
|
||||
self.package_model.delete_flight(flight)
|
||||
|
||||
|
||||
class QEditPackageDialog(QPackageDialog):
|
||||
|
||||
Reference in New Issue
Block a user