mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 11:41:49 +02:00
fix: changed inheritance to adress qt designer bug in rendering
This commit is contained in:
@ -12,7 +12,7 @@ from typing import TYPE_CHECKING
|
|||||||
import qdarktheme
|
import qdarktheme
|
||||||
from bec_lib.utils.import_utils import lazy_import_from
|
from bec_lib.utils.import_utils import lazy_import_from
|
||||||
from qtpy.QtCore import QObject, QTimer, Signal, Slot
|
from qtpy.QtCore import QObject, QTimer, Signal, Slot
|
||||||
from qtpy.QtWidgets import QTreeWidget, QTreeWidgetItem
|
from qtpy.QtWidgets import QHBoxLayout, QTreeWidget, QTreeWidgetItem, QWidget
|
||||||
|
|
||||||
from bec_widgets.utils.bec_connector import BECConnector
|
from bec_widgets.utils.bec_connector import BECConnector
|
||||||
from bec_widgets.widgets.bec_status_box.status_item import StatusItem
|
from bec_widgets.widgets.bec_status_box.status_item import StatusItem
|
||||||
@ -43,8 +43,8 @@ class BECServiceStatusMixin(QObject):
|
|||||||
|
|
||||||
services_update = Signal(dict, dict)
|
services_update = Signal(dict, dict)
|
||||||
|
|
||||||
def __init__(self, client: BECClient):
|
def __init__(self, parent, client: BECClient):
|
||||||
super().__init__()
|
super().__init__(parent)
|
||||||
self.client = client
|
self.client = client
|
||||||
self._service_update_timer = QTimer()
|
self._service_update_timer = QTimer()
|
||||||
self._service_update_timer.timeout.connect(self._get_service_status)
|
self._service_update_timer.timeout.connect(self._get_service_status)
|
||||||
@ -57,7 +57,7 @@ class BECServiceStatusMixin(QObject):
|
|||||||
self.services_update.emit(self.client._services_info, self.client._services_metric)
|
self.services_update.emit(self.client._services_info, self.client._services_metric)
|
||||||
|
|
||||||
|
|
||||||
class BECStatusBox(BECConnector, QTreeWidget):
|
class BECStatusBox(BECConnector, QWidget):
|
||||||
"""An autonomous widget to display the status of BEC services.
|
"""An autonomous widget to display the status of BEC services.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -73,9 +73,6 @@ class BECStatusBox(BECConnector, QTreeWidget):
|
|||||||
service_update = Signal(BECServiceInfoContainer)
|
service_update = Signal(BECServiceInfoContainer)
|
||||||
bec_core_state = Signal(str)
|
bec_core_state = Signal(str)
|
||||||
|
|
||||||
_initialized = False
|
|
||||||
_bec_status_box = None
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
parent=None,
|
parent=None,
|
||||||
@ -84,34 +81,23 @@ class BECStatusBox(BECConnector, QTreeWidget):
|
|||||||
bec_service_status_mixin: BECServiceStatusMixin = None,
|
bec_service_status_mixin: BECServiceStatusMixin = None,
|
||||||
gui_id: str = None,
|
gui_id: str = None,
|
||||||
):
|
):
|
||||||
if self._initialized == True:
|
|
||||||
return
|
|
||||||
super().__init__(client=client, gui_id=gui_id)
|
super().__init__(client=client, gui_id=gui_id)
|
||||||
QTreeWidget.__init__(self, parent=parent)
|
QWidget.__init__(self, parent=parent)
|
||||||
|
self.tree = QTreeWidget(self)
|
||||||
|
self.layout = QHBoxLayout(self)
|
||||||
|
|
||||||
self.box_name = box_name
|
self.box_name = box_name
|
||||||
self.status_container = defaultdict(lambda: {"info": None, "item": None, "widget": None})
|
self.status_container = defaultdict(lambda: {"info": None, "item": None, "widget": None})
|
||||||
self._initialized = False
|
|
||||||
|
|
||||||
if not bec_service_status_mixin:
|
if not bec_service_status_mixin:
|
||||||
bec_service_status_mixin = BECServiceStatusMixin(client=self.client)
|
bec_service_status_mixin = BECServiceStatusMixin(self, client=self.client)
|
||||||
self.bec_service_status = bec_service_status_mixin
|
self.bec_service_status = bec_service_status_mixin
|
||||||
|
|
||||||
if not self._initialized:
|
self.init_ui()
|
||||||
self.init_ui()
|
self.bec_service_status.services_update.connect(self.update_service_status)
|
||||||
self.bec_service_status.services_update.connect(self.update_service_status)
|
self.bec_core_state.connect(self.update_top_item_status)
|
||||||
self.bec_core_state.connect(self.update_top_item_status)
|
self.tree.itemDoubleClicked.connect(self.on_tree_item_double_clicked)
|
||||||
self.itemDoubleClicked.connect(self.on_tree_item_double_clicked)
|
self.layout.addWidget(self.tree)
|
||||||
|
|
||||||
def __new__(cls, *args, forced: bool = False, **kwargs):
|
|
||||||
if forced:
|
|
||||||
cls._initialized = False
|
|
||||||
cls._bec_status_box = super(BECStatusBox, cls).__new__(cls)
|
|
||||||
return cls._bec_status_box
|
|
||||||
if cls._bec_status_box is not None and cls._initialized is True:
|
|
||||||
return cls._bec_status_box
|
|
||||||
cls._bec_status_box = super(BECStatusBox, cls).__new__(cls)
|
|
||||||
return cls._bec_status_box
|
|
||||||
|
|
||||||
def init_ui(self) -> None:
|
def init_ui(self) -> None:
|
||||||
"""Init the UI for the BECStatusBox widget, should only take place once."""
|
"""Init the UI for the BECStatusBox widget, should only take place once."""
|
||||||
@ -121,15 +107,16 @@ class BECStatusBox(BECConnector, QTreeWidget):
|
|||||||
tree_item.setExpanded(True)
|
tree_item.setExpanded(True)
|
||||||
tree_item.setDisabled(True)
|
tree_item.setDisabled(True)
|
||||||
self.status_container[self.box_name].update({"item": tree_item, "widget": top_label})
|
self.status_container[self.box_name].update({"item": tree_item, "widget": top_label})
|
||||||
self.addTopLevelItem(tree_item)
|
self.tree.addTopLevelItem(tree_item)
|
||||||
self.setItemWidget(tree_item, 0, top_label)
|
self.tree.setItemWidget(tree_item, 0, top_label)
|
||||||
self.service_update.connect(top_label.update_config)
|
self.service_update.connect(top_label.update_config)
|
||||||
self._initialized = True
|
self._initialized = True
|
||||||
|
|
||||||
def init_ui_tree_widget(self) -> None:
|
def init_ui_tree_widget(self) -> None:
|
||||||
"""Initialise the tree widget for the status box."""
|
"""Initialise the tree widget for the status box."""
|
||||||
self.setHeaderHidden(True)
|
self.tree.setHeaderHidden(True)
|
||||||
self.setStyleSheet(
|
# TODO probably here is a problem still with setting the stylesheet
|
||||||
|
self.tree.setStyleSheet(
|
||||||
"QTreeWidget::item:!selected "
|
"QTreeWidget::item:!selected "
|
||||||
"{ "
|
"{ "
|
||||||
"border: 1px solid gainsboro; "
|
"border: 1px solid gainsboro; "
|
||||||
@ -191,7 +178,10 @@ class BECStatusBox(BECConnector, QTreeWidget):
|
|||||||
container.metrics = metrics
|
container.metrics = metrics
|
||||||
return
|
return
|
||||||
service_info_item = BECServiceInfoContainer(
|
service_info_item = BECServiceInfoContainer(
|
||||||
service_name=service_name, status=status.name, info=info, metrics=metrics
|
service_name=service_name,
|
||||||
|
status=status.name if isinstance(status, BECStatus) else status,
|
||||||
|
info=info,
|
||||||
|
metrics=metrics,
|
||||||
)
|
)
|
||||||
self.status_container[service_name].update({"info": service_info_item})
|
self.status_container[service_name].update({"info": service_info_item})
|
||||||
|
|
||||||
@ -213,6 +203,9 @@ class BECStatusBox(BECConnector, QTreeWidget):
|
|||||||
metric_msg = services_metric.get(service_name, None)
|
metric_msg = services_metric.get(service_name, None)
|
||||||
metrics = metric_msg.metrics if metric_msg else None
|
metrics = metric_msg.metrics if metric_msg else None
|
||||||
if service_name in self.status_container:
|
if service_name in self.status_container:
|
||||||
|
if not msg:
|
||||||
|
self.add_tree_item(service_name, "NOTCONNECTED", {}, metrics)
|
||||||
|
continue
|
||||||
self._update_status_container(service_name, msg.status, msg.info, metrics)
|
self._update_status_container(service_name, msg.status, msg.info, metrics)
|
||||||
self.service_update.emit(self.status_container[service_name]["info"])
|
self.service_update.emit(self.status_container[service_name]["info"])
|
||||||
continue
|
continue
|
||||||
@ -236,6 +229,9 @@ class BECStatusBox(BECConnector, QTreeWidget):
|
|||||||
metrics = metric_msg.metrics if metric_msg else None
|
metrics = metric_msg.metrics if metric_msg else None
|
||||||
msg = services_info.pop(service_name, None)
|
msg = services_info.pop(service_name, None)
|
||||||
if service_name not in self.status_container:
|
if service_name not in self.status_container:
|
||||||
|
if not msg:
|
||||||
|
self.add_tree_item(service_name, "NOTCONNECTED", {}, metrics)
|
||||||
|
continue
|
||||||
self.add_tree_item(service_name, msg.status, msg.info, metrics)
|
self.add_tree_item(service_name, msg.status, msg.info, metrics)
|
||||||
continue
|
continue
|
||||||
if not msg:
|
if not msg:
|
||||||
@ -248,8 +244,6 @@ class BECStatusBox(BECConnector, QTreeWidget):
|
|||||||
|
|
||||||
self.service_update.emit(self.status_container[service_name]["info"])
|
self.service_update.emit(self.status_container[service_name]["info"])
|
||||||
|
|
||||||
# self.add_tree_item(service_name, msg.status, msg.info, metrics)
|
|
||||||
|
|
||||||
self.bec_core_state.emit(core_state.name if core_state else "NOTCONNECTED")
|
self.bec_core_state.emit(core_state.name if core_state else "NOTCONNECTED")
|
||||||
return services_info
|
return services_info
|
||||||
|
|
||||||
@ -278,10 +272,10 @@ class BECStatusBox(BECConnector, QTreeWidget):
|
|||||||
metrics (dict): The metrics of the service.
|
metrics (dict): The metrics of the service.
|
||||||
"""
|
"""
|
||||||
item_widget = self._create_status_widget(service_name, status, info, metrics)
|
item_widget = self._create_status_widget(service_name, status, info, metrics)
|
||||||
item = QTreeWidgetItem() # setDisabled=True
|
item = QTreeWidgetItem()
|
||||||
self.service_update.connect(item_widget.update_config)
|
self.service_update.connect(item_widget.update_config)
|
||||||
self.status_container[self.box_name]["item"].addChild(item)
|
self.status_container[self.box_name]["item"].addChild(item)
|
||||||
self.setItemWidget(item, 0, item_widget)
|
self.tree.setItemWidget(item, 0, item_widget)
|
||||||
self.status_container[service_name].update({"item": item, "widget": item_widget})
|
self.status_container[service_name].update({"item": item, "widget": item_widget})
|
||||||
|
|
||||||
@Slot(QTreeWidgetItem, int)
|
@Slot(QTreeWidgetItem, int)
|
||||||
@ -297,13 +291,13 @@ class BECStatusBox(BECConnector, QTreeWidget):
|
|||||||
objects["widget"].show_popup()
|
objects["widget"].show_popup()
|
||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
"""Upon closing the widget, clean up the BECStatusBox and the QTreeWidget.
|
"""Upon closing the widget, clean up the BECStatusBox and the QWidget.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
event: The close event.
|
event: The close event.
|
||||||
"""
|
"""
|
||||||
super().cleanup()
|
super().cleanup()
|
||||||
return QTreeWidget.closeEvent(self, event)
|
super().closeEvent(event)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -48,7 +48,7 @@ class BECStatusBoxPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
|||||||
return "BECStatusBox"
|
return "BECStatusBox"
|
||||||
|
|
||||||
def toolTip(self):
|
def toolTip(self):
|
||||||
return "Widget to display the BECStatus from all active services."
|
return "An autonomous widget to display the status of BEC services."
|
||||||
|
|
||||||
def whatsThis(self):
|
def whatsThis(self):
|
||||||
return self.toolTip()
|
return self.toolTip()
|
||||||
|
@ -23,11 +23,11 @@ def status_box(qtbot, mocked_client, service_status_fixture):
|
|||||||
|
|
||||||
|
|
||||||
def test_update_top_item(status_box):
|
def test_update_top_item(status_box):
|
||||||
assert status_box.children()[0].children()[0].config.status == "IDLE"
|
assert status_box.tree.children()[0].children()[0].config.status == "IDLE"
|
||||||
name = status_box.box_name
|
name = status_box.box_name
|
||||||
status_box.update_top_item_status(status="RUNNING")
|
status_box.update_top_item_status(status="RUNNING")
|
||||||
assert status_box.status_container[name]["info"].status == "RUNNING"
|
assert status_box.status_container[name]["info"].status == "RUNNING"
|
||||||
assert status_box.children()[0].children()[0].config.status == "RUNNING"
|
assert status_box.tree.children()[0].children()[0].config.status == "RUNNING"
|
||||||
|
|
||||||
|
|
||||||
def test_create_status_widget(status_box):
|
def test_create_status_widget(status_box):
|
||||||
@ -62,9 +62,9 @@ def test_add_tree_item(status_box):
|
|||||||
status = BECStatus.IDLE
|
status = BECStatus.IDLE
|
||||||
info = {"test": "test"}
|
info = {"test": "test"}
|
||||||
metrics = {"metric": "test_metric"}
|
metrics = {"metric": "test_metric"}
|
||||||
assert len(status_box.children()[0].children()) == 1
|
assert len(status_box.tree.children()[0].children()) == 1
|
||||||
status_box.add_tree_item(name, status, info, metrics)
|
status_box.add_tree_item(name, status, info, metrics)
|
||||||
assert len(status_box.children()[0].children()) == 2
|
assert len(status_box.tree.children()[0].children()) == 2
|
||||||
assert name in status_box.status_container
|
assert name in status_box.status_container
|
||||||
|
|
||||||
|
|
||||||
@ -98,14 +98,14 @@ def test_update_core_services(status_box):
|
|||||||
services_metrics = {name: ServiceMetricMessage(name=name, metrics=metrics)}
|
services_metrics = {name: ServiceMetricMessage(name=name, metrics=metrics)}
|
||||||
|
|
||||||
status_box.update_core_services(services_status, services_metrics)
|
status_box.update_core_services(services_status, services_metrics)
|
||||||
assert status_box.children()[0].children()[0].config.status == "RUNNING"
|
assert status_box.tree.children()[0].children()[0].config.status == "RUNNING"
|
||||||
assert status_box.status_container[name]["widget"].config.metrics == metrics
|
assert status_box.status_container[name]["widget"].config.metrics == metrics
|
||||||
|
|
||||||
status = BECStatus.IDLE
|
status = BECStatus.IDLE
|
||||||
services_status = {name: StatusMessage(name=name, status=status, info=info)}
|
services_status = {name: StatusMessage(name=name, status=status, info=info)}
|
||||||
services_metrics = {name: ServiceMetricMessage(name=name, metrics=metrics)}
|
services_metrics = {name: ServiceMetricMessage(name=name, metrics=metrics)}
|
||||||
status_box.update_core_services(services_status, services_metrics)
|
status_box.update_core_services(services_status, services_metrics)
|
||||||
assert status_box.children()[0].children()[0].config.status == status.name
|
assert status_box.tree.children()[0].children()[0].config.status == status.name
|
||||||
assert status_box.status_container[name]["widget"].config.metrics == metrics
|
assert status_box.status_container[name]["widget"].config.metrics == metrics
|
||||||
|
|
||||||
|
|
||||||
@ -119,5 +119,5 @@ def test_double_click_item(status_box):
|
|||||||
item = container["item"]
|
item = container["item"]
|
||||||
status_item = container["widget"]
|
status_item = container["widget"]
|
||||||
with mock.patch.object(status_item, "show_popup") as mock_show_popup:
|
with mock.patch.object(status_item, "show_popup") as mock_show_popup:
|
||||||
status_box.itemDoubleClicked.emit(item, 0)
|
status_box.tree.itemDoubleClicked.emit(item, 0)
|
||||||
assert mock_show_popup.call_count == 1
|
assert mock_show_popup.call_count == 1
|
||||||
|
Reference in New Issue
Block a user