forked from M-Labs/artiq
1
0
Fork 0
artiq/artiq/dashboard/interactive_args.py

152 lines
5.4 KiB
Python

import logging
import asyncio
from PyQt5 import QtCore, QtWidgets, QtGui
from artiq.tools import elide
from artiq.gui.tools import LayoutWidget
from artiq.gui.models import DictSyncModel
from artiq.gui.applets import EntryArea
logger = logging.getLogger(__name__)
class Model(DictSyncModel):
def __init__(self, init):
DictSyncModel.__init__(self, ["RID", "Title", "Args"], init)
def convert(self, k, v, column):
if column == 0:
return k
elif column == 1:
txt = ":" + v["title"] if v["title"] != "" else ""
return str(k) + txt
elif column == 2:
return v["arglist_desc"]
else:
raise ValueError
def sort_key(self, k, v):
return k
class _InteractiveArgsRequest(QtWidgets.QWidget):
supplied = QtCore.pyqtSignal(int, dict)
cancelled = QtCore.pyqtSignal(int)
def __init__(self, rid, title, arglist_desc):
QtWidgets.QWidget.__init__(self)
self.rid = rid
layout = QtWidgets.QGridLayout()
self.setLayout(layout)
title_txt = title if title != "" else str(self.rid)
self.title_lbl = QtWidgets.QLabel(title_txt)
layout.addWidget(self.title_lbl, 0, 0, 1, 2)
self.entry_area = EntryArea()
layout.addWidget(self.entry_area, 1, 0, 1, 2)
for args in arglist_desc:
self.entry_area.setattr_argument_procdesc(*args)
self.cancel_btn = QtWidgets.QPushButton("Cancel")
self.cancel_btn.setIcon(QtWidgets.QApplication.style().standardIcon(
QtWidgets.QStyle.SP_DialogCancelButton))
self.cancel_btn.clicked.connect(self.cancel)
layout.addWidget(self.cancel_btn, 2, 0, 1, 1)
self.supply_btn = QtWidgets.QPushButton("Supply")
self.supply_btn.setIcon(QtWidgets.QApplication.style().standardIcon(
QtWidgets.QStyle.SP_DialogOkButton))
self.supply_btn.clicked.connect(self.supply)
layout.addWidget(self.supply_btn, 2, 1, 1, 1)
def supply(self):
self.supplied.emit(self.rid, self.entry_area.get_values())
def cancel(self):
self.cancelled.emit(self.rid)
class _InteractiveArgsView(QtWidgets.QTabWidget):
supplied = QtCore.pyqtSignal(int, dict)
cancelled = QtCore.pyqtSignal(int)
def __init__(self):
QtWidgets.QTabWidget.__init__(self)
self.model = Model({})
def setModel(self, model):
for i in range(self.count()):
widget = self.widget(i)
self.removeTab(i)
widget.deleteLater()
self.model = model
self.model.dataChanged.connect(self.dataChanged)
self.model.rowsInserted.connect(self.rowsInserted)
self.model.rowsMoved.connect(self.rowsMoved)
self.model.rowsRemoved.connect(self.rowsRemoved)
for i in range(self.model.rowCount(QtCore.QModelIndex())):
self._insert_widget(i)
def _insert_widget(self, row):
rid = self.model.data(self.model.index(row, 0), QtCore.Qt.DisplayRole)
title = self.model.data(self.model.index(row, 1), QtCore.Qt.DisplayRole)
arglist_desc = self.model.data(self.model.index(row, 2), QtCore.Qt.DisplayRole)
inter_args_request = _InteractiveArgsRequest(rid, title, arglist_desc)
inter_args_request.supplied.connect(self.supplied)
inter_args_request.cancelled.connect(self.cancelled)
self.insertTab(row, inter_args_request, title)
def dataChanged(self, top_left, bottom_right, roles):
row = top_left.row()
widget = self.widget(row)
self.removeTab(row)
self._insert_widget(row)
widget.deleteLater()
def rowsInserted(self, parent, first, last):
self._insert_widget(first)
def rowsMoved(self, src_parent, src_start, src_end, dest_parent, dest_end):
widget = self.widget(src_start)
self.insertTab(dest_end, widget)
def rowsRemoved(self, parent, first, last):
widget = self.widget(first)
self.removeTab(first)
widget.deleteLater()
class InteractiveArgsDock(QtWidgets.QDockWidget):
def __init__(self, interactive_args_sub, interactive_args_rpc):
QtWidgets.QDockWidget.__init__(self, "Interactive Args")
self.setObjectName("Interactive Args")
self.setFeatures(
QtWidgets.QDockWidget.DockWidgetMovable | QtWidgets.QDockWidget.DockWidgetFloatable)
self.interactive_args_rpc = interactive_args_rpc
layout = LayoutWidget(self)
self.setWidget(layout)
self.request_view = _InteractiveArgsView()
self.request_view.supplied.connect(self.supply)
self.request_view.cancelled.connect(self.cancel)
layout.addWidget(self.request_view, 0, 0)
interactive_args_sub.add_setmodel_callback(self.request_view.setModel)
def supply(self, rid, values):
asyncio.ensure_future(self._supply_task(rid, values))
async def _supply_task(self, rid, values):
try:
await self.interactive_args_rpc.supply(rid, values)
except:
logger.error("dashboard failed to supply interactive arguments for experiment: %d",
rid, exc_info=True)
def cancel(self, rid):
asyncio.ensure_future(self._cancel_task(rid))
async def _cancel_task(self, rid):
try:
await self.interactive_args_rpc.cancel(rid)
except:
logger.error("dashboard failed to cancel input request for experiment: %d",
rid, exc_info=True)