From c260c6088872fca4514785eece4f2f2a247d7540 Mon Sep 17 00:00:00 2001 From: John Henry Beale Date: Fri, 16 Oct 2026 13:11:57 +0200 Subject: [PATCH] edit the BS and PV channel lists in a separate dialog The channel lists were one very long line in the preferences tree. They are now buttons ("edit beam-sync channels (N)...") opening a dialog with one channel per line; OK saves the list (empty lines and duplicates removed, space separated pastes work) and forces a new jungfrau object. Co-Authored-By: Claude Opus 5.5 --- app_config.py | 49 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/app_config.py b/app_config.py index 32c8ce9..4113c3d 100644 --- a/app_config.py +++ b/app_config.py @@ -10,7 +10,8 @@ _log = logging.getLogger(__name__) from PyQt5.QtCore import QSettings, QRegularExpression from PyQt5.QtGui import QRegularExpressionValidator -from PyQt5.QtWidgets import QApplication, QMainWindow +from PyQt5.QtWidgets import (QApplication, QMainWindow, QDialog, QDialogButtonBox, QLabel, QPlainTextEdit, + QVBoxLayout) import json,re import numpy as np @@ -539,8 +540,9 @@ verbose bits: {'name':'space_group_number', 'value':daq_uc['space_group_number'], 'type':'int'}, ]}, ]}, - {'name':AppCfg.DAQ_BS_CH, 'title':'list of beam-sync channels','value':' '.join(cfg.value(AppCfg.DAQ_BS_CH)), 'type':'str'}, - {'name':AppCfg.DAQ_PV_CH, 'title':'list of PV channels','value':' '.join(cfg.value(AppCfg.DAQ_PV_CH)), 'type':'str'}, + # the channel lists are edited in a separate dialog (one channel per line) + {'name':AppCfg.DAQ_BS_CH, 'title':self.channels_title(AppCfg.DAQ_BS_CH), 'type':'action'}, + {'name':AppCfg.DAQ_PV_CH, 'title':self.channels_title(AppCfg.DAQ_PV_CH), 'type':'action'}, ]} #{'name':'Save/Restore functionality', 'type':'group','expanded':False, 'children':[ @@ -553,6 +555,8 @@ verbose bits: ] self._p=p=Parameter.create(name='params', type='group', children=params) p.sigTreeStateChanged.connect(lambda a,b: self.cb_change(a,b)) + for k in (AppCfg.DAQ_BS_CH, AppCfg.DAQ_PV_CH): + p.param('data acquisition', k).sigActivated.connect(lambda x, k=k: self.cb_edit_channels(k)) # Too lazy for recursion: for child in p.children(): child.sigValueChanging.connect(lambda a,b: self.cb_valueChanging(a,b)) @@ -674,9 +678,7 @@ verbose bits: elif nm in (AppCfg.DT_HOST): cfg.setValue(nm, param.value()) elif nm in(AppCfg.DAQ_BS_CH,AppCfg.DAQ_PV_CH): - s=param.value() - lst=s.split(' ') if len(s)>0 else () - cfg.setValue(nm,lst) + pass # edited and saved by cb_edit_channels elif par_nm in (AppCfg.GBL_MISC,AppCfg.DT_MISC, AppCfg.GEO_FND_FID,AppCfg.GEO_AUTOFOC, AppCfg.DAQ_UC, AppCfg.DAQ_SAMPLE, AppCfg.DATA_PROC, @@ -710,6 +712,41 @@ verbose bits: raise cfg.sync() + @staticmethod + def channels_title(key): + n=len(QApplication.instance()._cfg.value(key) or ()) + name='beam-sync' if key==AppCfg.DAQ_BS_CH else 'PV' + return f'edit {name} channels ({n})...' + + def cb_edit_channels(self, key): + '''edit a channel list (one channel per line) in a dialog''' + app=QApplication.instance() + cfg=app._cfg + name='beam-sync' if key==AppCfg.DAQ_BS_CH else 'PV' + dlg=QDialog(self) + dlg.setWindowTitle(f'{name} channels') + lay=QVBoxLayout(dlg) + lay.addWidget(QLabel('one channel per line (empty lines and duplicates are ignored)')) + ed=QPlainTextEdit('\n'.join(cfg.value(key) or ())) + ed.setLineWrapMode(QPlainTextEdit.NoWrap) + lay.addWidget(ed) + bb=QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) + bb.accepted.connect(dlg.accept) + bb.rejected.connect(dlg.reject) + lay.addWidget(bb) + dlg.resize(500, 600) + if dlg.exec_()!=QDialog.Accepted: + return + lst=list(dict.fromkeys(ed.toPlainText().split())) + cfg.setValue(key, lst) + cfg.sync() + _log.info(f'{key}: {len(lst)} channels saved') + try: + del app._jungfrau # force a new jungfrau object with the new channels + except AttributeError: + pass + self._p.param('data acquisition', key).setOpts(title=self.channels_title(key)) + def cb_valueChanging(self,param, value): _log.debug(f'Value changing (not finalized): {param}, {value}')