From ecbefb69e19f017d84cd7bd09a08bc84ac9780c5 Mon Sep 17 00:00:00 2001 From: David Perl Date: Tue, 2 Sep 2025 16:06:55 +0200 Subject: [PATCH] feat: prepare available devices for dragging config --- .../available_device_group.py | 12 ++++++-- .../available_device_group_ui.py | 28 ++++++++++++++++--- .../available_device_resources.py | 4 ++- .../available_device_resources_ui.py | 28 +++++++++++++++++-- 4 files changed, 63 insertions(+), 9 deletions(-) diff --git a/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_group.py b/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_group.py index 1fc2810c..057509d5 100644 --- a/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_group.py +++ b/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_group.py @@ -12,16 +12,17 @@ from bec_widgets.widgets.control.device_manager.components.available_device_reso from bec_widgets.widgets.control.device_manager.components.available_device_resources.device_resource_backend import ( HashableDevice, ) +from bec_widgets.widgets.control.device_manager.components.constants import CONFIG_DATA_ROLE def _warning_string(spec: HashableDevice): name_warning = ( - f"Device defined with multiple names! Please check:\n {'\n '.join(spec.names)}\n" + "Device defined with multiple names! Please check:\n " + "\n ".join(spec.names) if len(spec.names) > 1 else "" ) source_warning = ( - f"Device found in multiple source files! Please check:\n {'\n '.join(spec._source_files)}" + "Device found in multiple source files! Please check:\n " + "\n ".join(spec._source_files) if len(spec._source_files) > 1 else "" ) @@ -112,6 +113,7 @@ class AvailableDeviceGroup(ExpandableGroupFrame, Ui_AvailableDeviceGroup): super().__init__(parent=parent, **kwargs) self.setupUi(self) self.title_text = name # type: ignore + self._mime_data = [] self._devices: dict[str, _DeviceEntry] = {} for device in data: self._add_item(device) @@ -123,12 +125,18 @@ class AvailableDeviceGroup(ExpandableGroupFrame, Ui_AvailableDeviceGroup): def _add_item(self, device: HashableDevice): item = QListWidgetItem(self.device_list) + device_dump = device.model_dump(exclude_defaults=True) + item.setData(CONFIG_DATA_ROLE, device_dump) + self._mime_data.append(device_dump) widget = _DeviceEntryWidget(device, self) item.setSizeHint(QSize(widget.width(), widget.height())) self.device_list.setItemWidget(item, widget) self.device_list.addItem(item) self._devices[device.name] = _DeviceEntry(item, widget) + def create_mime_data(self): + return self._mime_data + def reset_devices_state(self): for dev in self._devices.values(): dev.widget.set_included(False) diff --git a/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_group_ui.py b/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_group_ui.py index d2565b4a..88ce0df3 100644 --- a/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_group_ui.py +++ b/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_group_ui.py @@ -1,10 +1,28 @@ +import json from functools import partial +from bec_lib.utils.json import ExtendedEncoder from bec_qthemes import material_icon -from PySide6.QtWidgets import QFrame -from qtpy.QtCore import QMetaObject +from qtpy.QtCore import QByteArray, QMetaObject, QMimeData, Qt from qtpy.QtWidgets import QLabel, QListWidget, QToolButton, QVBoxLayout +from bec_widgets.widgets.control.device_manager.components.constants import ( + CONFIG_DATA_ROLE, + MIME_DEVICE_CONFIG, +) + + +class _DeviceListWiget(QListWidget): + def mimeTypes(self): + return [MIME_DEVICE_CONFIG] + + def mimeData(self, items): + mime_obj = QMimeData() + data = [item.data(CONFIG_DATA_ROLE) for item in items] + byte_array = QByteArray(json.dumps(data, cls=ExtendedEncoder).encode("utf-8")) + mime_obj.setData(MIME_DEVICE_CONFIG, byte_array) + return mime_obj + class Ui_AvailableDeviceGroup(object): def setupUi(self, AvailableDeviceGroup): @@ -41,11 +59,13 @@ class Ui_AvailableDeviceGroup(object): self.add_all_button.setObjectName("add_all_to_composition_button") title_layout.addWidget(self.add_all_button) - self.device_list = QListWidget(AvailableDeviceGroup) + self.device_list = _DeviceListWiget(AvailableDeviceGroup) self.device_list.setSelectionMode(QListWidget.SelectionMode.ExtendedSelection) self.device_list.setObjectName("device_list") self.device_list.setFrameStyle(0) - + self.device_list.setDragEnabled(True) + self.device_list.setAcceptDrops(False) + self.device_list.setDefaultDropAction(Qt.DropAction.CopyAction) self.verticalLayout.addWidget(self.device_list) self.set_icons() diff --git a/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_resources.py b/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_resources.py index a4b8fc70..0fd7505d 100644 --- a/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_resources.py +++ b/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_resources.py @@ -15,6 +15,7 @@ from bec_widgets.widgets.control.device_manager.components.available_device_reso HashableDevice, get_backend, ) +from bec_widgets.widgets.control.device_manager.components.constants import CONFIG_DATA_ROLE class AvailableDeviceResources(BECWidget, QWidget, Ui_availableDeviceResources): @@ -37,9 +38,10 @@ class AvailableDeviceResources(BECWidget, QWidget, Ui_availableDeviceResources): self.device_groups_list.sortItems() def _add_device_group(self, device_group: str, devices: set[HashableDevice]): - self.device_groups_list.add_item( + item, widget = self.device_groups_list.add_item( device_group, self.device_groups_list, device_group, devices, expanded=False ) + item.setData(CONFIG_DATA_ROLE, widget.create_mime_data()) def _reset_devices_state(self): for device_group in self.device_groups_list.widgets(): diff --git a/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_resources_ui.py b/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_resources_ui.py index 4cfac859..0b7a56d9 100644 --- a/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_resources_ui.py +++ b/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_resources_ui.py @@ -1,4 +1,10 @@ -from qtpy.QtCore import QMetaObject, Qt +from __future__ import annotations + +import itertools +import json + +from bec_lib.utils.json import ExtendedEncoder +from qtpy.QtCore import QByteArray, QMetaObject, QMimeData, Qt from qtpy.QtWidgets import ( QAbstractItemView, QComboBox, @@ -14,6 +20,23 @@ from bec_widgets.utils.list_of_expandable_frames import ListOfExpandableFrames from bec_widgets.widgets.control.device_manager.components.available_device_resources.available_device_group import ( AvailableDeviceGroup, ) +from bec_widgets.widgets.control.device_manager.components.constants import ( + CONFIG_DATA_ROLE, + MIME_DEVICE_CONFIG, +) + + +class _ListOfDeviceGroups(ListOfExpandableFrames[AvailableDeviceGroup]): + + def mimeTypes(self): + return [MIME_DEVICE_CONFIG] + + def mimeData(self, items): + mime_obj = QMimeData() + data = list(itertools.chain.from_iterable(item.data(CONFIG_DATA_ROLE) for item in items)) + byte_array = QByteArray(json.dumps(data, cls=ExtendedEncoder).encode("utf-8")) + mime_obj.setData(MIME_DEVICE_CONFIG, byte_array) + return mime_obj class Ui_availableDeviceResources(object): @@ -32,7 +55,7 @@ class Ui_availableDeviceResources(object): self.grouping_selector = QComboBox() self.search_layout.addWidget(self.grouping_selector) - self.device_groups_list = ListOfExpandableFrames( + self.device_groups_list = _ListOfDeviceGroups( availableDeviceResources, AvailableDeviceGroup ) self.device_groups_list.setObjectName("device_groups_list") @@ -46,6 +69,7 @@ class Ui_availableDeviceResources(object): self.device_groups_list.setSelectionMode(QListWidget.SelectionMode.ExtendedSelection) self.device_groups_list.setDragEnabled(True) self.device_groups_list.setAcceptDrops(False) + self.device_groups_list.setDefaultDropAction(Qt.DropAction.CopyAction) self.device_groups_list.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) availableDeviceResources.setMinimumWidth(250) availableDeviceResources.resize(250, availableDeviceResources.height())