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:
@@ -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):
|
||||
|
||||
@@ -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}"
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user