diff --git a/changelog.d/791-sheet-built-twice.fixed.md b/changelog.d/791-sheet-built-twice.fixed.md new file mode 100644 index 000000000..d6c5d9a37 --- /dev/null +++ b/changelog.d/791-sheet-built-twice.fixed.md @@ -0,0 +1,4 @@ +The desktop front end no longer builds a class's sheet twice when the kernel answers its +route's description twice, once for the description fetched ahead and once for the one +asked as the setup opened; the second build replaced every widget on the sheet for +nothing ([#791](https://github.com/LupoLab/solprop/issues/791)). diff --git a/gui/src/solprop_gui/ui/document.py b/gui/src/solprop_gui/ui/document.py index 77ac1eed7..7f06d029d 100644 --- a/gui/src/solprop_gui/ui/document.py +++ b/gui/src/solprop_gui/ui/document.py @@ -268,8 +268,11 @@ def on_reply(self, reply: Reply) -> None: adapt = self._adapt.pop(reply.request_id, None) if purpose.startswith("describe-") and reply.ok and isinstance(value, dict): route = str(value["route"]) - self.descriptions[route] = value - self.described.emit(route) + # A route asked ahead and asked again as its setup opened can be + # answered twice; a second answer would rebuild the sheet for nothing. + if route not in self.descriptions: + self.descriptions[route] = value + self.described.emit(route) elif purpose == "example" and reply.ok and isinstance(value, str): model = RecipeModel(value) if adapt is not None: diff --git a/gui/tests/test_ui_workflow.py b/gui/tests/test_ui_workflow.py index cc93ffd06..d2c2e8463 100644 --- a/gui/tests/test_ui_workflow.py +++ b/gui/tests/test_ui_workflow.py @@ -11,10 +11,11 @@ import numpy as np import pytest -from PySide6.QtCore import QEvent, QSettings, QStandardPaths, Qt +from PySide6.QtCore import QCoreApplication, QEvent, QSettings, QStandardPaths, Qt from PySide6.QtGui import QFontDatabase, QStandardItemModel from PySide6.QtWidgets import QBoxLayout, QLabel, QLineEdit, QWidget from pytestqt.qtbot import QtBot +from shiboken6 import isValid from solprop.constants import C from solprop.output import open_file from solprop.service.messages import Event @@ -1436,6 +1437,26 @@ def test_a_step_index_fibre_solves_its_mode_for_its_numbers( ) +def test_a_second_answer_to_a_routes_description_leaves_its_sheet_standing( + window: WorkflowWindow, qtbot: QtBot +) -> None: + # A route asked ahead and asked again as its setup opened is answered twice when + # the first answer is through before the second question is sent (#791). + window.begin_class("gnlse") + sheet = window.sheet + qtbot.waitUntil(lambda: sheet.problem is GNLSE, timeout=WAIT_MS) + order = sheet.derived["soliton_order"] + model = window.document.model + assert model is not None + route = model.route + again = window.document._ask("describe", {"route": route}, f"describe-{route}") + qtbot.waitUntil(lambda: again not in window.document._pending, timeout=WAIT_MS) + QCoreApplication.sendPostedEvents(None, QEvent.Type.DeferredDelete) + assert sheet.derived["soliton_order"] is order + assert isValid(order) + qtbot.waitUntil(lambda: order.text() == "3", timeout=WAIT_MS) + + def test_a_graded_index_fibre_shows_its_profile_and_its_modes( window: WorkflowWindow, qtbot: QtBot, tmp_path: Path ) -> None: