mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 03:31:50 +02:00
WIP ensure sibling names are unique
This commit is contained in:
@ -7,6 +7,8 @@ import uuid
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from PySide6.QtCore import Qt
|
||||
|
||||
from bec_lib.logger import bec_logger
|
||||
from bec_lib.utils.import_utils import lazy_import_from
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
@ -17,6 +19,7 @@ from bec_widgets.cli.rpc.rpc_register import RPCRegister
|
||||
from bec_widgets.utils.container_utils import WidgetContainerUtils
|
||||
from bec_widgets.utils.error_popups import ErrorPopupUtility
|
||||
from bec_widgets.utils.error_popups import SafeSlot as pyqtSlot
|
||||
from bec_widgets.utils.widget_io import WidgetHierarchy
|
||||
from bec_widgets.utils.yaml_dialog import load_yaml, load_yaml_gui, save_yaml, save_yaml_gui
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
@ -129,9 +132,13 @@ class BECConnector:
|
||||
raise ValueError(f"Name {name} contains invalid characters.")
|
||||
# TODO Hierarchy can be refreshed upon creation
|
||||
if isinstance(self, QObject):
|
||||
# 1) If no objectName is set, set the initial name
|
||||
if not self.objectName():
|
||||
self.setObjectName(name if name else self.__class__.__name__)
|
||||
self._name = self.objectName()
|
||||
self._name = self.objectName()
|
||||
|
||||
# 2) Enforce unique objectName among siblings with the same BECConnector parent
|
||||
self._enforce_unique_sibling_name()
|
||||
else:
|
||||
self._name = name if name else self.__class__.__name__
|
||||
self.rpc_register = RPCRegister()
|
||||
@ -144,6 +151,49 @@ class BECConnector:
|
||||
# Store references to running workers so they're not garbage collected prematurely.
|
||||
self._workers = []
|
||||
|
||||
def _enforce_unique_sibling_name(self):
|
||||
"""
|
||||
Enforce that this BECConnector has a unique objectName among its siblings.
|
||||
|
||||
Sibling logic:
|
||||
- If there's a nearest BECConnector parent, only compare with children of that parent.
|
||||
- If parent is None (i.e., top-level object), compare with all other top-level BECConnectors.
|
||||
"""
|
||||
parent_bec = WidgetHierarchy._get_becwidget_ancestor(self)
|
||||
|
||||
if parent_bec:
|
||||
# We have a parent => only compare with siblings under that parent
|
||||
siblings = parent_bec.findChildren(BECConnector, options=Qt.FindDirectChildrenOnly)
|
||||
else:
|
||||
# No parent => treat all top-level BECConnectors as siblings
|
||||
# 1) Gather all BECConnectors from QApplication
|
||||
all_widgets = QApplication.allWidgets()
|
||||
all_bec = [w for w in all_widgets if isinstance(w, BECConnector)]
|
||||
# 2) "Top-level" means closest BECConnector parent is None
|
||||
top_level_bec = [
|
||||
w for w in all_bec if WidgetHierarchy._get_becwidget_ancestor(w) is None
|
||||
]
|
||||
# 3) We are among these top-level siblings
|
||||
siblings = top_level_bec
|
||||
|
||||
# Collect used names among siblings
|
||||
used_names = {sib.objectName() for sib in siblings if sib is not self}
|
||||
|
||||
base_name = self.objectName()
|
||||
if base_name not in used_names:
|
||||
# Name is already unique among siblings
|
||||
return
|
||||
|
||||
# Need a suffix to avoid collision
|
||||
counter = 0
|
||||
while True:
|
||||
trial_name = f"{base_name}_{counter}"
|
||||
if trial_name not in used_names:
|
||||
self.setObjectName(trial_name)
|
||||
self._name = trial_name
|
||||
break
|
||||
counter += 1
|
||||
|
||||
def submit_task(self, fn, *args, on_complete: pyqtSlot = None, **kwargs) -> Worker:
|
||||
"""
|
||||
Submit a task to run in a separate thread. The task will run the specified
|
||||
|
@ -177,8 +177,9 @@ class _ErrorPopupUtility(QObject):
|
||||
msg.setStandardButtons(QMessageBox.Ok)
|
||||
msg.setDetailedText(detailed_text)
|
||||
msg.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
||||
msg.setMinimumWidth(600)
|
||||
msg.setMinimumHeight(400)
|
||||
msg.resize(800, 800)
|
||||
# msg.setMinimumWidth(600)
|
||||
# msg.setMinimumHeight(400)
|
||||
msg.exec_()
|
||||
|
||||
def show_property_error(self, title, message, widget):
|
||||
|
@ -23,8 +23,6 @@ from qtpy.QtWidgets import (
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from bec_widgets.utils import BECConnector
|
||||
from bec_widgets.utils.bec_widget import BECWidget
|
||||
from bec_widgets.widgets.utility.toggle.toggle import ToggleSwitch
|
||||
|
||||
|
||||
@ -299,6 +297,8 @@ class WidgetHierarchy:
|
||||
"""
|
||||
from bec_widgets.widgets.plots.waveform.waveform import Waveform
|
||||
|
||||
from bec_widgets.utils import BECConnector
|
||||
|
||||
# 1) Filter out widgets that are not BECConnectors (if 'only_bec_widgets' is True)
|
||||
is_bec = isinstance(widget, BECConnector)
|
||||
if only_bec_widgets and not is_bec:
|
||||
|
@ -92,7 +92,6 @@ class Curve(BECConnector, pg.PlotDataItem):
|
||||
else:
|
||||
self.config = config
|
||||
pg.PlotDataItem.__init__(self, parent=parent, name=name)
|
||||
BECConnector.__init__(self, config=config, gui_id=gui_id)
|
||||
|
||||
self.setObjectName(name.replace("-", "_"))
|
||||
self.parent_id = parent_item.config.gui_id
|
||||
@ -103,6 +102,8 @@ class Curve(BECConnector, pg.PlotDataItem):
|
||||
if kwargs:
|
||||
self.set(**kwargs)
|
||||
|
||||
BECConnector.__init__(self, config=config, gui_id=gui_id)
|
||||
|
||||
def parent(self):
|
||||
return self.parent_item
|
||||
|
||||
|
@ -1607,7 +1607,7 @@ class DemoApp(QMainWindow): # pragma: no cover
|
||||
self.waveform_popup = Waveform(popups=True)
|
||||
self.waveform_popup.plot(y_name="monitor_async")
|
||||
|
||||
self.waveform_side = Waveform(popups=False, parent=self.main_widget)
|
||||
self.waveform_side = Waveform(popups=False)
|
||||
self.waveform_side.plot(y_name="bpm4i", y_entry="bpm4i", dap="GaussianModel")
|
||||
self.waveform_side.plot(y_name="bpm3a", y_entry="bpm3a")
|
||||
|
||||
@ -1622,9 +1622,10 @@ class DemoApp(QMainWindow): # pragma: no cover
|
||||
def hierarchy(self):
|
||||
print("getting app")
|
||||
WidgetHierarchy.print_becconnector_hierarchy_from_app() # , only_bec_widgets=True)
|
||||
|
||||
print("getting of side waveform")
|
||||
WidgetHierarchy.print_widget_hierarchy(self.waveform_side, only_bec_widgets=True)
|
||||
print("Waveform popup")
|
||||
print(self.waveform_popup.objectName())
|
||||
print("Waveform side")
|
||||
print(self.waveform_side.objectName())
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
|
Reference in New Issue
Block a user