mirror of https://github.com/m-labs/artiq.git
gui/shortcuts: integrate with experiment manager
This commit is contained in:
parent
741dfce38c
commit
ff4c03014c
|
@ -13,7 +13,7 @@ from pyqtgraph import dockarea
|
||||||
from artiq.tools import *
|
from artiq.tools import *
|
||||||
from artiq.protocols.pc_rpc import AsyncioClient
|
from artiq.protocols.pc_rpc import AsyncioClient
|
||||||
from artiq.gui.models import ModelSubscriber
|
from artiq.gui.models import ModelSubscriber
|
||||||
from artiq.gui import (state, experiments, explorer,
|
from artiq.gui import (state, experiments, shortcuts, explorer,
|
||||||
moninj, datasets, schedule, log, console)
|
moninj, datasets, schedule, log, console)
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,11 +100,12 @@ def main():
|
||||||
sub_clients["schedule"],
|
sub_clients["schedule"],
|
||||||
rpc_clients["schedule"])
|
rpc_clients["schedule"])
|
||||||
smgr.register(expmgr)
|
smgr.register(expmgr)
|
||||||
d_explorer = explorer.ExplorerDock(win, status_bar, expmgr,
|
d_shortcuts = shortcuts.ShortcutsDock(win, status_bar, expmgr)
|
||||||
|
smgr.register(d_shortcuts)
|
||||||
|
d_explorer = explorer.ExplorerDock(status_bar, expmgr, d_shortcuts,
|
||||||
sub_clients["explist"],
|
sub_clients["explist"],
|
||||||
rpc_clients["schedule"],
|
rpc_clients["schedule"],
|
||||||
rpc_clients["repository"])
|
rpc_clients["repository"])
|
||||||
smgr.register(d_explorer)
|
|
||||||
|
|
||||||
d_datasets = datasets.DatasetsDock(win, dock_area, sub_clients["datasets"])
|
d_datasets = datasets.DatasetsDock(win, dock_area, sub_clients["datasets"])
|
||||||
smgr.register(d_datasets)
|
smgr.register(d_datasets)
|
||||||
|
@ -130,7 +131,8 @@ def main():
|
||||||
dock_area.addDock(d_datasets, "above", d_ttl_dds.ttl_dock)
|
dock_area.addDock(d_datasets, "above", d_ttl_dds.ttl_dock)
|
||||||
else:
|
else:
|
||||||
dock_area.addDock(d_datasets, "top")
|
dock_area.addDock(d_datasets, "top")
|
||||||
dock_area.addDock(d_explorer, "above", d_datasets)
|
dock_area.addDock(d_shortcuts, "above", d_datasets)
|
||||||
|
dock_area.addDock(d_explorer, "above", d_shortcuts)
|
||||||
dock_area.addDock(d_console, "bottom")
|
dock_area.addDock(d_console, "bottom")
|
||||||
dock_area.addDock(d_schedule, "above", d_console)
|
dock_area.addDock(d_schedule, "above", d_console)
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
from quamash import QtGui, QtCore
|
from quamash import QtGui, QtCore
|
||||||
from pyqtgraph import dockarea
|
from pyqtgraph import dockarea
|
||||||
from pyqtgraph import LayoutWidget
|
from pyqtgraph import LayoutWidget
|
||||||
|
|
||||||
from artiq.gui.models import DictSyncTreeSepModel
|
from artiq.gui.models import DictSyncTreeSepModel
|
||||||
from artiq.gui.shortcuts import ShortcutManager
|
|
||||||
|
|
||||||
|
|
||||||
class Model(DictSyncTreeSepModel):
|
class Model(DictSyncTreeSepModel):
|
||||||
|
@ -22,13 +22,15 @@ class Model(DictSyncTreeSepModel):
|
||||||
|
|
||||||
|
|
||||||
class ExplorerDock(dockarea.Dock):
|
class ExplorerDock(dockarea.Dock):
|
||||||
def __init__(self, main_window, status_bar, exp_manager,
|
def __init__(self, status_bar, exp_manager, d_shortcuts,
|
||||||
explist_sub, schedule_ctl, repository_ctl):
|
explist_sub, schedule_ctl, repository_ctl):
|
||||||
dockarea.Dock.__init__(self, "Explorer", size=(1500, 500))
|
dockarea.Dock.__init__(self, "Explorer", size=(1500, 500))
|
||||||
|
self.layout.setSpacing(5)
|
||||||
|
self.layout.setContentsMargins(5, 5, 5, 5)
|
||||||
|
|
||||||
self.main_window = main_window
|
|
||||||
self.status_bar = status_bar
|
self.status_bar = status_bar
|
||||||
self.exp_manager = exp_manager
|
self.exp_manager = exp_manager
|
||||||
|
self.d_shortcuts = d_shortcuts
|
||||||
self.schedule_ctl = schedule_ctl
|
self.schedule_ctl = schedule_ctl
|
||||||
|
|
||||||
self.el = QtGui.QTreeView()
|
self.el = QtGui.QTreeView()
|
||||||
|
@ -38,18 +40,21 @@ class ExplorerDock(dockarea.Dock):
|
||||||
self.el.doubleClicked.connect(self.open_clicked)
|
self.el.doubleClicked.connect(self.open_clicked)
|
||||||
|
|
||||||
open = QtGui.QPushButton("Open")
|
open = QtGui.QPushButton("Open")
|
||||||
|
open.setIcon(QtGui.QApplication.style().standardIcon(
|
||||||
|
QtGui.QStyle.SP_DialogOpenButton))
|
||||||
open.setToolTip("Open the selected experiment (Return)")
|
open.setToolTip("Open the selected experiment (Return)")
|
||||||
self.addWidget(open, 1, 0)
|
self.addWidget(open, 1, 0)
|
||||||
open.clicked.connect(self.open_clicked)
|
open.clicked.connect(self.open_clicked)
|
||||||
|
|
||||||
submit = QtGui.QPushButton("Submit")
|
submit = QtGui.QPushButton("Submit")
|
||||||
|
submit.setIcon(QtGui.QApplication.style().standardIcon(
|
||||||
|
QtGui.QStyle.SP_DialogOkButton))
|
||||||
submit.setToolTip("Schedule the selected experiment (Ctrl+Return)")
|
submit.setToolTip("Schedule the selected experiment (Ctrl+Return)")
|
||||||
self.addWidget(submit, 1, 1)
|
self.addWidget(submit, 1, 1)
|
||||||
submit.clicked.connect(self.submit_clicked)
|
submit.clicked.connect(self.submit_clicked)
|
||||||
|
|
||||||
self.explist_model = Model(dict())
|
self.explist_model = Model(dict())
|
||||||
explist_sub.add_setmodel_callback(self.set_model)
|
explist_sub.add_setmodel_callback(self.set_model)
|
||||||
self.shortcuts = ShortcutManager(self.main_window, self)
|
|
||||||
|
|
||||||
self.el.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
|
self.el.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
|
||||||
open_action = QtGui.QAction("Open", self.el)
|
open_action = QtGui.QAction("Open", self.el)
|
||||||
|
@ -69,9 +74,15 @@ class ExplorerDock(dockarea.Dock):
|
||||||
sep.setSeparator(True)
|
sep.setSeparator(True)
|
||||||
self.el.addAction(sep)
|
self.el.addAction(sep)
|
||||||
|
|
||||||
edit_shortcuts_action = QtGui.QAction("Edit shortcuts", self.el)
|
set_shortcut_menu = QtGui.QMenu()
|
||||||
edit_shortcuts_action.triggered.connect(self.edit_shortcuts)
|
for i in range(12):
|
||||||
self.el.addAction(edit_shortcuts_action)
|
action = QtGui.QAction("F" + str(i+1), self.el)
|
||||||
|
action.triggered.connect(partial(self.set_shortcut, i))
|
||||||
|
set_shortcut_menu.addAction(action)
|
||||||
|
|
||||||
|
set_shortcut_action = QtGui.QAction("Set shortcut", self.el)
|
||||||
|
set_shortcut_action.setMenu(set_shortcut_menu)
|
||||||
|
self.el.addAction(set_shortcut_action)
|
||||||
scan_repository_action = QtGui.QAction("(Re)scan repository HEAD",
|
scan_repository_action = QtGui.QAction("(Re)scan repository HEAD",
|
||||||
self.el)
|
self.el)
|
||||||
def scan_repository():
|
def scan_repository():
|
||||||
|
@ -107,18 +118,7 @@ class ExplorerDock(dockarea.Dock):
|
||||||
if expname is not None:
|
if expname is not None:
|
||||||
self.exp_manager.request_inst_term(expname)
|
self.exp_manager.request_inst_term(expname)
|
||||||
|
|
||||||
def save_state(self):
|
def set_shortcut(self, nr):
|
||||||
return {
|
expname = self._get_selected_expname()
|
||||||
"shortcuts": self.shortcuts.save_state()
|
if expname is not None:
|
||||||
}
|
self.d_shortcuts.set_shortcut(nr, expname)
|
||||||
|
|
||||||
def restore_state(self, state):
|
|
||||||
try:
|
|
||||||
shortcuts_state = state["shortcuts"]
|
|
||||||
except KeyError:
|
|
||||||
return
|
|
||||||
self.shortcuts.restore_state(shortcuts_state)
|
|
||||||
|
|
||||||
def edit_shortcuts(self):
|
|
||||||
experiments = sorted(self.explist_model.backing_store.keys())
|
|
||||||
self.shortcuts.edit(experiments)
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
import logging
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from quamash import QtGui
|
from quamash import QtGui
|
||||||
|
from pyqtgraph import dockarea
|
||||||
try:
|
try:
|
||||||
from quamash import QtWidgets
|
from quamash import QtWidgets
|
||||||
QShortcut = QtWidgets.QShortcut
|
QShortcut = QtWidgets.QShortcut
|
||||||
|
@ -8,91 +10,82 @@ except:
|
||||||
QShortcut = QtGui.QShortcut
|
QShortcut = QtGui.QShortcut
|
||||||
|
|
||||||
|
|
||||||
class _ShortcutEditor(QtGui.QDialog):
|
logger = logging.getLogger(__name__)
|
||||||
def __init__(self, parent, experiments, shortcuts):
|
|
||||||
QtGui.QDialog.__init__(self, parent=parent)
|
|
||||||
self.setWindowTitle("Shortcuts")
|
|
||||||
|
|
||||||
self.shortcuts = shortcuts
|
|
||||||
self.edit_widgets = dict()
|
|
||||||
|
|
||||||
grid = QtGui.QGridLayout()
|
class ShortcutsDock(dockarea.Dock):
|
||||||
self.setLayout(grid)
|
def __init__(self, main_window, status_bar, exp_manager):
|
||||||
|
dockarea.Dock.__init__(self, "Shortcuts", size=(1000, 300))
|
||||||
|
self.layout.setSpacing(5)
|
||||||
|
self.layout.setContentsMargins(5, 5, 5, 5)
|
||||||
|
|
||||||
for n, title in enumerate(["Key", "Experiment", "Priority", "Pipeline"]):
|
self.status_bar = status_bar
|
||||||
label = QtGui.QLabel("<b>" + title + "</b")
|
self.exp_manager = exp_manager
|
||||||
grid.addWidget(label, 0, n)
|
self.shortcut_widgets = dict()
|
||||||
|
|
||||||
|
for n, title in enumerate(["Key", "Experiment"]):
|
||||||
|
label = QtGui.QLabel("<b>" + title + "</b>")
|
||||||
|
self.addWidget(label, 0, n)
|
||||||
label.setMaximumHeight(label.sizeHint().height())
|
label.setMaximumHeight(label.sizeHint().height())
|
||||||
grid.setColumnStretch(1, 1)
|
self.layout.setColumnStretch(1, 1)
|
||||||
grid.setColumnStretch(3, 1)
|
|
||||||
|
|
||||||
for i in range(12):
|
for i in range(12):
|
||||||
row = i + 1
|
row = i + 1
|
||||||
existing_shortcut = self.shortcuts.get(i, dict())
|
|
||||||
|
|
||||||
grid.addWidget(QtGui.QLabel("F" + str(i+1)), row, 0)
|
self.addWidget(QtGui.QLabel("F" + str(i+1)), row, 0)
|
||||||
|
|
||||||
experiment = QtGui.QComboBox()
|
label = QtGui.QLabel()
|
||||||
grid.addWidget(experiment, row, 1)
|
self.addWidget(label, row, 1)
|
||||||
experiment.addItem("<None>")
|
|
||||||
experiment.addItems(experiments)
|
|
||||||
experiment.setEditable(True)
|
|
||||||
experiment.setEditText(
|
|
||||||
existing_shortcut.get("experiment", "<None>"))
|
|
||||||
|
|
||||||
priority = QtGui.QSpinBox()
|
clear = QtGui.QToolButton()
|
||||||
grid.addWidget(priority, row, 2)
|
clear.setIcon(QtGui.QApplication.style().standardIcon(
|
||||||
priority.setRange(-99, 99)
|
QtGui.QStyle.SP_DialogResetButton))
|
||||||
priority.setValue(existing_shortcut.get("priority", 0))
|
self.addWidget(clear, row, 2)
|
||||||
|
clear.clicked.connect(partial(self.set_shortcut, i, ""))
|
||||||
|
|
||||||
pipeline = QtGui.QLineEdit()
|
submit = QtGui.QPushButton("Submit")
|
||||||
grid.addWidget(pipeline, row, 3)
|
submit.setIcon(QtGui.QApplication.style().standardIcon(
|
||||||
pipeline.setText(existing_shortcut.get("pipeline", "main"))
|
QtGui.QStyle.SP_DialogOkButton))
|
||||||
|
self.addWidget(submit, row, 3)
|
||||||
|
submit.clicked.connect(partial(self._activated, i))
|
||||||
|
|
||||||
self.edit_widgets[i] = {
|
self.shortcut_widgets[i] = {
|
||||||
"experiment": experiment,
|
"label": label,
|
||||||
"priority": priority,
|
"clear": clear,
|
||||||
"pipeline": pipeline
|
"submit": submit
|
||||||
}
|
}
|
||||||
|
|
||||||
buttons = QtGui.QDialogButtonBox(
|
|
||||||
QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel)
|
|
||||||
grid.addWidget(buttons, 14, 0, 1, 4)
|
|
||||||
buttons.accepted.connect(self.accept)
|
|
||||||
buttons.rejected.connect(self.reject)
|
|
||||||
self.accepted.connect(self.on_accept)
|
|
||||||
|
|
||||||
def on_accept(self):
|
|
||||||
for n, widgets in self.edit_widgets.items():
|
|
||||||
self.shortcuts[n] = {
|
|
||||||
"experiment": widgets["experiment"].currentText(),
|
|
||||||
"priority": widgets["priority"].value(),
|
|
||||||
"pipeline": widgets["pipeline"].text()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class ShortcutManager:
|
|
||||||
def __init__(self, main_window, explorer):
|
|
||||||
for i in range(12):
|
|
||||||
shortcut = QShortcut("F" + str(i+1), main_window)
|
shortcut = QShortcut("F" + str(i+1), main_window)
|
||||||
shortcut.activated.connect(partial(self._activated, i))
|
shortcut.activated.connect(partial(self._activated, i))
|
||||||
self.main_window = main_window
|
|
||||||
self.explorer = explorer
|
|
||||||
self.shortcuts = dict()
|
|
||||||
|
|
||||||
def edit(self, experiments):
|
|
||||||
dlg = _ShortcutEditor(self.main_window, experiments, self.shortcuts)
|
|
||||||
dlg.open()
|
|
||||||
|
|
||||||
def _activated(self, nr):
|
def _activated(self, nr):
|
||||||
info = self.shortcuts.get(nr, dict())
|
expname = self.shortcut_widgets[nr]["label"].text()
|
||||||
experiment = info.get("experiment", "")
|
if expname:
|
||||||
if experiment and experiment != "<None>":
|
try:
|
||||||
self.explorer.submit(info["pipeline"], experiment,
|
rid = self.exp_manager.submit(expname)
|
||||||
info["priority"], None, False)
|
except:
|
||||||
|
self.status_bar.showMessage("Could not submit experiment '{}'"
|
||||||
|
.format(expname))
|
||||||
|
logger.warning("failed to submit experiment %s",
|
||||||
|
expname, exc_info=True)
|
||||||
|
else:
|
||||||
|
self.status_bar.showMessage("Submitted RID {} "
|
||||||
|
"(from global shortcut)"
|
||||||
|
.format(rid))
|
||||||
|
|
||||||
|
def set_shortcut(self, nr, expname):
|
||||||
|
widgets = self.shortcut_widgets[nr]
|
||||||
|
widgets["label"].setText(expname)
|
||||||
|
if expname:
|
||||||
|
widgets["clear"].show()
|
||||||
|
widgets["submit"].show()
|
||||||
|
else:
|
||||||
|
widgets["clear"].hide()
|
||||||
|
widgets["submit"].hide()
|
||||||
|
|
||||||
def save_state(self):
|
def save_state(self):
|
||||||
return self.shortcuts
|
return {nr: widgets["label"].text()
|
||||||
|
for nr, widgets in self.shortcut_widgets.items()}
|
||||||
|
|
||||||
def restore_state(self, state):
|
def restore_state(self, state):
|
||||||
self.shortcuts = state
|
for nr, expname in state.items():
|
||||||
|
self.set_shortcut(nr, expname)
|
||||||
|
|
Loading…
Reference in New Issue