1
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2026-03-05 00:12:49 +01:00

feat: connect available devices to doc and yaml views

This commit is contained in:
2025-09-04 09:36:19 +02:00
committed by wyzula-jan
parent 8284ade4ad
commit b0456489a2
6 changed files with 53 additions and 41 deletions

View File

@@ -30,9 +30,6 @@ from bec_widgets.widgets.control.device_manager.components.available_device_reso
AvailableDeviceResources,
)
if TYPE_CHECKING:
from bec_lib.client import BECClient
logger = bec_logger.logger
@@ -157,6 +154,8 @@ class DeviceManagerView(BECWidget, QWidget):
# Connect slots
self.device_table_view.selected_devices.connect(self.dm_config_view.on_select_config)
self.device_table_view.selected_devices.connect(self.dm_docs_view.on_select_config)
self.available_devices.selected_devices.connect(self.dm_config_view.on_select_config)
self.available_devices.selected_devices.connect(self.dm_docs_view.on_select_config)
self.ophyd_test_view.device_validated.connect(
self.device_table_view.update_device_validation
)
@@ -260,6 +259,15 @@ class DeviceManagerView(BECWidget, QWidget):
# IO actions
def _coming_soon(self):
return QMessageBox.question(
self,
"Not implemented yet",
"This feature has not been implemented yet, will be coming soon...!!",
QMessageBox.StandardButton.Cancel,
QMessageBox.StandardButton.Cancel,
)
@SafeSlot()
def _load_file_action(self):
"""Action for the 'load' action to load a config from disk for the io_bundle of the toolbar."""
@@ -282,7 +290,7 @@ class DeviceManagerView(BECWidget, QWidget):
)
if file_path:
try:
config = yaml_load(file_path)
config = [{"name": k, **v} for k, v in yaml_load(file_path).items()]
except Exception as e:
logger.error(f"Failed to load config from file {file_path}. Error: {e}")
return
@@ -297,18 +305,14 @@ class DeviceManagerView(BECWidget, QWidget):
reply = QMessageBox.question(
self,
"Load currently active config",
"Do you really want to flush the current config and reload?",
"Do you really want to discard the current config and reload?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
QMessageBox.StandardButton.No,
)
if reply == QMessageBox.StandardButton.Yes and self.client.device_manager is not None:
cfg = {}
config_list = self.client.device_manager._get_redis_device_config()
for item in config_list:
k = item["name"]
item.pop("name")
cfg[k] = item
self.device_table_view.set_device_config(cfg)
self.device_table_view.set_device_config(
self.client.device_manager._get_redis_device_config()
)
else:
return
@@ -328,7 +332,7 @@ class DeviceManagerView(BECWidget, QWidget):
self, caption="Save Config File", dir=config_path
)
if file_path:
config = self.device_table_view.get_device_config()
config = {cfg.pop("name"): cfg for cfg in self.device_table_view.get_device_config()}
with open(file_path, "w") as file:
file.write(yaml.dump(config))
@@ -337,13 +341,7 @@ class DeviceManagerView(BECWidget, QWidget):
def _update_redis_action(self):
"""Action for the 'update_redis' action to update the current config in Redis."""
config = self.device_table_view.get_device_config()
reply = QMessageBox.question(
self,
"Not implemented yet",
"This feature has not been implemented yet, will be coming soon...!!",
QMessageBox.StandardButton.Cancel,
QMessageBox.StandardButton.Cancel,
)
reply = self._coming_soon()
# Table actions
@@ -368,13 +366,7 @@ class DeviceManagerView(BECWidget, QWidget):
def _add_device_action(self):
"""Action for the 'add_device' action to add a new device."""
# Implement the logic to add a new device
reply = QMessageBox.question(
self,
"Not implemented yet",
"This feature has not been implemented yet, will be coming soon...!!",
QMessageBox.StandardButton.Cancel,
QMessageBox.StandardButton.Cancel,
)
reply = self._coming_soon()
@SafeSlot()
def _remove_device_action(self):
@@ -387,13 +379,7 @@ class DeviceManagerView(BECWidget, QWidget):
def _rerun_validation_action(self):
"""Action for the 'rerun_validation' action to rerun validation on selected devices."""
# Implement the logic to rerun validation on selected devices
reply = QMessageBox.question(
self,
"Not implemented yet",
"This feature has not been implemented yet, will be coming soon...!!",
QMessageBox.StandardButton.Cancel,
QMessageBox.StandardButton.Cancel,
)
reply = self._coming_soon()
####### Default view has to be done with setting up splitters ########
def set_default_view(self, horizontal_weights: list, vertical_weights: list):

View File

