From b2c706b85fa4b113f9640fc98c598fa1e4cc130f Mon Sep 17 00:00:00 2001 From: Mark Wolfman Date: Sun, 12 Jan 2025 15:12:24 -0600 Subject: [PATCH] Added pydm channels for the 'current' checkboxes for proposal and ESAF id's. --- src/firefly/run_browser/display.py | 47 ++++++++++++++++++- src/firefly/run_browser/tests/test_display.py | 31 ++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/firefly/run_browser/display.py b/src/firefly/run_browser/display.py index 4a4cfbe7..d814ca57 100644 --- a/src/firefly/run_browser/display.py +++ b/src/firefly/run_browser/display.py @@ -3,7 +3,7 @@ import logging from collections import Counter from contextlib import contextmanager -from functools import wraps +from functools import wraps, partial from typing import Mapping, Optional, Sequence import qtawesome as qta @@ -11,6 +11,9 @@ from qasync import asyncSlot from qtpy.QtCore import Qt, QDateTime from qtpy.QtGui import QStandardItem, QStandardItemModel +from ophyd_async.core import Device +from ophyd import Device as ThreadedDevice +from pydm import PyDMChannel from firefly import display from firefly.run_browser.client import DatabaseWorker @@ -49,6 +52,9 @@ class RunBrowserDisplay(display.FireflyDisplay): selected_runs: list _running_db_tasks: Mapping + proposal_channel: PyDMChannel + esaf_channel: PyDMChannel + export_dialog: Optional[ExportDialog] = None # Counter for keeping track of UI hints for long DB hits @@ -226,6 +232,45 @@ def customize_ui(self): # Create a new export dialog for saving files self.export_dialog = ExportDialog(parent=self) + async def update_devices(self, registry): + try: + bss_device = registry["bss"] + except KeyError: + log.warning("Could not find device 'bss', disabling 'current' filters.") + self.ui.filter_current_proposal_checkbox.setChecked(False), + self.ui.filter_current_proposal_checkbox.setEnabled(False), + self.ui.filter_current_esaf_checkbox.setChecked(False), + self.ui.filter_current_esaf_checkbox.setEnabled(False), + else: + self.setup_bss_channels(bss_device) + await super().update_devices(registry) + + def setup_bss_channels(self, bss: Device | ThreadedDevice): + """Setup channels to update the proposal and ESAF ID boxes.""" + self.proposal_channel.disconnect() + self.proposal_channel = PyDMChannel( + address=f"haven://{bss.proposal.proposal_id.name}", + value_slot=partial( + self.update_bss_filter, + combobox=self.ui.filter_proposal_combobox, + checkbox=self.ui.filter_current_proposal_checkbox, + ) + ) + self.esaf_channel.disconnect() + self.esaf_channel = PyDMChannel( + address=f"haven://{bss.esaf.esaf_id.name}", + value_slot=partial( + self.update_bss_filter, + combobox=self.ui.filter_esaf_combobox, + checkbox=self.ui.filter_current_esaf_checkbox, + ) + ) + + def update_bss_filter(self, text: str, *, combobox, checkbox): + """If *checkbox* is checked, update *combobox* with new *text*.""" + if checkbox.checkState(): + combobox.setCurrentText(text) + def auto_range(self): self.plot_1d_view.autoRange() diff --git a/src/firefly/run_browser/tests/test_display.py b/src/firefly/run_browser/tests/test_display.py index f1343b03..4d439ea0 100644 --- a/src/firefly/run_browser/tests/test_display.py +++ b/src/firefly/run_browser/tests/test_display.py @@ -1,16 +1,25 @@ import datetime as dt import asyncio from unittest.mock import MagicMock +from functools import partial import numpy as np import pytest from pyqtgraph import ImageItem, ImageView, PlotItem, PlotWidget from qtpy.QtWidgets import QFileDialog import time_machine +from ophyd.sim import instantiate_fake_device +from haven.devices.beamline_manager import EpicsBssDevice from firefly.run_browser.display import RunBrowserDisplay +@pytest.fixture() +def bss(sim_registry): + bss_ = instantiate_fake_device(EpicsBssDevice, prefix="apsbss:", name="bss") + return bss_ + + @pytest.fixture() async def display(qtbot, catalog, mocker): mocker.patch( @@ -423,6 +432,28 @@ def test_time_filters(display): filters = display.filters() assert "after" in filters assert "before" in filters + + + +def test_bss_channels(display, bss): + """Do the widgets get updated based on the BSS proposal ID, etc.""" + display.setup_bss_channels(bss) + assert display.proposal_channel.address == f"haven://{bss.proposal.proposal_id.name}" + assert display.esaf_channel.address == f"haven://{bss.esaf.esaf_id.name}" + + +def test_update_bss_filters(display): + checkbox = display.ui.filter_current_proposal_checkbox + combobox = display.ui.filter_proposal_combobox + update_slot = partial(display.update_bss_filter, combobox=combobox, checkbox=checkbox) + # Enable the "current" checkbox, and make sure the combobox updates + checkbox.setChecked(True) + update_slot("89321") + assert combobox.currentText() == "89321" + # Disable the "current" checkbox, and make sure the combobox doesn't update + checkbox.setChecked(False) + update_slot("99531") + assert combobox.currentText() == "89321" # ----------------------------------------------------------------------------- # :author: Mark Wolfman