gui: shortcut support

This commit is contained in:
Sebastien Bourdeauducq 2015-10-27 17:59:34 +08:00
parent 9f2ff32948
commit 967d4eda63
2 changed files with 162 additions and 26 deletions

View File

@ -9,6 +9,7 @@ from artiq.protocols.sync_struct import Subscriber
from artiq.protocols import pyon
from artiq.gui.tools import DictSyncModel
from artiq.gui.scan import ScanController
from artiq.gui.shortcuts import ShortcutManager
class _ExplistModel(DictSyncModel):
@ -122,14 +123,14 @@ _procty_to_entry = {
class _ArgumentEditor(QtGui.QTreeWidget):
def __init__(self, dialog_parent):
def __init__(self, main_window):
QtGui.QTreeWidget.__init__(self)
self.setColumnCount(2)
self.header().setResizeMode(QtGui.QHeaderView.ResizeToContents)
self.header().setVisible(False)
self.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
self.dialog_parent = dialog_parent
self.main_window = main_window
self._groups = dict()
self.set_arguments([])
@ -176,7 +177,7 @@ class _ArgumentEditor(QtGui.QTreeWidget):
r[arg] = entry.get_argument_value()
except Exception as e:
if show_error_message:
msgbox = QtGui.QMessageBox(self.dialog_parent)
msgbox = QtGui.QMessageBox(self.main_window)
msgbox.setWindowTitle("Error")
msgbox.setText("Failed to obtain value for argument '{}':\n{}"
.format(arg, str(e)))
@ -215,10 +216,10 @@ class _ArgumentEditor(QtGui.QTreeWidget):
class ExplorerDock(dockarea.Dock):
def __init__(self, dialog_parent, status_bar, schedule_ctl):
def __init__(self, main_window, status_bar, schedule_ctl):
dockarea.Dock.__init__(self, "Explorer", size=(1500, 500))
self.dialog_parent = dialog_parent
self.main_window = main_window
self.status_bar = status_bar
self.schedule_ctl = schedule_ctl
@ -268,20 +269,27 @@ class ExplorerDock(dockarea.Dock):
grid.addWidget(submit, 4, 0, colspan=4)
submit.clicked.connect(self.submit_clicked)
self.argeditor = _ArgumentEditor(self.dialog_parent)
self.argeditor = _ArgumentEditor(self.main_window)
self.splitter.addWidget(self.argeditor)
self.splitter.setSizes([grid.minimumSizeHint().width(), 1000])
self.state = dict()
self.argeditor_states = dict()
self.shortcuts = ShortcutManager(self.main_window, self)
self.el.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
edit_shortcuts_action = QtGui.QAction("Edit shortcuts", self.el)
edit_shortcuts_action.triggered.connect(self.edit_shortcuts)
self.el.addAction(edit_shortcuts_action)
def update_selection(self, selected, deselected):
if deselected:
self.state[deselected] = self.argeditor.save_state()
self.argeditor_states[deselected] = self.argeditor.save_state()
if selected:
expinfo = self.explist_model.backing_store[selected]
self.argeditor.set_arguments(expinfo["arguments"])
if selected in self.state:
self.argeditor.restore_state(self.state[selected])
if selected in self.argeditor_states:
self.argeditor.restore_state(self.argeditor_states[selected])
self.splitter.insertWidget(1, self.argeditor)
self.selected_key = selected
@ -302,11 +310,20 @@ class ExplorerDock(dockarea.Dock):
if idx:
row = idx[0].row()
key = self.explist_model.row_to_key[row]
self.state[key] = self.argeditor.save_state()
return self.state
self.argeditor_states[key] = self.argeditor.save_state()
return {
"argeditor": self.argeditor_states,
"shortcuts": self.shortcuts.save_state()
}
def restore_state(self, state):
self.state = state
try:
argeditor_states = state["argeditor"]
shortcuts_state = state["shortcuts"]
except KeyError:
return
self.argeditor_states = argeditor_states
self.shortcuts.restore_state(shortcuts_state)
def enable_duedate(self):
self.datetime_en.setChecked(True)
@ -324,8 +341,8 @@ class ExplorerDock(dockarea.Dock):
self.el.setModel(self.explist_model)
return self.explist_model
async def submit(self, pipeline_name, file, class_name, arguments,
priority, due_date, flush):
async def submit_task(self, pipeline_name, file, class_name, arguments,
priority, due_date, flush):
expid = {
"log_level": getattr(logging, self.log_level.currentText()),
"repo_rev": None,
@ -337,20 +354,41 @@ class ExplorerDock(dockarea.Dock):
priority, due_date, flush)
self.status_bar.showMessage("Submitted RID {}".format(rid))
def submit(self, pipeline, key, priority, due_date, flush):
# TODO: refactor explorer and cleanup.
# Argument editors should immediately modify the global state.
expinfo = self.explist_model.backing_store[key]
if key == self.selected_key:
arguments = self.argeditor.get_argument_values(True)
if arguments is None:
# There has been an error. Displaying the error message box
# was done by argeditor.
return
else:
try:
arguments = self.argeditor_states[key]["argument_values"]
except KeyError:
arguments = dict()
asyncio.ensure_future(self.submit_task(self.pipeline.text(),
expinfo["file"],
expinfo["class_name"],
arguments,
priority,
due_date,
flush))
def submit_clicked(self):
if self.selected_key is not None:
expinfo = self.explist_model.backing_store[self.selected_key]
if self.datetime_en.isChecked():
due_date = self.datetime.dateTime().toMSecsSinceEpoch()/1000
else:
due_date = None
arguments = self.argeditor.get_argument_values(True)
if arguments is None:
return
asyncio.ensure_future(self.submit(self.pipeline.text(),
expinfo["file"],
expinfo["class_name"],
arguments,
self.priority.value(),
due_date,
self.flush.isChecked()))
self.submit(self.pipeline.text(),
self.selected_key,
self.priority.value(),
due_date,
self.flush.isChecked())
def edit_shortcuts(self):
experiments = sorted(self.explist_model.backing_store.keys())
self.shortcuts.edit(experiments)

98
artiq/gui/shortcuts.py Normal file
View File

@ -0,0 +1,98 @@
from functools import partial
from quamash import QtGui
try:
from quamash import QtWidgets
QShortcut = QtWidgets.QShortcut
except:
QShortcut = QtGui.QShortcut
class _ShortcutEditor(QtGui.QDialog):
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()
self.setLayout(grid)
for n, title in enumerate(["Key", "Experiment", "Priority", "Pipeline"]):
label = QtGui.QLabel("<b>" + title + "</b")
grid.addWidget(label, 0, n)
label.setMaximumHeight(label.sizeHint().height())
grid.setColumnStretch(1, 1)
grid.setColumnStretch(3, 1)
for i in range(12):
row = i + 1
existing_shortcut = self.shortcuts.get(i, dict())
grid.addWidget(QtGui.QLabel("F" + str(i+1)), row, 0)
experiment = QtGui.QComboBox()
grid.addWidget(experiment, row, 1)
experiment.addItem("<None>")
experiment.addItems(experiments)
experiment.setEditable(True)
experiment.setEditText(
existing_shortcut.get("experiment", "<None>"))
priority = QtGui.QSpinBox()
grid.addWidget(priority, row, 2)
priority.setRange(-99, 99)
priority.setValue(existing_shortcut.get("priority", 0))
pipeline = QtGui.QLineEdit()
grid.addWidget(pipeline, row, 3)
pipeline.setText(existing_shortcut.get("pipeline", "main"))
self.edit_widgets[i] = {
"experiment": experiment,
"priority": priority,
"pipeline": pipeline
}
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.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):
info = self.shortcuts.get(nr, dict())
experiment = info.get("experiment", "")
if experiment and experiment != "<None>":
self.explorer.submit(info["pipeline"], experiment,
info["priority"], None, False)
def save_state(self):
return self.shortcuts
def restore_state(self, state):
self.shortcuts = state