2015-07-14 23:31:18 +08:00
|
|
|
import asyncio
|
2015-07-17 02:52:53 +08:00
|
|
|
from collections import OrderedDict
|
|
|
|
from functools import partial
|
2015-08-01 19:37:16 +08:00
|
|
|
import logging
|
2015-07-14 23:31:18 +08:00
|
|
|
|
|
|
|
from quamash import QtGui, QtCore
|
|
|
|
from pyqtgraph import dockarea
|
|
|
|
from pyqtgraph import LayoutWidget
|
|
|
|
|
|
|
|
from artiq.protocols.sync_struct import Subscriber
|
2015-10-12 18:10:58 +08:00
|
|
|
from artiq.tools import short_format
|
|
|
|
from artiq.gui.tools import DictSyncModel
|
2015-07-17 02:52:53 +08:00
|
|
|
from artiq.gui.displays import *
|
2015-07-14 23:31:18 +08:00
|
|
|
|
2015-10-17 19:11:17 +08:00
|
|
|
try:
|
|
|
|
QSortFilterProxyModel = QtCore.QSortFilterProxyModel
|
|
|
|
except AttributeError:
|
|
|
|
QSortFilterProxyModel = QtGui.QSortFilterProxyModel
|
|
|
|
|
2015-07-14 23:31:18 +08:00
|
|
|
|
2015-08-01 19:37:16 +08:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2015-10-12 17:18:23 +08:00
|
|
|
class DatasetsModel(DictSyncModel):
|
2015-07-14 23:31:18 +08:00
|
|
|
def __init__(self, parent, init):
|
2015-10-12 17:18:23 +08:00
|
|
|
DictSyncModel.__init__(self, ["Dataset", "Persistent", "Value"],
|
2015-07-14 23:31:18 +08:00
|
|
|
parent, init)
|
|
|
|
|
|
|
|
def sort_key(self, k, v):
|
|
|
|
return k
|
|
|
|
|
|
|
|
def convert(self, k, v, column):
|
|
|
|
if column == 0:
|
|
|
|
return k
|
|
|
|
elif column == 1:
|
2015-10-12 17:18:23 +08:00
|
|
|
return "Y" if v[0] else "N"
|
|
|
|
elif column == 2:
|
|
|
|
return short_format(v[1])
|
2015-07-14 23:31:18 +08:00
|
|
|
else:
|
|
|
|
raise ValueError
|
|
|
|
|
|
|
|
|
2015-08-01 19:37:16 +08:00
|
|
|
def _get_display_type_name(display_cls):
|
|
|
|
for name, (_, cls) in display_types.items():
|
|
|
|
if cls is display_cls:
|
|
|
|
return name
|
|
|
|
|
|
|
|
|
2015-10-12 17:18:23 +08:00
|
|
|
class DatasetsDock(dockarea.Dock):
|
2015-07-17 02:52:53 +08:00
|
|
|
def __init__(self, dialog_parent, dock_area):
|
2015-10-12 17:18:23 +08:00
|
|
|
dockarea.Dock.__init__(self, "Datasets", size=(1500, 500))
|
2015-07-17 02:52:53 +08:00
|
|
|
self.dialog_parent = dialog_parent
|
|
|
|
self.dock_area = dock_area
|
2015-07-14 23:31:18 +08:00
|
|
|
|
|
|
|
grid = LayoutWidget()
|
|
|
|
self.addWidget(grid)
|
|
|
|
|
2015-10-12 17:31:55 +08:00
|
|
|
self.search = QtGui.QLineEdit()
|
|
|
|
self.search.setPlaceholderText("search...")
|
|
|
|
self.search.editingFinished.connect(self._search_datasets)
|
2015-10-30 19:58:15 +08:00
|
|
|
grid.addWidget(self.search, 0, 0)
|
2015-10-12 17:31:55 +08:00
|
|
|
|
2015-07-14 23:31:18 +08:00
|
|
|
self.table = QtGui.QTableView()
|
2015-07-15 01:08:08 +08:00
|
|
|
self.table.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
|
2015-07-23 22:36:52 +08:00
|
|
|
self.table.horizontalHeader().setResizeMode(
|
|
|
|
QtGui.QHeaderView.ResizeToContents)
|
2015-10-12 17:31:55 +08:00
|
|
|
grid.addWidget(self.table, 1, 0)
|
2015-07-14 23:31:18 +08:00
|
|
|
|
|
|
|
add_display_box = QtGui.QGroupBox("Add display")
|
2015-10-12 17:31:55 +08:00
|
|
|
grid.addWidget(add_display_box, 1, 1)
|
2015-07-14 23:31:18 +08:00
|
|
|
display_grid = QtGui.QGridLayout()
|
|
|
|
add_display_box.setLayout(display_grid)
|
|
|
|
|
2015-07-17 02:52:53 +08:00
|
|
|
for n, name in enumerate(display_types.keys()):
|
2015-07-14 23:31:18 +08:00
|
|
|
btn = QtGui.QPushButton(name)
|
|
|
|
display_grid.addWidget(btn, n, 0)
|
2015-07-17 02:52:53 +08:00
|
|
|
btn.clicked.connect(partial(self.create_dialog, name))
|
|
|
|
|
|
|
|
self.displays = dict()
|
2015-07-14 23:31:18 +08:00
|
|
|
|
2015-10-12 17:31:55 +08:00
|
|
|
def _search_datasets(self):
|
2015-10-14 19:29:58 +08:00
|
|
|
self.table_model_filter.setFilterFixedString(self.search.displayText())
|
2015-10-12 17:31:55 +08:00
|
|
|
|
2015-10-12 17:18:23 +08:00
|
|
|
def get_dataset(self, key):
|
|
|
|
return self.table_model.backing_store[key][1]
|
2015-07-25 00:36:16 +08:00
|
|
|
|
2015-10-03 19:28:57 +08:00
|
|
|
async def sub_connect(self, host, port):
|
2015-10-12 17:18:23 +08:00
|
|
|
self.subscriber = Subscriber("datasets", self.init_datasets_model,
|
2015-07-17 02:52:53 +08:00
|
|
|
self.on_mod)
|
2015-10-03 19:28:57 +08:00
|
|
|
await self.subscriber.connect(host, port)
|
2015-07-14 23:31:18 +08:00
|
|
|
|
2015-10-03 19:28:57 +08:00
|
|
|
async def sub_close(self):
|
|
|
|
await self.subscriber.close()
|
2015-07-14 23:31:18 +08:00
|
|
|
|
2015-10-12 17:18:23 +08:00
|
|
|
def init_datasets_model(self, init):
|
|
|
|
self.table_model = DatasetsModel(self.table, init)
|
2015-10-17 19:11:17 +08:00
|
|
|
self.table_model_filter = QSortFilterProxyModel()
|
2015-10-14 19:29:58 +08:00
|
|
|
self.table_model_filter.setSourceModel(self.table_model)
|
|
|
|
self.table.setModel(self.table_model_filter)
|
2015-07-17 02:52:53 +08:00
|
|
|
return self.table_model
|
|
|
|
|
2015-10-12 17:18:23 +08:00
|
|
|
def update_display_data(self, dsp):
|
2015-10-24 09:57:42 +08:00
|
|
|
filtered_data = {k: self.table_model.backing_store[k][1]
|
|
|
|
for k in dsp.data_sources()
|
|
|
|
if k in self.table_model.backing_store}
|
|
|
|
dsp.update_data(filtered_data)
|
2015-10-12 17:18:23 +08:00
|
|
|
|
2015-07-17 02:52:53 +08:00
|
|
|
def on_mod(self, mod):
|
|
|
|
if mod["action"] == "init":
|
|
|
|
for display in self.displays.values():
|
|
|
|
display.update_data(self.table_model.backing_store)
|
|
|
|
return
|
|
|
|
|
2015-10-26 00:32:49 +08:00
|
|
|
if mod["path"]:
|
2015-07-17 02:52:53 +08:00
|
|
|
source = mod["path"][0]
|
2015-10-26 00:32:49 +08:00
|
|
|
elif mod["action"] == "setitem":
|
|
|
|
source = mod["key"]
|
2015-07-17 02:52:53 +08:00
|
|
|
else:
|
|
|
|
return
|
|
|
|
|
|
|
|
for display in self.displays.values():
|
|
|
|
if source in display.data_sources():
|
2015-10-12 17:18:23 +08:00
|
|
|
self.update_display_data(display)
|
2015-07-17 02:52:53 +08:00
|
|
|
|
|
|
|
def create_dialog(self, ty):
|
|
|
|
dlg_class = display_types[ty][0]
|
|
|
|
dlg = dlg_class(self.dialog_parent, None, dict(),
|
|
|
|
sorted(self.table_model.backing_store.keys()),
|
|
|
|
partial(self.create_display, ty, None))
|
|
|
|
dlg.open()
|
|
|
|
|
|
|
|
def create_display(self, ty, prev_name, name, settings):
|
|
|
|
if prev_name is not None and prev_name in self.displays:
|
|
|
|
raise NotImplementedError
|
|
|
|
dsp_class = display_types[ty][1]
|
|
|
|
dsp = dsp_class(name, settings)
|
|
|
|
self.displays[name] = dsp
|
2015-10-12 17:18:23 +08:00
|
|
|
self.update_display_data(dsp)
|
2015-07-17 02:52:53 +08:00
|
|
|
|
|
|
|
def on_close():
|
|
|
|
del self.displays[name]
|
|
|
|
dsp.sigClosed.connect(on_close)
|
|
|
|
self.dock_area.addDock(dsp)
|
|
|
|
self.dock_area.floatDock(dsp)
|
2015-08-15 15:29:41 +08:00
|
|
|
return dsp
|
2015-08-01 19:37:16 +08:00
|
|
|
|
|
|
|
def save_state(self):
|
|
|
|
r = dict()
|
|
|
|
for name, display in self.displays.items():
|
|
|
|
r[name] = {
|
|
|
|
"ty": _get_display_type_name(type(display)),
|
2015-08-15 15:29:41 +08:00
|
|
|
"settings": display.settings,
|
|
|
|
"state": display.save_state()
|
2015-08-01 19:37:16 +08:00
|
|
|
}
|
|
|
|
return r
|
|
|
|
|
|
|
|
def restore_state(self, state):
|
|
|
|
for name, desc in state.items():
|
|
|
|
try:
|
2015-08-15 15:29:41 +08:00
|
|
|
dsp = self.create_display(desc["ty"], None, name,
|
|
|
|
desc["settings"])
|
2015-08-01 19:37:16 +08:00
|
|
|
except:
|
|
|
|
logger.warning("Failed to create display '%s'", name,
|
|
|
|
exc_info=True)
|
2015-08-15 15:29:41 +08:00
|
|
|
try:
|
|
|
|
dsp.restore_state(desc["state"])
|
|
|
|
except:
|
|
|
|
logger.warning("Failed to restore display state of '%s'",
|
|
|
|
name, exc_info=True)
|