diff --git a/artiq/frontend/artiq_gui.py b/artiq/frontend/artiq_gui.py index d0c429b70..7607924c7 100755 --- a/artiq/frontend/artiq_gui.py +++ b/artiq/frontend/artiq_gui.py @@ -81,6 +81,7 @@ def main(): win.setStatusBar(status_bar) d_explorer = ExplorerDock(win, status_bar, schedule_ctl) + smgr.register(d_explorer) loop.run_until_complete(d_explorer.sub_connect( args.server, args.port_notify)) atexit.register(lambda: loop.run_until_complete(d_explorer.sub_close())) diff --git a/artiq/gui/explorer.py b/artiq/gui/explorer.py index 5954b87d5..4a4bcfe99 100644 --- a/artiq/gui/explorer.py +++ b/artiq/gui/explorer.py @@ -28,21 +28,27 @@ class _FreeValueEntry(QtGui.QLineEdit): def __init__(self, procdesc): QtGui.QLineEdit.__init__(self) if "default" in procdesc: - self.insert(pyon.encode(procdesc["default"])) + self.set_argument_value(procdesc["default"]) def get_argument_value(self): return pyon.decode(self.text()) + def set_argument_value(self, value): + self.setText(pyon.encode(value)) + class _BooleanEntry(QtGui.QCheckBox): def __init__(self, procdesc): QtGui.QCheckBox.__init__(self) if "default" in procdesc: - self.setChecked(procdesc["default"]) + self.set_argument_value(procdesc["default"]) def get_argument_value(self): return self.isChecked() + def set_argument_value(self, value): + self.setChecked(value) + class _EnumerationEntry(QtGui.QComboBox): def __init__(self, procdesc): @@ -50,16 +56,15 @@ class _EnumerationEntry(QtGui.QComboBox): self.choices = procdesc["choices"] self.addItems(self.choices) if "default" in procdesc: - try: - idx = self.choices.index(procdesc["default"]) - except: - pass - else: - self.setCurrentIndex(idx) + self.set_argument_value(procdesc["default"]) def get_argument_value(self): return self.choices[self.currentIndex()] + def set_argument_value(self, value): + idx = self.choices.index(value) + self.setCurrentIndex(idx) + class _NumberEntry(QtGui.QDoubleSpinBox): def __init__(self, procdesc): @@ -73,21 +78,27 @@ class _NumberEntry(QtGui.QDoubleSpinBox): if procdesc["unit"]: self.setSuffix(" " + procdesc["unit"]) if "default" in procdesc: - force_spinbox_value(self, procdesc["default"]) + self.set_argument_value(procdesc["default"]) def get_argument_value(self): return self.value() + def set_argument_value(self, value): + force_spinbox_value(self, value) + class _StringEntry(QtGui.QLineEdit): def __init__(self, procdesc): QtGui.QLineEdit.__init__(self) if "default" in procdesc: - self.insert(procdesc["default"]) + self.set_argument_value(procdesc["default"]) def get_argument_value(self): return self.text() + def set_argument_value(self, value): + self.setText(value) + _procty_to_entry = { "FreeValue": _FreeValueEntry, @@ -114,21 +125,31 @@ class _ArgumentSetter(LayoutWidget): self.addWidget(entry, n, 1) self._args_to_entries[name] = entry - def get_argument_values(self): + def get_argument_values(self, show_error_message): r = dict() for arg, entry in self._args_to_entries.items(): try: r[arg] = entry.get_argument_value() except: - msgbox = QtGui.QMessageBox(self.dialog_parent) - msgbox.setWindowTitle("Error") - msgbox.setText("Failed to obtain value for argument '{}'.\n{}" - .format(arg, traceback.format_exc())) - msgbox.setStandardButtons(QtGui.QMessageBox.Ok) - msgbox.show() + if show_error_message: + msgbox = QtGui.QMessageBox(self.dialog_parent) + msgbox.setWindowTitle("Error") + msgbox.setText("Failed to obtain value for argument '{}'.\n{}" + .format(arg, traceback.format_exc())) + msgbox.setStandardButtons(QtGui.QMessageBox.Ok) + msgbox.show() return None return r + def set_argument_values(self, arguments, ignore_errors): + for arg, value in arguments.items(): + try: + entry = self._args_to_entries[arg] + entry.set_argument_value(value) + except: + if not ignore_errors: + raise + class ExplorerDock(dockarea.Dock): def __init__(self, dialog_parent, status_bar, schedule_ctl): @@ -163,7 +184,7 @@ class ExplorerDock(dockarea.Dock): grid.addWidget(self.priority, 1, 3) self.pipeline = QtGui.QLineEdit() - self.pipeline.insert("main") + self.pipeline.setText("main") grid.addWidget(QtGui.QLabel("Pipeline:"), 2, 0) grid.addWidget(self.pipeline, 2, 1) @@ -177,8 +198,15 @@ class ExplorerDock(dockarea.Dock): self.argsetter = _ArgumentSetter(self.dialog_parent, []) self.splitter.addWidget(self.argsetter) self.splitter.setSizes([grid.minimumSizeHint().width(), 1000]) + self.state = dict() def update_argsetter(self, selected, deselected): + deselected = deselected.indexes() + if deselected: + row = deselected[0].row() + key = self.explist_model.row_to_key[row] + self.state[key] = self.argsetter.get_argument_values(False) + selected = selected.indexes() if selected: row = selected[0].row() @@ -188,9 +216,24 @@ class ExplorerDock(dockarea.Dock): sizes = self.splitter.sizes() self.argsetter.deleteLater() self.argsetter = _ArgumentSetter(self.dialog_parent, arguments) + if key in self.state: + arguments = self.state[key] + if arguments is not None: + self.argsetter.set_argument_values(arguments, True) self.splitter.insertWidget(1, self.argsetter) self.splitter.setSizes(sizes) + def save_state(self): + idx = self.el.selectedIndexes() + if idx: + row = idx[0].row() + key = self.explist_model.row_to_key[row] + self.state[key] = self.argsetter.get_argument_values(False) + return self.state + + def restore_state(self, state): + self.state = state + def enable_duedate(self): self.datetime_en.setChecked(True) @@ -231,7 +274,7 @@ class ExplorerDock(dockarea.Dock): due_date = self.datetime.dateTime().toMSecsSinceEpoch()/1000 else: due_date = None - arguments = self.argsetter.get_argument_values() + arguments = self.argsetter.get_argument_values(True) if arguments is None: return asyncio.async(self.submit(self.pipeline.text(), diff --git a/artiq/gui/scan.py b/artiq/gui/scan.py index 8c319a925..ee97a1401 100644 --- a/artiq/gui/scan.py +++ b/artiq/gui/scan.py @@ -96,20 +96,7 @@ class ScanController(LayoutWidget): b.toggled.connect(self.select_page) if "default" in procdesc: - d = procdesc["default"] - if d["ty"] == "NoScan": - self.noscan.setChecked(True) - force_spinbox_value(self.v_noscan, d["value"]) - elif d["ty"] == "LinearScan": - self.linear.setChecked(True) - self.v_linear.set_values(d["min"], d["max"], d["npoints"]) - elif d["ty"] == "RandomScan": - self.random.setChecked(True) - self.v_random.set_values(d["min"], d["max"], d["npoints"]) - elif d["ty"] == "ExplicitScan": - self.explicit.setChecked(True) - self.v_explicit.insert(" ".join( - [str(x) for x in d["sequence"]])) + self.set_argument_value(procdesc["default"]) else: self.noscan.setChecked(True) @@ -137,3 +124,20 @@ class ScanController(LayoutWidget): elif self.explicit.isChecked(): sequence = [float(x) for x in self.v_explicit.text().split()] return {"ty": "ExplicitScan", "sequence": sequence} + + def set_argument_value(self, d): + if d["ty"] == "NoScan": + self.noscan.setChecked(True) + force_spinbox_value(self.v_noscan, d["value"]) + elif d["ty"] == "LinearScan": + self.linear.setChecked(True) + self.v_linear.set_values(d["min"], d["max"], d["npoints"]) + elif d["ty"] == "RandomScan": + self.random.setChecked(True) + self.v_random.set_values(d["min"], d["max"], d["npoints"]) + elif d["ty"] == "ExplicitScan": + self.explicit.setChecked(True) + self.v_explicit.insert(" ".join( + [str(x) for x in d["sequence"]])) + else: + raise ValueError("Unknown scan type '{}'".format(d["ty"]))