Files
BondGraph/BEdit/src/bedit/gui/simulation_window.py
2026-07-21 13:54:57 +02:00

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