@@ -3,7 +3,7 @@ from typing import NamedTuple
from uuid import uuid4
from bec_qthemes import material_icon
from qtpy.QtCore import QItemSelection, QSize
from qtpy.QtCore import QItemSelection, QSize, Signal
from qtpy.QtWidgets import QFrame, QHBoxLayout, QLabel, QListWidgetItem, QVBoxLayout, QWidget
from bec_widgets.utils.error_popups import SafeSlot
@@ -110,6 +110,9 @@ class _DeviceEntry(NamedTuple):
class AvailableDeviceGroup(ExpandableGroupFrame, Ui_AvailableDeviceGroup):
selected_devices = Signal(list)
def __init__(
self,
parent=None,
@@ -182,6 +185,8 @@ class AvailableDeviceGroup(ExpandableGroupFrame, Ui_AvailableDeviceGroup):
@SafeSlot(QItemSelection, QItemSelection)
def _on_selection_changed(self, selected: QItemSelection, deselected: QItemSelection) -> None:
self._shared_selection_signal.proc.emit(self._shared_selection_uuid)
config = [dev.as_normal_device().model_dump() for dev in self.get_selection()]
self.selected_devices.emit(config)
@SafeSlot(str)
def _handle_shared_selection_signal(self, uuid: str):
@@ -198,9 +203,6 @@ class AvailableDeviceGroup(ExpandableGroupFrame, Ui_AvailableDeviceGroup):
widgets = (w.widget for _, w in self._devices.items() if w.list_item in selection)
return set(w._device_spec for w in widgets)
def test(self, *args):
print(self.get_selection())
def __repr__(self) -> str:
return f"{self.__class__.__name__}: {self.title_text}"

View File

@@ -12,6 +12,13 @@ from bec_widgets.widgets.control.device_manager.components.constants import (
class _DeviceListWiget(QListWidget):
def _item_iter(self):
return (self.item(i) for i in range(self.count()))
def all_configs(self):
return [item.data(CONFIG_DATA_ROLE) for item in self._item_iter()]
def mimeTypes(self):
return [MIME_DEVICE_CONFIG]

View File

@@ -2,7 +2,7 @@ from random import randint
from typing import Any, Iterable
from uuid import uuid4
from qtpy.QtCore import QItemSelection
from qtpy.QtCore import QItemSelection, Signal
from qtpy.QtWidgets import QWidget
from bec_widgets.utils.bec_widget import BECWidget
@@ -22,6 +22,9 @@ from bec_widgets.widgets.control.device_manager.components.constants import CONF
class AvailableDeviceResources(BECWidget, QWidget, Ui_availableDeviceResources):
selected_devices = Signal(list) # list[dict[str,Any]] of device configs currently selected
def __init__(self, parent=None, shared_selection_signal=SharedSelectionSignal(), **kwargs):
super().__init__(parent=parent, **kwargs)
self.setupUi(self)
@@ -56,6 +59,8 @@ class AvailableDeviceResources(BECWidget, QWidget, Ui_availableDeviceResources):
expanded=False,
)
item.setData(CONFIG_DATA_ROLE, widget.create_mime_data())
# Re-emit the selected items from a subgroup - all other selections should be disabled anyway
widget.selected_devices.connect(self.selected_devices)
def resizeEvent(self, event):
super().resizeEvent(event)
@@ -64,6 +69,7 @@ class AvailableDeviceResources(BECWidget, QWidget, Ui_availableDeviceResources):
@SafeSlot(QItemSelection, QItemSelection)
def _on_selection_changed(self, selected: QItemSelection, deselected: QItemSelection) -> None:
self.selected_devices.emit(self.device_groups_list.selected_devices())
self._shared_selection_signal.proc.emit(self._shared_selection_uuid)
@SafeSlot(str)

View File

@@ -1,6 +1,7 @@
from __future__ import annotations
import itertools
from typing import Generator
from qtpy.QtCore import QMetaObject, Qt
from qtpy.QtWidgets import (
@@ -26,6 +27,14 @@ from bec_widgets.widgets.control.device_manager.components.constants import (
class _ListOfDeviceGroups(ListOfExpandableFrames[AvailableDeviceGroup]):
def selected_devices(self):
selected_items = (self.item(r.row()) for r in self.selectionModel().selectedRows())
widgets: Generator[AvailableDeviceGroup, None, None] = (
self.itemWidget(item) for item in selected_items # type: ignore
)
return list(itertools.chain.from_iterable(w.device_list.all_configs() for w in widgets))
def mimeTypes(self):
return [MIME_DEVICE_CONFIG]

View File

@@ -147,8 +147,10 @@ class WrappingTextDelegate(DictToolTipDelegate):
painter.save()
painter.setClipRect(option.rect)
text_option = Qt.TextWordWrap | Qt.AlignLeft | Qt.AlignTop
painter.drawText(option.rect.adjusted(4, 2, -4, -2), text_option, text)
text_option = (
Qt.TextFlag.TextWordWrap | Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop
)
painter.drawText(option.rect.adjusted(4, 2, -5, -2), text_option, text)
painter.restore()
def sizeHint(self, option, index):