forked from M-Labs/artiq
gui: basic support for opening files outside repository
This commit is contained in:
parent
238ee9adb4
commit
0da89557da
|
@ -118,10 +118,16 @@ _argty_to_entry = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Experiment URLs come in two forms:
|
||||||
|
# 1. repo:<experiment name>
|
||||||
|
# (file name and class name to be retrieved from explist)
|
||||||
|
# 2. file:<class name>@<file name>
|
||||||
|
|
||||||
|
|
||||||
class _ArgumentEditor(QtGui.QTreeWidget):
|
class _ArgumentEditor(QtGui.QTreeWidget):
|
||||||
def __init__(self, manager, dock, expname):
|
def __init__(self, manager, dock, expurl):
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
self.expname = expname
|
self.expurl = expurl
|
||||||
|
|
||||||
QtGui.QTreeWidget.__init__(self)
|
QtGui.QTreeWidget.__init__(self)
|
||||||
self.setColumnCount(3)
|
self.setColumnCount(3)
|
||||||
|
@ -137,7 +143,7 @@ class _ArgumentEditor(QtGui.QTreeWidget):
|
||||||
self._groups = dict()
|
self._groups = dict()
|
||||||
self._arg_to_entry_widgetitem = dict()
|
self._arg_to_entry_widgetitem = dict()
|
||||||
|
|
||||||
arguments = self.manager.get_submission_arguments(self.expname)
|
arguments = self.manager.get_submission_arguments(self.expurl)
|
||||||
|
|
||||||
if not arguments:
|
if not arguments:
|
||||||
self.addTopLevelItem(QtGui.QTreeWidgetItem(["No arguments"]))
|
self.addTopLevelItem(QtGui.QTreeWidgetItem(["No arguments"]))
|
||||||
|
@ -194,11 +200,11 @@ class _ArgumentEditor(QtGui.QTreeWidget):
|
||||||
|
|
||||||
async def _recompute_argument(self, name):
|
async def _recompute_argument(self, name):
|
||||||
try:
|
try:
|
||||||
arginfo = await self.manager.recompute_arginfo(self.expname)
|
arginfo = await self.manager.compute_arginfo(self.expurl)
|
||||||
except:
|
except:
|
||||||
logger.warning("Could not recompute argument '%s' of '%s'",
|
logger.warning("Could not recompute argument '%s' of '%s'",
|
||||||
name, self.expname, exc_info=True)
|
name, self.expurl, exc_info=True)
|
||||||
argument = self.manager.get_submission_arguments(self.expname)[name]
|
argument = self.manager.get_submission_arguments(self.expurl)[name]
|
||||||
|
|
||||||
procdesc = arginfo[name][0]
|
procdesc = arginfo[name][0]
|
||||||
state = _argty_to_entry[procdesc["ty"]].default_state(procdesc)
|
state = _argty_to_entry[procdesc["ty"]].default_state(procdesc)
|
||||||
|
@ -228,21 +234,21 @@ class _ArgumentEditor(QtGui.QTreeWidget):
|
||||||
|
|
||||||
|
|
||||||
class _ExperimentDock(dockarea.Dock):
|
class _ExperimentDock(dockarea.Dock):
|
||||||
def __init__(self, manager, expname):
|
def __init__(self, manager, expurl):
|
||||||
dockarea.Dock.__init__(self, "Exp: " + expname,
|
dockarea.Dock.__init__(self, "Exp: " + expurl,
|
||||||
closable=True, size=(1500, 500))
|
closable=True, size=(1500, 500))
|
||||||
self.layout.setSpacing(5)
|
self.layout.setSpacing(5)
|
||||||
self.layout.setContentsMargins(5, 5, 5, 5)
|
self.layout.setContentsMargins(5, 5, 5, 5)
|
||||||
|
|
||||||
self.manager = manager
|
self.manager = manager
|
||||||
self.expname = expname
|
self.expurl = expurl
|
||||||
|
|
||||||
self.argeditor = _ArgumentEditor(self.manager, self, self.expname)
|
self.argeditor = _ArgumentEditor(self.manager, self, self.expurl)
|
||||||
self.addWidget(self.argeditor, 0, 0, colspan=5)
|
self.addWidget(self.argeditor, 0, 0, colspan=5)
|
||||||
self.layout.setRowStretch(0, 1)
|
self.layout.setRowStretch(0, 1)
|
||||||
|
|
||||||
scheduling = manager.get_submission_scheduling(expname)
|
scheduling = manager.get_submission_scheduling(expurl)
|
||||||
options = manager.get_submission_options(expname)
|
options = manager.get_submission_options(expurl)
|
||||||
|
|
||||||
datetime = QtGui.QDateTimeEdit()
|
datetime = QtGui.QDateTimeEdit()
|
||||||
datetime.setDisplayFormat("MMM d yyyy hh:mm:ss")
|
datetime.setDisplayFormat("MMM d yyyy hh:mm:ss")
|
||||||
|
@ -312,23 +318,23 @@ class _ExperimentDock(dockarea.Dock):
|
||||||
options["log_level"] = getattr(logging, log_level.currentText())
|
options["log_level"] = getattr(logging, log_level.currentText())
|
||||||
log_level.currentIndexChanged.connect(update_log_level)
|
log_level.currentIndexChanged.connect(update_log_level)
|
||||||
|
|
||||||
repo_rev = QtGui.QLineEdit()
|
if "repo_rev" in options:
|
||||||
repo_rev.setPlaceholderText("current")
|
repo_rev = QtGui.QLineEdit()
|
||||||
repo_rev_label = QtGui.QLabel("Revision:")
|
repo_rev.setPlaceholderText("current")
|
||||||
repo_rev_label.setToolTip("Experiment repository revision "
|
repo_rev_label = QtGui.QLabel("Revision:")
|
||||||
"(commit ID) to use")
|
repo_rev_label.setToolTip("Experiment repository revision "
|
||||||
self.addWidget(repo_rev_label, 3, 2)
|
"(commit ID) to use")
|
||||||
self.addWidget(repo_rev, 3, 3)
|
self.addWidget(repo_rev_label, 3, 2)
|
||||||
|
self.addWidget(repo_rev, 3, 3)
|
||||||
|
|
||||||
if options["repo_rev"] is not None:
|
if options["repo_rev"] is not None:
|
||||||
repo_rev.setText(options["repo_rev"])
|
repo_rev.setText(options["repo_rev"])
|
||||||
def update_repo_rev():
|
def update_repo_rev(text):
|
||||||
t = repo_rev.text()
|
if text:
|
||||||
if t:
|
options["repo_rev"] = text
|
||||||
options["repo_rev"] = t
|
else:
|
||||||
else:
|
options["repo_rev"] = None
|
||||||
options["repo_rev"] = None
|
repo_rev.textEdited.connect(update_repo_rev)
|
||||||
repo_rev.editingFinished.connect(update_repo_rev)
|
|
||||||
|
|
||||||
submit = QtGui.QPushButton("Submit")
|
submit = QtGui.QPushButton("Submit")
|
||||||
submit.setIcon(QtGui.QApplication.style().standardIcon(
|
submit.setIcon(QtGui.QApplication.style().standardIcon(
|
||||||
|
@ -352,35 +358,35 @@ class _ExperimentDock(dockarea.Dock):
|
||||||
|
|
||||||
def submit_clicked(self):
|
def submit_clicked(self):
|
||||||
try:
|
try:
|
||||||
self.manager.submit(self.expname)
|
self.manager.submit(self.expurl)
|
||||||
except:
|
except:
|
||||||
# May happen when experiment has been removed
|
# May happen when experiment has been removed
|
||||||
# from repository/explist
|
# from repository/explist
|
||||||
logger.warning("failed to submit '%s'",
|
logger.warning("failed to submit '%s'",
|
||||||
self.expname, exc_info=True)
|
self.expurl, exc_info=True)
|
||||||
|
|
||||||
def reqterm_clicked(self):
|
def reqterm_clicked(self):
|
||||||
try:
|
try:
|
||||||
self.manager.request_inst_term(self.expname)
|
self.manager.request_inst_term(self.expurl)
|
||||||
except:
|
except:
|
||||||
# May happen when experiment has been removed
|
# May happen when experiment has been removed
|
||||||
# from repository/explist
|
# from repository/explist
|
||||||
logger.warning("failed to request termination of instances of '%s'",
|
logger.warning("failed to request termination of instances of '%s'",
|
||||||
self.expname, exc_info=True)
|
self.expurl, exc_info=True)
|
||||||
|
|
||||||
def _recompute_arguments_clicked(self):
|
def _recompute_arguments_clicked(self):
|
||||||
asyncio.ensure_future(self._recompute_arguments_task())
|
asyncio.ensure_future(self._recompute_arguments_task())
|
||||||
|
|
||||||
async def _recompute_arguments_task(self):
|
async def _recompute_arguments_task(self):
|
||||||
try:
|
try:
|
||||||
arginfo = await self.manager.recompute_arginfo(self.expname)
|
arginfo = await self.manager.compute_arginfo(self.expurl)
|
||||||
except:
|
except:
|
||||||
logger.warning("Could not recompute arguments of '%s'",
|
logger.warning("Could not recompute arguments of '%s'",
|
||||||
self.expname, exc_info=True)
|
self.expurl, exc_info=True)
|
||||||
self.manager.initialize_submission_arguments(self.expname, arginfo)
|
self.manager.initialize_submission_arguments(self.expurl, arginfo)
|
||||||
|
|
||||||
self.argeditor.deleteLater()
|
self.argeditor.deleteLater()
|
||||||
self.argeditor = _ArgumentEditor(self.manager, self, self.expname)
|
self.argeditor = _ArgumentEditor(self.manager, self, self.expurl)
|
||||||
self.addWidget(self.argeditor, 0, 0, colspan=5)
|
self.addWidget(self.argeditor, 0, 0, colspan=5)
|
||||||
|
|
||||||
def save_state(self):
|
def save_state(self):
|
||||||
|
@ -416,9 +422,19 @@ class ExperimentManager:
|
||||||
def set_schedule_model(self, model):
|
def set_schedule_model(self, model):
|
||||||
self.schedule = model.backing_store
|
self.schedule = model.backing_store
|
||||||
|
|
||||||
def get_submission_scheduling(self, expname):
|
def resolve_expurl(self, expurl):
|
||||||
if expname in self.submission_scheduling:
|
if expurl[:5] == "repo:":
|
||||||
return self.submission_scheduling[expname]
|
expinfo = self.explist[expurl[5:]]
|
||||||
|
return expinfo["file"], expinfo["class_name"], True
|
||||||
|
elif expurl[:5] == "file:":
|
||||||
|
class_name, file = expurl[5:].split("@", maxsplit=1)
|
||||||
|
return file, class_name, False
|
||||||
|
else:
|
||||||
|
raise ValueError("Malformed experiment URL")
|
||||||
|
|
||||||
|
def get_submission_scheduling(self, expurl):
|
||||||
|
if expurl in self.submission_scheduling:
|
||||||
|
return self.submission_scheduling[expurl]
|
||||||
else:
|
else:
|
||||||
# mutated by _ExperimentDock
|
# mutated by _ExperimentDock
|
||||||
scheduling = {
|
scheduling = {
|
||||||
|
@ -427,22 +443,23 @@ class ExperimentManager:
|
||||||
"due_date": None,
|
"due_date": None,
|
||||||
"flush": False
|
"flush": False
|
||||||
}
|
}
|
||||||
self.submission_scheduling[expname] = scheduling
|
self.submission_scheduling[expurl] = scheduling
|
||||||
return scheduling
|
return scheduling
|
||||||
|
|
||||||
def get_submission_options(self, expname):
|
def get_submission_options(self, expurl):
|
||||||
if expname in self.submission_options:
|
if expurl in self.submission_options:
|
||||||
return self.submission_options[expname]
|
return self.submission_options[expurl]
|
||||||
else:
|
else:
|
||||||
# mutated by _ExperimentDock
|
# mutated by _ExperimentDock
|
||||||
options = {
|
options = {
|
||||||
"log_level": logging.WARNING,
|
"log_level": logging.WARNING
|
||||||
"repo_rev": None
|
|
||||||
}
|
}
|
||||||
self.submission_options[expname] = options
|
if expurl[:5] == "repo:":
|
||||||
|
options["repo_rev"] = None
|
||||||
|
self.submission_options[expurl] = options
|
||||||
return options
|
return options
|
||||||
|
|
||||||
def initialize_submission_arguments(self, expname, arginfo):
|
def initialize_submission_arguments(self, expurl, arginfo):
|
||||||
arguments = OrderedDict()
|
arguments = OrderedDict()
|
||||||
for name, (procdesc, group) in arginfo.items():
|
for name, (procdesc, group) in arginfo.items():
|
||||||
state = _argty_to_entry[procdesc["ty"]].default_state(procdesc)
|
state = _argty_to_entry[procdesc["ty"]].default_state(procdesc)
|
||||||
|
@ -451,39 +468,42 @@ class ExperimentManager:
|
||||||
"group": group,
|
"group": group,
|
||||||
"state": state # mutated by entries
|
"state": state # mutated by entries
|
||||||
}
|
}
|
||||||
self.submission_arguments[expname] = arguments
|
self.submission_arguments[expurl] = arguments
|
||||||
return arguments
|
return arguments
|
||||||
|
|
||||||
def get_submission_arguments(self, expname):
|
def get_submission_arguments(self, expurl):
|
||||||
if expname in self.submission_arguments:
|
if expurl in self.submission_arguments:
|
||||||
return self.submission_arguments[expname]
|
return self.submission_arguments[expurl]
|
||||||
else:
|
else:
|
||||||
arginfo = self.explist[expname]["arginfo"]
|
if expurl[:5] != "repo:":
|
||||||
arguments = self.initialize_submission_arguments(arginfo)
|
raise ValueError("Submission arguments must be preinitialized "
|
||||||
|
"when not using repository")
|
||||||
|
arginfo = self.explist[expurl[5:]]["arginfo"]
|
||||||
|
arguments = self.initialize_submission_arguments(expurl, arginfo)
|
||||||
return arguments
|
return arguments
|
||||||
|
|
||||||
def open_experiment(self, expname):
|
def open_experiment(self, expurl):
|
||||||
if expname in self.open_experiments:
|
if expurl in self.open_experiments:
|
||||||
return self.open_experiments[expname]
|
return self.open_experiments[expurl]
|
||||||
dock = _ExperimentDock(self, expname)
|
dock = _ExperimentDock(self, expurl)
|
||||||
self.open_experiments[expname] = dock
|
self.open_experiments[expurl] = dock
|
||||||
self.dock_area.addDock(dock)
|
self.dock_area.addDock(dock)
|
||||||
self.dock_area.floatDock(dock)
|
self.dock_area.floatDock(dock)
|
||||||
dock.sigClosed.connect(partial(self.on_dock_closed, expname))
|
dock.sigClosed.connect(partial(self.on_dock_closed, expurl))
|
||||||
return dock
|
return dock
|
||||||
|
|
||||||
def on_dock_closed(self, expname):
|
def on_dock_closed(self, expurl):
|
||||||
del self.open_experiments[expname]
|
del self.open_experiments[expurl]
|
||||||
|
|
||||||
async def _submit_task(self, *args):
|
async def _submit_task(self, *args):
|
||||||
rid = await self.schedule_ctl.submit(*args)
|
rid = await self.schedule_ctl.submit(*args)
|
||||||
self.status_bar.showMessage("Submitted RID {}".format(rid))
|
self.status_bar.showMessage("Submitted RID {}".format(rid))
|
||||||
|
|
||||||
def submit(self, expname):
|
def submit(self, expurl):
|
||||||
expinfo = self.explist[expname]
|
file, class_name, _ = self.resolve_expurl(expurl)
|
||||||
scheduling = self.get_submission_scheduling(expname)
|
scheduling = self.get_submission_scheduling(expurl)
|
||||||
options = self.get_submission_options(expname)
|
options = self.get_submission_options(expurl)
|
||||||
arguments = self.get_submission_arguments(expname)
|
arguments = self.get_submission_arguments(expurl)
|
||||||
|
|
||||||
argument_values = dict()
|
argument_values = dict()
|
||||||
for name, argument in arguments.items():
|
for name, argument in arguments.items():
|
||||||
|
@ -492,11 +512,12 @@ class ExperimentManager:
|
||||||
|
|
||||||
expid = {
|
expid = {
|
||||||
"log_level": options["log_level"],
|
"log_level": options["log_level"],
|
||||||
"repo_rev": options["repo_rev"],
|
"file": file,
|
||||||
"file": expinfo["file"],
|
"class_name": class_name,
|
||||||
"class_name": expinfo["class_name"],
|
|
||||||
"arguments": argument_values,
|
"arguments": argument_values,
|
||||||
}
|
}
|
||||||
|
if "repo_rev" in options:
|
||||||
|
expid["repo_rev"] = options["repo_rev"]
|
||||||
asyncio.ensure_future(self._submit_task(
|
asyncio.ensure_future(self._submit_task(
|
||||||
scheduling["pipeline_name"],
|
scheduling["pipeline_name"],
|
||||||
expid,
|
expid,
|
||||||
|
@ -513,27 +534,41 @@ class ExperimentManager:
|
||||||
logger.debug("failed to request termination of RID %d",
|
logger.debug("failed to request termination of RID %d",
|
||||||
rid, exc_info=True)
|
rid, exc_info=True)
|
||||||
|
|
||||||
def request_inst_term(self, expname):
|
def request_inst_term(self, expurl):
|
||||||
self.status_bar.showMessage("Requesting termination of all instances "
|
self.status_bar.showMessage("Requesting termination of all instances "
|
||||||
"of '{}'".format(expname))
|
"of '{}'".format(expurl))
|
||||||
expinfo = self.explist[expname]
|
file, class_name, use_repository = self.resolve_expurl(expurl)
|
||||||
rids = []
|
rids = []
|
||||||
for rid, desc in self.schedule.items():
|
for rid, desc in self.schedule.items():
|
||||||
expid = desc["expid"]
|
expid = desc["expid"]
|
||||||
if ("repo_rev" in expid # only consider runs from repository
|
if use_repository:
|
||||||
and expid["file"] == expinfo["file"]
|
repo_match = "repo_rev" in expid
|
||||||
and expid["class_name"] == expinfo["class_name"]):
|
else:
|
||||||
|
repo_match = "repo_rev" not in expid
|
||||||
|
if (repo_match
|
||||||
|
and expid["file"] == file
|
||||||
|
and expid["class_name"] == class_name):
|
||||||
rids.append(rid)
|
rids.append(rid)
|
||||||
asyncio.ensure_future(self._request_term_multiple(rids))
|
asyncio.ensure_future(self._request_term_multiple(rids))
|
||||||
|
|
||||||
async def recompute_arginfo(self, expname):
|
async def compute_arginfo(self, expurl):
|
||||||
expinfo = self.explist[expname]
|
file, class_name, use_repository = self.resolve_expurl(expurl)
|
||||||
description = await self.experiment_db_ctl.examine(expinfo["file"])
|
description = await self.experiment_db_ctl.examine(file,
|
||||||
return description[expinfo["class_name"]]["arginfo"]
|
use_repository)
|
||||||
|
return description[class_name]["arginfo"]
|
||||||
|
|
||||||
|
async def open_file(self, file):
|
||||||
|
description = await self.experiment_db_ctl.examine(file, False)
|
||||||
|
for class_name, class_desc in description.items():
|
||||||
|
expurl = "file:{}@{}".format(class_name, file)
|
||||||
|
self.initialize_submission_arguments(expurl, class_desc["arginfo"])
|
||||||
|
if expurl in self.open_experiments:
|
||||||
|
self.open_experiments[expurl].close()
|
||||||
|
self.open_experiment(expurl)
|
||||||
|
|
||||||
def save_state(self):
|
def save_state(self):
|
||||||
docks = {expname: dock.save_state()
|
docks = {expurl: dock.save_state()
|
||||||
for expname, dock in self.open_experiments.items()}
|
for expurl, dock in self.open_experiments.items()}
|
||||||
return {
|
return {
|
||||||
"scheduling": self.submission_scheduling,
|
"scheduling": self.submission_scheduling,
|
||||||
"options": self.submission_options,
|
"options": self.submission_options,
|
||||||
|
@ -547,6 +582,6 @@ class ExperimentManager:
|
||||||
self.submission_scheduling = state["scheduling"]
|
self.submission_scheduling = state["scheduling"]
|
||||||
self.submission_options = state["options"]
|
self.submission_options = state["options"]
|
||||||
self.submission_arguments = state["arguments"]
|
self.submission_arguments = state["arguments"]
|
||||||
for expname, dock_state in state["docks"].items():
|
for expurl, dock_state in state["docks"].items():
|
||||||
dock = self.open_experiment(expname)
|
dock = self.open_experiment(expurl)
|
||||||
dock.restore_state(dock_state)
|
dock.restore_state(dock_state)
|
||||||
|
|
|
@ -9,17 +9,34 @@ from pyqtgraph import LayoutWidget
|
||||||
from artiq.gui.models import DictSyncTreeSepModel
|
from artiq.gui.models import DictSyncTreeSepModel
|
||||||
|
|
||||||
|
|
||||||
|
class _OpenFileDialog(QtGui.QDialog):
|
||||||
|
def __init__(self, parent, exp_manager):
|
||||||
|
QtGui.QDialog.__init__(self, parent=parent)
|
||||||
|
self.setWindowTitle("Open file outside repository")
|
||||||
|
|
||||||
|
grid = QtGui.QGridLayout()
|
||||||
|
self.setLayout(grid)
|
||||||
|
|
||||||
|
grid.addWidget(QtGui.QLabel("Filename:"), 0, 0)
|
||||||
|
filename = QtGui.QLineEdit()
|
||||||
|
grid.addWidget(filename, 0, 1)
|
||||||
|
|
||||||
|
buttons = QtGui.QDialogButtonBox(
|
||||||
|
QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel)
|
||||||
|
grid.addWidget(buttons, 1, 0, 1, 2)
|
||||||
|
buttons.accepted.connect(self.accept)
|
||||||
|
buttons.rejected.connect(self.reject)
|
||||||
|
|
||||||
|
def open_file():
|
||||||
|
file = filename.text()
|
||||||
|
asyncio.ensure_future(exp_manager.open_file(file))
|
||||||
|
self.accepted.connect(open_file)
|
||||||
|
|
||||||
|
|
||||||
class Model(DictSyncTreeSepModel):
|
class Model(DictSyncTreeSepModel):
|
||||||
def __init__(self, init):
|
def __init__(self, init):
|
||||||
self.explorer = None
|
|
||||||
DictSyncTreeSepModel.__init__(self, "/", ["Experiment"], init)
|
DictSyncTreeSepModel.__init__(self, "/", ["Experiment"], init)
|
||||||
|
|
||||||
def __setitem__(self, k, v):
|
|
||||||
DictSyncTreeSepModel.__setitem__(self, k, v)
|
|
||||||
# TODO
|
|
||||||
#if self.explorer is not None and k == self.explorer.selected_key:
|
|
||||||
# self.explorer.update_selection(k, k)
|
|
||||||
|
|
||||||
|
|
||||||
class ExplorerDock(dockarea.Dock):
|
class ExplorerDock(dockarea.Dock):
|
||||||
def __init__(self, status_bar, exp_manager, d_shortcuts,
|
def __init__(self, status_bar, exp_manager, d_shortcuts,
|
||||||
|
@ -37,43 +54,45 @@ class ExplorerDock(dockarea.Dock):
|
||||||
self.el.setHeaderHidden(True)
|
self.el.setHeaderHidden(True)
|
||||||
self.el.setSelectionBehavior(QtGui.QAbstractItemView.SelectItems)
|
self.el.setSelectionBehavior(QtGui.QAbstractItemView.SelectItems)
|
||||||
self.addWidget(self.el, 0, 0, colspan=2)
|
self.addWidget(self.el, 0, 0, colspan=2)
|
||||||
self.el.doubleClicked.connect(self.open_clicked)
|
self.el.doubleClicked.connect(
|
||||||
|
partial(self.expname_action, "open_experiment"))
|
||||||
|
|
||||||
open = QtGui.QPushButton("Open")
|
open = QtGui.QPushButton("Open")
|
||||||
open.setIcon(QtGui.QApplication.style().standardIcon(
|
open.setIcon(QtGui.QApplication.style().standardIcon(
|
||||||
QtGui.QStyle.SP_DialogOpenButton))
|
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(
|
||||||
|
partial(self.expname_action, "open_experiment"))
|
||||||
|
|
||||||
submit = QtGui.QPushButton("Submit")
|
submit = QtGui.QPushButton("Submit")
|
||||||
submit.setIcon(QtGui.QApplication.style().standardIcon(
|
submit.setIcon(QtGui.QApplication.style().standardIcon(
|
||||||
QtGui.QStyle.SP_DialogOkButton))
|
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(
|
||||||
|
partial(self.expname_action, "submit"))
|
||||||
|
|
||||||
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.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)
|
||||||
open_action.triggered.connect(self.open_clicked)
|
open_action.triggered.connect(
|
||||||
|
partial(self.expname_action, "open_experiment"))
|
||||||
open_action.setShortcut("RETURN")
|
open_action.setShortcut("RETURN")
|
||||||
self.el.addAction(open_action)
|
self.el.addAction(open_action)
|
||||||
submit_action = QtGui.QAction("Submit", self.el)
|
submit_action = QtGui.QAction("Submit", self.el)
|
||||||
submit_action.triggered.connect(self.submit_clicked)
|
submit_action.triggered.connect(
|
||||||
|
partial(self.expname_action, "submit"))
|
||||||
submit_action.setShortcut("CTRL+RETURN")
|
submit_action.setShortcut("CTRL+RETURN")
|
||||||
self.el.addAction(submit_action)
|
self.el.addAction(submit_action)
|
||||||
reqterm_action = QtGui.QAction("Request termination of instances", self.el)
|
reqterm_action = QtGui.QAction("Request termination of instances", self.el)
|
||||||
reqterm_action.triggered.connect(self.reqterm_clicked)
|
reqterm_action.triggered.connect(
|
||||||
|
partial(self.expname_action, "request_inst_term"))
|
||||||
reqterm_action.setShortcut("CTRL+BACKSPACE")
|
reqterm_action.setShortcut("CTRL+BACKSPACE")
|
||||||
self.el.addAction(reqterm_action)
|
self.el.addAction(reqterm_action)
|
||||||
|
|
||||||
sep = QtGui.QAction(self.el)
|
|
||||||
sep.setSeparator(True)
|
|
||||||
self.el.addAction(sep)
|
|
||||||
|
|
||||||
set_shortcut_menu = QtGui.QMenu()
|
set_shortcut_menu = QtGui.QMenu()
|
||||||
for i in range(12):
|
for i in range(12):
|
||||||
action = QtGui.QAction("F" + str(i+1), self.el)
|
action = QtGui.QAction("F" + str(i+1), self.el)
|
||||||
|
@ -83,7 +102,12 @@ class ExplorerDock(dockarea.Dock):
|
||||||
set_shortcut_action = QtGui.QAction("Set shortcut", self.el)
|
set_shortcut_action = QtGui.QAction("Set shortcut", self.el)
|
||||||
set_shortcut_action.setMenu(set_shortcut_menu)
|
set_shortcut_action.setMenu(set_shortcut_menu)
|
||||||
self.el.addAction(set_shortcut_action)
|
self.el.addAction(set_shortcut_action)
|
||||||
scan_repository_action = QtGui.QAction("(Re)scan repository HEAD",
|
|
||||||
|
sep = QtGui.QAction(self.el)
|
||||||
|
sep.setSeparator(True)
|
||||||
|
self.el.addAction(sep)
|
||||||
|
|
||||||
|
scan_repository_action = QtGui.QAction("Scan repository HEAD",
|
||||||
self.el)
|
self.el)
|
||||||
def scan_repository():
|
def scan_repository():
|
||||||
asyncio.ensure_future(experiment_db_ctl.scan_repository_async())
|
asyncio.ensure_future(experiment_db_ctl.scan_repository_async())
|
||||||
|
@ -91,8 +115,13 @@ class ExplorerDock(dockarea.Dock):
|
||||||
scan_repository_action.triggered.connect(scan_repository)
|
scan_repository_action.triggered.connect(scan_repository)
|
||||||
self.el.addAction(scan_repository_action)
|
self.el.addAction(scan_repository_action)
|
||||||
|
|
||||||
|
open_file_action = QtGui.QAction("Open file outside repository",
|
||||||
|
self.el)
|
||||||
|
open_file_action.triggered.connect(
|
||||||
|
lambda: _OpenFileDialog(self, self.exp_manager).open())
|
||||||
|
self.el.addAction(open_file_action)
|
||||||
|
|
||||||
def set_model(self, model):
|
def set_model(self, model):
|
||||||
model.explorer = self
|
|
||||||
self.explist_model = model
|
self.explist_model = model
|
||||||
self.el.setModel(model)
|
self.el.setModel(model)
|
||||||
|
|
||||||
|
@ -103,22 +132,16 @@ class ExplorerDock(dockarea.Dock):
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def open_clicked(self):
|
def expname_action(self, action):
|
||||||
expname = self._get_selected_expname()
|
expname = self._get_selected_expname()
|
||||||
if expname is not None:
|
if expname is not None:
|
||||||
self.exp_manager.open_experiment(expname)
|
action = getattr(self.exp_manager, action)
|
||||||
|
action("repo:" + expname)
|
||||||
def submit_clicked(self):
|
|
||||||
expname = self._get_selected_expname()
|
|
||||||
if expname is not None:
|
|
||||||
self.exp_manager.submit(expname)
|
|
||||||
|
|
||||||
def reqterm_clicked(self):
|
|
||||||
expname = self._get_selected_expname()
|
|
||||||
if expname is not None:
|
|
||||||
self.exp_manager.request_inst_term(expname)
|
|
||||||
|
|
||||||
def set_shortcut(self, nr):
|
def set_shortcut(self, nr):
|
||||||
expname = self._get_selected_expname()
|
expname = self._get_selected_expname()
|
||||||
if expname is not None:
|
if expname is not None:
|
||||||
self.d_shortcuts.set_shortcut(nr, expname)
|
expurl = "repo:" + expname
|
||||||
|
self.d_shortcuts.set_shortcut(nr, expurl)
|
||||||
|
self.status_bar.showMessage("Set shortcut F{} to '{}'"
|
||||||
|
.format(nr+1, expurl))
|
||||||
|
|
|
@ -71,31 +71,31 @@ class ShortcutsDock(dockarea.Dock):
|
||||||
shortcut.activated.connect(partial(self._activated, i))
|
shortcut.activated.connect(partial(self._activated, i))
|
||||||
|
|
||||||
def _activated(self, nr):
|
def _activated(self, nr):
|
||||||
expname = self.shortcut_widgets[nr]["label"].text()
|
expurl = self.shortcut_widgets[nr]["label"].text()
|
||||||
if expname:
|
if expurl:
|
||||||
try:
|
try:
|
||||||
self.exp_manager.submit(expname)
|
self.exp_manager.submit(expurl)
|
||||||
except:
|
except:
|
||||||
# May happen when experiment has been removed
|
# May happen when experiment has been removed
|
||||||
# from repository/explist
|
# from repository/explist
|
||||||
logger.warning("failed to submit experiment %s",
|
logger.warning("failed to submit experiment %s",
|
||||||
expname, exc_info=True)
|
expurl, exc_info=True)
|
||||||
|
|
||||||
def _open_experiment(self, nr):
|
def _open_experiment(self, nr):
|
||||||
expname = self.shortcut_widgets[nr]["label"].text()
|
expurl = self.shortcut_widgets[nr]["label"].text()
|
||||||
if expname:
|
if expurl:
|
||||||
try:
|
try:
|
||||||
self.exp_manager.open_experiment(expname)
|
self.exp_manager.open_experiment(expurl)
|
||||||
except:
|
except:
|
||||||
# May happen when experiment has been removed
|
# May happen when experiment has been removed
|
||||||
# from repository/explist
|
# from repository/explist
|
||||||
logger.warning("failed to open experiment %s",
|
logger.warning("failed to open experiment %s",
|
||||||
expname, exc_info=True)
|
expurl, exc_info=True)
|
||||||
|
|
||||||
def set_shortcut(self, nr, expname):
|
def set_shortcut(self, nr, expurl):
|
||||||
widgets = self.shortcut_widgets[nr]
|
widgets = self.shortcut_widgets[nr]
|
||||||
widgets["label"].setText(expname)
|
widgets["label"].setText(expurl)
|
||||||
if expname:
|
if expurl:
|
||||||
widgets["clear"].show()
|
widgets["clear"].show()
|
||||||
widgets["open"].show()
|
widgets["open"].show()
|
||||||
widgets["submit"].show()
|
widgets["submit"].show()
|
||||||
|
@ -109,5 +109,5 @@ class ShortcutsDock(dockarea.Dock):
|
||||||
for nr, widgets in self.shortcut_widgets.items()}
|
for nr, widgets in self.shortcut_widgets.items()}
|
||||||
|
|
||||||
def restore_state(self, state):
|
def restore_state(self, state):
|
||||||
for nr, expname in state.items():
|
for nr, expurl in state.items():
|
||||||
self.set_shortcut(nr, expname)
|
self.set_shortcut(nr, expurl)
|
||||||
|
|
Loading…
Reference in New Issue