move controller connect to popup dialog

This commit is contained in:
ykcheungab
2026-09-24 21:36:24 +08:00
parent 4dad413d29
commit 6effe74172
13 changed files with 773 additions and 99 deletions
+1 -1
View File
@@ -68,7 +68,7 @@ _SCOPED_ENUMS = {
"QMessageBox": ("StandardButton", "Icon"),
"QDialog": ("DialogCode",),
"QAbstractItemView": ("SelectionMode", "EditTrigger"),
"QDialogButtonBox": ("StandardButton",),
"QDialogButtonBox": ("StandardButton", "ButtonRole"),
"QPainter": ("RenderHint", "CompositionMode"),
"QImage": ("Format",),
"QSurfaceFormat": ("RenderableType", "OpenGLContextProfile", "SwapBehavior"),
+188
View File
@@ -0,0 +1,188 @@
"""The device-setup dialog: connection and bus initialisation, out of the rail.
Both groups are touched once per machine start-up. In the rail they cost ~460 px of
height above the axis readout, which is read all day — so they moved into a modeless
dialog opened from the status strip, its state chips, or the File menu.
What these tests protect:
* the rail no longer carries them, and the dialog is not open at start-up;
* every entry point works and lands on the right tab;
* the window's own handlers still receive the panels' signals, from inside the
dialog — the connect and download code paths did not move, only the widgets did;
* the dialog survives a language change and remembers its size and tab.
"""
from __future__ import annotations
import pytest
from orisys_app_shared.i18n import set_locale, t
from orisys_autocal.motion import ConnectionSpec
from orisys_autocal.ui.device_setup import DeviceSetupDialog
def test_the_rail_no_longer_holds_the_startup_panels(make_window):
"""The point of the change: the rail is the run screen, not the setup form."""
window = make_window()
try:
rail = window.rail_content.findChildren(object)
names = {type(child).__name__ for child in rail}
assert "AxisReadoutPanel" in names
assert "ConnectionPanel" not in names
assert "BusPanel" not in names
# And they are in the dialog, once each. (The parent is Qt's internal
# stacked widget, so ask about ancestry rather than the direct parent.)
dialog = window.device_setup
assert window.connection_panel is dialog.connection_panel
assert window.bus_panel is dialog.bus_panel
assert dialog.tabs.isAncestorOf(window.connection_panel)
assert dialog.tabs.isAncestorOf(window.bus_panel)
finally:
window.close()
def test_the_dialog_is_hidden_until_it_is_asked_for(make_window):
window = make_window()
try:
assert not window.device_setup.isVisible()
window._show_device_setup() # noqa: SLF001
assert window.device_setup.isVisible()
# Showing it again raises rather than ignores: a second click that appears
# to do nothing reads as a broken button.
window._show_device_setup("bus") # noqa: SLF001
assert window.device_setup.isVisible()
assert window.device_setup.current_tab() == "bus"
finally:
window.close()
def test_the_strip_button_opens_the_setup(make_window):
window = make_window()
try:
window.status_strip.setup_button.click()
assert window.device_setup.isVisible()
assert window.status_strip.setup_button.text() == t("setup.open")
finally:
window.close()
@pytest.mark.parametrize(
"chip, tab",
[("chip_connection", "connection"), ("chip_bus", "bus"), ("chip_init", "bus")],
)
def test_the_state_chips_open_the_tab_they_report(make_window, chip, tab):
"""A chip that says "not connected" is the natural place to click."""
window = make_window()
try:
getattr(window.status_strip, chip).clicked.emit()
assert window.device_setup.isVisible()
assert window.device_setup.current_tab() == tab
finally:
window.close()
def test_the_file_menu_opens_the_setup(make_window):
window = make_window()
try:
window.act_device_setup.trigger()
assert window.device_setup.isVisible()
assert window.device_setup.current_tab() == "connection"
assert window.act_device_setup.text() == t("menu.device_setup")
finally:
window.close()
def test_connecting_from_the_dialog_reaches_the_window(make_window):
"""The widgets moved; the code path did not.
The connect button lives in the dialog now, so this drives the *button* rather
than emitting the signal directly: it is the signal wiring across the new
parent that could have been lost.
"""
window = make_window()
try:
seen = []
window.connection_panel.connectRequested.connect(seen.append)
panel = window.connection_panel
panel.mode_combo.setCurrentIndex(panel.mode_combo.findData("demo"))
window.device_setup.open_for("connection")
panel.open_button.click()
assert seen, "the connection request never left the dialog"
assert isinstance(seen[0], ConnectionSpec)
assert seen[0].mode == "demo"
finally:
window.close()
def test_downloading_the_bas_from_the_dialog_reaches_the_window(make_window):
window = make_window()
try:
# A path *must* be set first: with none, the window opens a modal file
# chooser, which offscreen is a hang rather than a test.
from orisys_autocal.ui.bus_panel import default_bas_dir
window.bus_panel.set_bas_path(str(default_bas_dir() / "ECAT.bas"))
seen = []
window.bus_panel.downloadRequested.connect(lambda: seen.append(True))
window.device_setup.open_for("bus")
window.bus_panel.download_button.click()
assert seen, "the download request never left the dialog"
finally:
window.close()
def test_the_dialog_survives_a_language_change(make_window):
window = make_window()
try:
window._set_language("en_US") # noqa: SLF001
assert window.device_setup.windowTitle() == t("setup.title")
assert window.device_setup.tabs.tabText(1) == t("setup.tab_bus")
assert window.status_strip.setup_button.text() == t("setup.open")
# The panels inside are retranslated too, not just the dialog's own labels.
assert window.connection_panel.open_button.text() == t("connection.open")
window._set_language("zh_CN") # noqa: SLF001
set_locale("zh_CN")
finally:
window.close()
def test_the_dialog_remembers_its_size_and_tab(make_window):
window = make_window()
try:
window.device_setup.select_tab("bus")
window.device_setup.resize(640, 480)
stored = window.device_setup.settings()
assert stored["tab"] == "bus"
assert stored["size"] == [640, 480]
fresh = DeviceSetupDialog(ConnectionSpec(mode="eth", ip="10.0.0.1"))
try:
fresh.apply_settings(stored)
assert fresh.size().width() == 640
assert fresh.current_tab() == "bus"
# Anything malformed is ignored, not raised on: this comes from a file
# a human may have edited.
fresh.apply_settings({"size": ["wide", 2], "tab": 7})
fresh.apply_settings(None)
finally:
fresh.deleteLater()
finally:
window.close()
def test_opening_the_setup_does_not_touch_the_connection(make_window):
"""Opening a dialog is not a command: it must not connect or disconnect."""
window = make_window()
try:
window.device_setup.open_for("connection")
assert not window._last_snapshot.connected # noqa: SLF001
window.device_setup.close()
assert window.connection_panel.close_button.isEnabled() is False
assert window.connection_panel.open_button.isEnabled() is True
finally:
window.close()