103 lines
3.9 KiB
Python
103 lines
3.9 KiB
Python
from PySide6.QtCore import Signal
|
|
from PySide6.QtWidgets import QMainWindow
|
|
|
|
from bedit.core.simulation.openmodelica import SimulationMessage, SimulationProgress
|
|
from bedit.gui.generated.ui_simulation_window import Ui_SimulationWindow
|
|
|
|
|
|
class SimulationWindow(QMainWindow):
|
|
"""Persistent, reusable view of simulation progress and results."""
|
|
|
|
progressReceived = Signal(object)
|
|
messageReceived = Signal(object)
|
|
simulationFinished = Signal(object)
|
|
simulationFailed = Signal(str)
|
|
|
|
def __init__(self, parent=None) -> None:
|
|
super().__init__(parent)
|
|
self.ui = Ui_SimulationWindow()
|
|
self.ui.setupUi(self)
|
|
self._running = False
|
|
self._run_generation = 0
|
|
self.progressReceived.connect(self._show_progress)
|
|
self.messageReceived.connect(self._show_message)
|
|
self.simulationFinished.connect(self._show_finished)
|
|
self.simulationFailed.connect(self._show_error)
|
|
|
|
def begin_run(self) -> tuple:
|
|
"""Reset the view and return callbacks bound to this particular run."""
|
|
|
|
self._run_generation += 1
|
|
generation = self._run_generation
|
|
self._running = True
|
|
self.ui.statusLabel.setText("Preparing simulation…")
|
|
self.ui.progressBar.setValue(0)
|
|
self.ui.timeLabel.setText("Time: 0 s")
|
|
self.ui.messageList.clear()
|
|
self.clear_results()
|
|
return (
|
|
lambda progress: self._report_progress(generation, progress),
|
|
lambda message: self._report_message(generation, message),
|
|
lambda result: self._report_finished(generation, result),
|
|
lambda error: self._report_error(generation, error),
|
|
)
|
|
|
|
def clear_results(self) -> None:
|
|
"""Clear future plots and result models before a new run.
|
|
|
|
Add graph widgets and their clearing logic here when simulation result
|
|
loading and plotting are implemented. The Designer-owned `resultsLayout`
|
|
is the intended container for those widgets.
|
|
"""
|
|
|
|
def _report_progress(
|
|
self, generation: int, progress: SimulationProgress
|
|
) -> None:
|
|
if generation == self._run_generation:
|
|
self.progressReceived.emit(progress)
|
|
|
|
def _report_message(self, generation: int, message: SimulationMessage) -> None:
|
|
if generation == self._run_generation:
|
|
self.messageReceived.emit(message)
|
|
|
|
def _report_finished(self, generation: int, result) -> None:
|
|
if generation == self._run_generation:
|
|
self.simulationFinished.emit(result)
|
|
|
|
def _report_error(self, generation: int, error: Exception) -> None:
|
|
if generation == self._run_generation:
|
|
self.simulationFailed.emit(str(error))
|
|
|
|
def report_start_error(self, error: Exception) -> None:
|
|
"""Report an error raised before asynchronous callbacks were installed."""
|
|
|
|
self.simulationFailed.emit(str(error))
|
|
|
|
def _show_progress(self, progress: SimulationProgress) -> None:
|
|
self.ui.statusLabel.setText(progress.phase or "Running")
|
|
self.ui.timeLabel.setText(f"Time: {progress.time:g} s")
|
|
self.ui.progressBar.setValue(max(0, min(10000, progress.progress)))
|
|
|
|
def _show_message(self, message: SimulationMessage) -> None:
|
|
prefix = message.stream or message.type or "OpenModelica"
|
|
self.ui.messageList.addItem(f"{prefix}: {message.text}")
|
|
self.ui.messageList.scrollToBottom()
|
|
|
|
def _show_finished(self, _result) -> None:
|
|
self._running = False
|
|
self.ui.progressBar.setValue(10000)
|
|
self.ui.statusLabel.setText("Simulation finished")
|
|
self.load_results()
|
|
|
|
def _show_error(self, message: str) -> None:
|
|
self._running = False
|
|
self.ui.statusLabel.setText("Simulation failed")
|
|
self.ui.messageList.addItem(f"Error: {message}")
|
|
|
|
def load_results(self) -> None:
|
|
"""Populate future plots and result controls after a successful run."""
|
|
|
|
@property
|
|
def is_running(self) -> bool:
|
|
return self._running
|