diff --git a/artiq/dashboard/moninj.py b/artiq/dashboard/moninj.py index 8964448bf..b1c5c64a3 100644 --- a/artiq/dashboard/moninj.py +++ b/artiq/dashboard/moninj.py @@ -72,6 +72,8 @@ class _TTLWidget(QtWidgets.QFrame): self.setFrameShape(QtWidgets.QFrame.Box) self.setFrameShadow(QtWidgets.QFrame.Raised) + self.uid = title + grid = QtWidgets.QGridLayout() grid.setContentsMargins(0, 0, 0, 0) grid.setHorizontalSpacing(0) @@ -213,6 +215,8 @@ class _DDSWidget(QtWidgets.QFrame): self.setFrameShape(QtWidgets.QFrame.Box) self.setFrameShadow(QtWidgets.QFrame.Raised) + self.uid = title + grid = QtWidgets.QGridLayout() grid.setContentsMargins(0, 0, 0, 0) grid.setHorizontalSpacing(0) @@ -407,6 +411,9 @@ class _DACWidget(QtWidgets.QFrame): self.setFrameShape(QtWidgets.QFrame.Box) self.setFrameShadow(QtWidgets.QFrame.Raised) + + self.uid = (title, channel) + grid = QtWidgets.QGridLayout() grid.setContentsMargins(0, 0, 0, 0) grid.setHorizontalSpacing(0) @@ -888,6 +895,7 @@ class _MonInjDock(QDockWidgetCloseDetect): QtWidgets.QDockWidget.DockWidgetFloatable) self.name = name self.manager = manager + self.widget_uids = None grid = LayoutWidget() self.setWidget(grid) self._channel_dialog = _AddChannelDialog(self, self.manager.channel_model) @@ -908,8 +916,8 @@ class _MonInjDock(QDockWidgetCloseDetect): newdock.clicked.connect(lambda: manager.create_new_dock()) grid.addWidget(newdock, 0, 1) - display_name_edit = _DoubleClickLineEdit(name) - grid.addWidget(display_name_edit, 0, 1) + self.display_name_edit = _DoubleClickLineEdit(name) + grid.addWidget(self.display_name_edit, 0, 2) scroll_area = QtWidgets.QScrollArea() grid.addWidget(scroll_area, 1, 0, 1, 10) @@ -927,6 +935,45 @@ class _MonInjDock(QDockWidgetCloseDetect): for handler in sorted(handlers, key=lambda h: h.sort_key()): self.flow.addWidget(handler.widget) + def restore_widgets(self): + if self.widget_uids is not None: + uid2handler = self.manager.dm.handlers_by_uid + handlers = list() + for uid in self.widget_uids: + if uid in uid2handler: + handler = uid2handler[uid] + handler.create_widget() + handlers.append(handler) + else: + logger.warning("removing moninj widget {}".format(uid)) + self.layout_widgets(handlers) + self.widget_uids = None + + def _save_widget_uids(self): + uids = [] + for i in range(self.flow.count()): + uids.append(self.flow.itemAt(i).widget().uid) + return uids + + def save_state(self): + return { + "display_name": self.display_name_edit.text(), + "widget_uids": self._save_widget_uids() + } + + def restore_state(self, state): + try: + display_name = state["display_name"] + except KeyError: + pass + else: + self.display_name_edit._text = display_name + self.display_name_edit.setText(display_name) + try: + self.widget_uids = state["widget_uids"] + except KeyError: + pass + class MonInj: def __init__(self, schedule_ctl, main_window): @@ -940,6 +987,8 @@ class MonInj: def add_channels(self): self.channel_model.clear() self.channel_model.update(self.dm.handlers_by_uid) + for dock in self.docks.values(): + dock.restore_widgets() def create_new_dock(self, add_to_area=True): n = 0 @@ -971,6 +1020,20 @@ class MonInj: for dock in self.docks.values(): dock.setFeatures(flags) + def save_state(self): + return {name: dock.save_state() for name, dock in self.docks.items()} + + def restore_state(self, state): + if self.docks: + raise NotImplementedError + for name, dock_state in state.items(): + dock = _MonInjDock(name, self) + self.docks[name] = dock + dock.restore_state(dock_state) + self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock) + dock.sigClosed.connect(partial(self.on_dock_closed, name)) + self.update_closable() + def first_moninj_dock(self): if self.docks: return None diff --git a/artiq/frontend/artiq_dashboard.py b/artiq/frontend/artiq_dashboard.py index 896efb96c..4faece0dc 100755 --- a/artiq/frontend/artiq_dashboard.py +++ b/artiq/frontend/artiq_dashboard.py @@ -227,6 +227,7 @@ def main(): broadcast_clients["ccb"].notify_cbs.append(d_applets.ccb_notify) moninj_mgr = moninj.MonInj(rpc_clients["schedule"], main_window) + smgr.register(moninj_mgr) atexit_register_coroutine(moninj_mgr.stop, loop=loop) d_waveform = waveform.WaveformDock( @@ -260,9 +261,6 @@ def main(): main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, right_docks[0]) for d1, d2 in zip(right_docks, right_docks[1:]): main_window.tabifyDockWidget(d1, d2) - d_moninj0 = moninj_mgr.first_moninj_dock() - if d_moninj0 is not None: - main_window.tabifyDockWidget(right_docks[-1], d_moninj0) main_window.addDockWidget(QtCore.Qt.BottomDockWidgetArea, d_schedule) # load/initialize state @@ -290,6 +288,9 @@ def main(): d_log0 = logmgr.first_log_dock() if d_log0 is not None: main_window.tabifyDockWidget(d_schedule, d_log0) + d_moninj0 = moninj_mgr.first_moninj_dock() + if d_moninj0 is not None: + main_window.tabifyDockWidget(right_docks[-1], d_moninj0) if server_name is not None: server_description = server_name + " ({})".format(args.server)