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.protocols import pyon
from artiq.gui.tools import DictSyncModel from artiq.gui.tools import DictSyncModel
from artiq.gui.scan import ScanController from artiq.gui.scan import ScanController
from artiq.gui.shortcuts import ShortcutManager
class _ExplistModel(DictSyncModel): class _ExplistModel(DictSyncModel):
@ -122,14 +123,14 @@ _procty_to_entry = {
class _ArgumentEditor(QtGui.QTreeWidget): class _ArgumentEditor(QtGui.QTreeWidget):
def __init__(self, dialog_parent): def __init__(self, main_window):
QtGui.QTreeWidget.__init__(self) QtGui.QTreeWidget.__init__(self)
self.setColumnCount(2) self.setColumnCount(2)
self.header().setResizeMode(QtGui.QHeaderView.ResizeToContents) self.header().setResizeMode(QtGui.QHeaderView.ResizeToContents)
self.header().setVisible(False) self.header().setVisible(False)
self.setSelectionMode(QtGui.QAbstractItemView.NoSelection) self.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
self.dialog_parent = dialog_parent self.main_window = main_window
self._groups = dict() self._groups = dict()
self.set_arguments([]) self.set_arguments([])
@ -176,7 +177,7 @@ class _ArgumentEditor(QtGui.QTreeWidget):
r[arg] = entry.get_argument_value() r[arg] = entry.get_argument_value()
except Exception as e: except Exception as e:
if show_error_message: if show_error_message:
msgbox = QtGui.QMessageBox(self.dialog_parent) msgbox = QtGui.QMessageBox(self.main_window)
msgbox.setWindowTitle("Error") msgbox.setWindowTitle("Error")
msgbox.setText("Failed to obtain value for argument '{}':\n{}" msgbox.setText("Failed to obtain value for argument '{}':\n{}"
.format(arg, str(e))) .format(arg, str(e)))
@ -215,10 +216,10 @@ class _ArgumentEditor(QtGui.QTreeWidget):
class ExplorerDock(dockarea.Dock): 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)) dockarea.Dock.__init__(self, "Explorer", size=(1500, 500))
self.dialog_parent = dialog_parent self.main_window = main_window
self.status_bar = status_bar self.status_bar = status_bar
self.schedule_ctl = schedule_ctl self.schedule_ctl = schedule_ctl
@ -268,20 +269,27 @@ class ExplorerDock(dockarea.Dock):
grid.addWidget(submit, 4, 0, colspan=4) grid.addWidget(submit, 4, 0, colspan=4)
submit.clicked.connect(self.submit_clicked) 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.addWidget(self.argeditor)
self.splitter.setSizes([grid.minimumSizeHint().width(), 1000]) 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): def update_selection(self, selected, deselected):
if deselected: if deselected:
self.state[deselected] = self.argeditor.save_state() self.argeditor_states[deselected] = self.argeditor.save_state()
if selected: if selected:
expinfo = self.explist_model.backing_store[selected] expinfo = self.explist_model.backing_store[selected]
self.argeditor.set_arguments(expinfo["arguments"]) self.argeditor.set_arguments(expinfo["arguments"])
if selected in self.state: if selected in self.argeditor_states:
self.argeditor.restore_state(self.state[selected]) self.argeditor.restore_state(self.argeditor_states[selected])
self.splitter.insertWidget(1, self.argeditor) self.splitter.insertWidget(1, self.argeditor)
self.selected_key = selected self.selected_key = selected
@ -302,11 +310,20 @@ class ExplorerDock(dockarea.Dock):
if idx: if idx:
row = idx[0].row() row = idx[0].row()
key = self.explist_model.row_to_key[row] key = self.explist_model.row_to_key[row]
self.state[key] = self.argeditor.save_state() self.argeditor_states[key] = self.argeditor.save_state()
return self.state return {
"argeditor": self.argeditor_states,
"shortcuts": self.shortcuts.save_state()
}
def restore_state(self, 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): def enable_duedate(self):
self.datetime_en.setChecked(True) self.datetime_en.setChecked(True)
@ -324,8 +341,8 @@ class ExplorerDock(dockarea.Dock):
self.el.setModel(self.explist_model) self.el.setModel(self.explist_model)
return self.explist_model return self.explist_model
async def submit(self, pipeline_name, file, class_name, arguments, async def submit_task(self, pipeline_name, file, class_name, arguments,
priority, due_date, flush): priority, due_date, flush):
expid = { expid = {
"log_level": getattr(logging, self.log_level.currentText()), "log_level": getattr(logging, self.log_level.currentText()),
"repo_rev": None, "repo_rev": None,
@ -337,20 +354,41 @@ class ExplorerDock(dockarea.Dock):
priority, due_date, flush) priority, due_date, flush)
self.status_bar.showMessage("Submitted RID {}".format(rid)) 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): def submit_clicked(self):
if self.selected_key is not None: if self.selected_key is not None:
expinfo = self.explist_model.backing_store[self.selected_key]
if self.datetime_en.isChecked(): if self.datetime_en.isChecked():
due_date = self.datetime.dateTime().toMSecsSinceEpoch()/1000 due_date = self.datetime.dateTime().toMSecsSinceEpoch()/1000
else: else:
due_date = None due_date = None
arguments = self.argeditor.get_argument_values(True) self.submit(self.pipeline.text(),
if arguments is None: self.selected_key,
return self.priority.value(),
asyncio.ensure_future(self.submit(self.pipeline.text(), due_date,
expinfo["file"], self.flush.isChecked())
expinfo["class_name"],
arguments, def edit_shortcuts(self):
self.priority.value(), experiments = sorted(self.explist_model.backing_store.keys())
due_date, self.shortcuts.edit(experiments)
self.flush.isChecked()))

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