diff --git a/artiq/dashboard/moninj.py b/artiq/dashboard/moninj.py index 019c3cd5d..40cc919d6 100644 --- a/artiq/dashboard/moninj.py +++ b/artiq/dashboard/moninj.py @@ -9,6 +9,7 @@ from artiq.coredevice.comm_moninj import CommMonInj, TTLOverride, TTLProbe from artiq.coredevice.ad9912_reg import AD9912_SER_CONF from artiq.gui.tools import LayoutWidget from artiq.gui.flowlayout import FlowLayout +from artiq.gui.models import DictSyncTreeSepModel logger = logging.getLogger(__name__) @@ -410,6 +411,58 @@ class _DACHandler: return (self.spi_channel, self.channel) +class Model(DictSyncTreeSepModel): + def __init__(self, init): + DictSyncTreeSepModel.__init__(self, "/", ["Channels"], init) + + def clear(self): + for k in self.backing_store: + self._del_item(self, k.split(self.separator)) + self.backing_store.clear() + + def update(self, d): + for k, v in d.items(): + self[str(k)] = v + + +class _AddChannelDialog(QtWidgets.QDialog): + def __init__(self, parent, model): + QtWidgets.QDialog.__init__(self, parent=parent) + self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) + self.setWindowTitle("Add channels") + + layout = QtWidgets.QVBoxLayout() + self.setLayout(layout) + + self._model = model + self._tree_view = QtWidgets.QTreeView() + self._tree_view.setHeaderHidden(True) + self._tree_view.setSelectionBehavior( + QtWidgets.QAbstractItemView.SelectItems) + self._tree_view.setSelectionMode( + QtWidgets.QAbstractItemView.ExtendedSelection) + self._tree_view.setModel(self._model) + layout.addWidget(self._tree_view) + + self._button_box = QtWidgets.QDialogButtonBox( + QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel + ) + self._button_box.setCenterButtons(True) + self._button_box.accepted.connect(self.add_channels) + self._button_box.rejected.connect(self.reject) + layout.addWidget(self._button_box) + + def add_channels(self): + selection = self._tree_view.selectedIndexes() + channels = [] + for select in selection: + key = self._model.index_to_key(select) + if key is not None: + channels.append(self._model[key].ref) + self.channels = channels + self.accept() + + _HandlerDesc = namedtuple("_HandlerDesc", "uid comment cls arguments") @@ -493,6 +546,7 @@ class _DeviceManager: self.dds_handlers = dict() self.dac_cb = lambda: None self.dac_handlers = dict() + self.channels_cb = lambda: None def init_ddb(self, ddb): self.ddb = ddb @@ -547,6 +601,7 @@ class _DeviceManager: self.ttl_cb() self.dds_cb() self.dac_cb() + self.channels_cb() self.description = description @@ -794,11 +849,14 @@ class _MonInjDock(QtWidgets.QDockWidget): QtWidgets.QDockWidget.DockWidgetFloatable) layout = LayoutWidget() self.setWidget(layout) + self._channel_model = Model({}) + self.add_channel_dialog = _AddChannelDialog(self, self._channel_model) add_channel_btn = QtWidgets.QToolButton() add_channel_btn.setToolTip("Add channels...") add_channel_btn.setIcon( QtWidgets.QApplication.style().standardIcon( QtWidgets.QStyle.SP_FileDialogListView)) + add_channel_btn.clicked.connect(self.add_channel_dialog.open) layout.addWidget(add_channel_btn, 0, 0, colspan=1) scroll_area = QtWidgets.QScrollArea() layout.addWidget(scroll_area, 1, 0, colspan=10) @@ -812,6 +870,9 @@ class _MonInjDock(QtWidgets.QDockWidget): for handler in sorted(handlers, key=lambda h: h.sort_key()): self.grid.addWidget(handler.widget) + def set_channels(self, handlers): + self._channel_model.update(handlers) + class MonInj: def __init__(self, schedule_ctl): @@ -823,6 +884,7 @@ class MonInj: self.dm.ttl_cb = lambda: self.ttl_dock.layout_widgets(self.dm.ttl_handlers.values()) self.dm.dds_cb = lambda: self.dds_dock.layout_widgets(self.dm.dds_handlers.values()) self.dm.dac_cb = lambda: self.dac_dock.layout_widgets(self.dm.dac_handlers.values()) + self.dm.channels_cb = lambda: self.ttl_dock.set_channels(self.dm.handlers_by_uid) async def stop(self): if self.dm is not None: