forked from M-Labs/artiq
1
0
Fork 0
artiq/artiq/browser/files.py

190 lines
6.3 KiB
Python
Raw Normal View History

2016-04-04 23:37:51 +08:00
import logging
2016-04-06 22:15:51 +08:00
import os
2016-04-04 23:37:51 +08:00
2016-04-05 15:51:04 +08:00
import h5py
from PyQt5 import QtCore, QtWidgets, QtGui
2016-04-04 23:37:51 +08:00
2016-04-18 23:10:40 +08:00
from artiq.protocols import pyon
2016-04-04 23:37:51 +08:00
logger = logging.getLogger(__name__)
2016-04-18 23:10:40 +08:00
def open_h5(info):
if not (info.isFile() and info.isReadable() and
info.suffix() == "h5"):
return
try:
f = h5py.File(info.filePath(), "r")
except:
logger.warning("unable to read HDF5 file %s", info.filePath(),
exc_info=True)
return
return f
2016-04-17 16:34:10 +08:00
class ThumbnailIconProvider(QtWidgets.QFileIconProvider):
2016-04-06 02:01:25 +08:00
def icon(self, info):
2016-04-06 18:16:40 +08:00
icon = self.hdf5_thumbnail(info)
if icon is None:
icon = QtWidgets.QFileIconProvider.icon(self, info)
return icon
def hdf5_thumbnail(self, info):
2016-04-18 23:10:40 +08:00
f = open_h5(info)
if not f:
2016-04-08 11:44:37 +08:00
return
with f:
try:
t = f["datasets/thumbnail"]
except KeyError:
return
try:
img = QtGui.QImage.fromData(t.value)
except:
2016-04-17 16:34:10 +08:00
logger.warning("unable to read thumbnail from %s",
info.filePath(), exc_info=True)
2016-04-06 18:16:40 +08:00
return
pix = QtGui.QPixmap.fromImage(img)
return QtGui.QIcon(pix)
2016-04-17 16:34:10 +08:00
class DirsOnlyProxy(QtCore.QSortFilterProxyModel):
def filterAcceptsRow(self, row, parent):
idx = self.sourceModel().index(row, 0, parent)
if not self.sourceModel().fileInfo(idx).isDir():
return False
return QtCore.QSortFilterProxyModel.filterAcceptsRow(self, row, parent)
2016-04-14 17:55:44 +08:00
class FilesDock(QtWidgets.QDockWidget):
2016-04-17 16:34:10 +08:00
def __init__(self, datasets, main_window, root=""):
2016-04-14 17:55:44 +08:00
QtWidgets.QDockWidget.__init__(self, "Files")
self.setObjectName("Files")
2016-04-20 03:59:02 +08:00
self.setFeatures(self.DockWidgetMovable | self.DockWidgetFloatable)
2016-04-10 16:22:24 +08:00
self.splitter = QtWidgets.QSplitter()
self.setWidget(self.splitter)
2016-04-05 15:51:04 +08:00
self.datasets = datasets
2016-04-10 20:07:46 +08:00
self.main_window = main_window
2016-04-05 15:51:04 +08:00
2016-04-17 16:34:10 +08:00
self.model = QtWidgets.QFileSystemModel()
self.model.setFilter(QtCore.QDir.Drives | QtCore.QDir.NoDotAndDotDot |
QtCore.QDir.AllDirs | QtCore.QDir.Files)
self.model.setNameFilterDisables(False)
self.model.setIconProvider(ThumbnailIconProvider())
2016-04-04 23:37:51 +08:00
self.rt = QtWidgets.QTreeView()
2016-04-17 16:34:10 +08:00
rt_model = DirsOnlyProxy()
rt_model.setDynamicSortFilter(True)
rt_model.setSourceModel(self.model)
self.rt.setModel(rt_model)
self.model.directoryLoaded.connect(
lambda: self.rt.resizeColumnToContents(0))
self.rt.setAnimated(False)
self.rt.setRootIndex(rt_model.mapFromSource(
self.model.setRootPath(root)))
self.rt.setSelectionBehavior(self.rt.SelectRows)
self.rt.setSelectionMode(self.rt.SingleSelection)
self.rt.selectionModel().currentChanged.connect(
2016-04-06 18:16:40 +08:00
self.tree_current_changed)
self.rt.setRootIsDecorated(False)
2016-04-17 16:34:10 +08:00
for i in range(1, 4):
self.rt.hideColumn(i)
2016-04-10 16:22:24 +08:00
self.splitter.addWidget(self.rt)
2016-04-05 16:05:53 +08:00
self.rl = QtWidgets.QListView()
2016-04-20 03:59:02 +08:00
self.rl.setViewMode(self.rl.IconMode)
l = QtGui.QFontMetrics(self.font()).lineSpacing()
2016-04-06 18:16:40 +08:00
self.rl.setIconSize(QtCore.QSize(20*l, 15*l))
2016-04-20 03:59:02 +08:00
self.rl.setFlow(self.rl.LeftToRight)
2016-04-06 18:16:40 +08:00
self.rl.setWrapping(True)
2016-04-17 16:34:10 +08:00
self.rl.setModel(self.model)
self.rl.selectionModel().currentChanged.connect(
self.list_current_changed)
2016-04-20 03:59:02 +08:00
self.rl.doubleClicked.connect(self.double_clicked)
2016-04-10 16:22:24 +08:00
self.splitter.addWidget(self.rl)
2016-04-06 18:16:40 +08:00
def tree_current_changed(self, current, previous):
2016-04-17 16:34:10 +08:00
idx = self.rt.model().mapToSource(current)
self.rl.setRootIndex(idx)
2016-04-06 18:16:40 +08:00
def list_current_changed(self, current, previous):
2016-04-17 16:34:10 +08:00
info = self.model.fileInfo(current)
2016-04-18 23:10:40 +08:00
f = open_h5(info)
if not f:
2016-04-08 11:54:49 +08:00
return
2016-04-20 03:59:02 +08:00
logger.info("loading datasets from %s", info.filePath())
2016-04-08 11:44:37 +08:00
with f:
2016-04-06 18:16:40 +08:00
rd = {}
2016-04-08 11:44:37 +08:00
try:
group = f["datasets"]
except KeyError:
2016-04-06 18:16:40 +08:00
return
2016-04-08 11:44:37 +08:00
for k in f["datasets"]:
2016-04-06 18:16:40 +08:00
rd[k] = True, group[k].value
self.datasets.init(rd)
2016-04-04 23:37:51 +08:00
2016-04-20 03:59:02 +08:00
def double_clicked(self, current):
2016-04-18 23:10:40 +08:00
info = self.model.fileInfo(current)
2016-04-20 03:59:02 +08:00
if info.isDir():
self.rl.setRootIndex(current)
idx = self.rt.model().mapFromSource(current)
self.rt.expand(idx)
self.rt.setCurrentIndex(idx)
return
2016-04-18 23:10:40 +08:00
f = open_h5(info)
if not f:
return
2016-04-20 03:59:02 +08:00
logger.info("loading experiment for %s", info.filePath())
2016-04-18 23:10:40 +08:00
with f:
expid = pyon.decode(f["expid"].value)
2016-04-17 16:34:10 +08:00
def select_dir(self, path):
if not os.path.exists(path):
return
idx = self.model.index(path)
self.rl.setRootIndex(idx)
def scroll_when_loaded(p):
if p != path:
return
self.model.directoryLoaded.disconnect(scroll_when_loaded)
QtCore.QTimer.singleShot(
100, lambda:
self.rt.scrollTo(self.rt.model().mapFromSource(
self.model.index(path)), self.rt.PositionAtCenter))
self.model.directoryLoaded.connect(scroll_when_loaded)
2016-04-20 03:59:02 +08:00
idx = self.rt.model().mapFromSource(idx)
self.rt.expand(idx)
self.rt.setCurrentIndex(idx)
2016-04-17 16:34:10 +08:00
def select_file(self, path):
if not os.path.exists(path):
return
self.select_dir(os.path.dirname(path))
self.rl.setCurrentIndex(self.model.index(path))
2016-04-04 23:37:51 +08:00
def save_state(self):
return {
2016-04-17 16:34:10 +08:00
"dir": self.model.filePath(self.rt.model().mapToSource(
self.rt.currentIndex())),
"file": self.model.filePath(self.rl.currentIndex()),
"header": bytes(self.rt.header().saveState()),
2016-04-10 16:22:24 +08:00
"splitter": bytes(self.splitter.saveState()),
2016-04-04 23:37:51 +08:00
}
def restore_state(self, state):
2016-04-17 16:34:10 +08:00
dir = state.get("dir")
if dir:
self.select_dir(dir)
file = state.get("file")
if file:
self.select_file(file)
header = state.get("header")
if header:
self.rt.header().restoreState(QtCore.QByteArray(header))
splitter = state.get("splitter")
if splitter:
self.splitter.restoreState(QtCore.QByteArray(splitter))