diff --git a/artiq/browser/datasets.py b/artiq/browser/datasets.py index 6784d18aa..4f49c1ba5 100644 --- a/artiq/browser/datasets.py +++ b/artiq/browser/datasets.py @@ -43,8 +43,20 @@ class DatasetsDock(QtWidgets.QDockWidget): QtWidgets.QAbstractItemView.SingleSelection) grid.addWidget(self.table, 1, 0) + metadata_grid = LayoutWidget() + self.metadata = {} + for i, label in enumerate("artiq_version repo_rev file class_name " + "rid start_time".split()): + metadata_grid.addWidget(QtWidgets.QLabel(label), i, 0) + v = QtWidgets.QLabel() + v.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse) + metadata_grid.addWidget(v, i, 1) + self.metadata[label] = v + grid.addWidget(metadata_grid, 2, 0) + self.table.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) - upload_action = QtWidgets.QAction("Upload dataset to master", self.table) + upload_action = QtWidgets.QAction("Upload dataset to master", + self.table) upload_action.triggered.connect(self.upload_clicked) self.table.addAction(upload_action) @@ -59,6 +71,10 @@ class DatasetsDock(QtWidgets.QDockWidget): self.table_model_filter.setFilterFixedString( self.search.displayText()) + def metadata_changed(self, new): + for k, v in new.items(): + self.metadata[k].setText("{}".format(v)) + def set_model(self, model): self.table_model = model self.table_model_filter = QtCore.QSortFilterProxyModel() diff --git a/artiq/browser/files.py b/artiq/browser/files.py index 2eb43bc9e..4273c97a5 100644 --- a/artiq/browser/files.py +++ b/artiq/browser/files.py @@ -118,8 +118,9 @@ class Hdf5FileSystemModel(QtWidgets.QFileSystemModel): class FilesDock(QtWidgets.QDockWidget): dataset_activated = QtCore.pyqtSignal(str) dataset_changed = QtCore.pyqtSignal(str) + metadata_changed = QtCore.pyqtSignal(dict) - def __init__(self, datasets, browse_root="", select=None): + def __init__(self, datasets, browse_root="", restore_selection=True): QtWidgets.QDockWidget.__init__(self, "Files") self.setObjectName("Files") self.setFeatures(self.DockWidgetMovable | self.DockWidgetFloatable) @@ -168,13 +169,7 @@ class FilesDock(QtWidgets.QDockWidget): rev_copy.setShortcutContext(QtCore.Qt.WidgetShortcut) self.rl.addAction(rev_copy) - self.restore_selected = select is None - if select is not None: - f = os.path.abspath(select) - if os.path.isdir(f): - self.select_dir(f) - else: - self.select_file(f) + self.restore_selection = restore_selection def _copy_repo_rev(self): pass @@ -190,10 +185,24 @@ class FilesDock(QtWidgets.QDockWidget): return logger.debug("loading datasets from %s", info.filePath()) with f: - if "datasets" not in f: - return - rd = {k: (True, v.value) for k, v in f["datasets"].items()} - self.datasets.init(rd) + try: + expid = pyon.decode(f["expid"].value) + start_time = datetime.fromtimestamp(f["start_time"].value) + v = { + "artiq_version": f["artiq_version"].value, + "repo_rev": expid["repo_rev"], + "file": expid["file"], + "class_name": expid["class_name"], + "rid": f["rid"].value, + "start_time": start_time, + } + self.metadata_changed.emit(v) + except: + logger.warning("unable to read metadata from %s", + info.filePath(), exc_info=True) + if "datasets" in f: + rd = {k: (True, v.value) for k, v in f["datasets"].items()} + self.datasets.init(rd) self.dataset_changed.emit(info.filePath()) def list_activated(self, idx): @@ -206,6 +215,13 @@ class FilesDock(QtWidgets.QDockWidget): self.rt.expand(idx) self.rt.setCurrentIndex(idx) + def select(self, path): + f = os.path.abspath(path) + if os.path.isdir(f): + self.select_dir(f) + else: + self.select_file(f) + def select_dir(self, path): if not os.path.exists(path): return @@ -247,7 +263,7 @@ class FilesDock(QtWidgets.QDockWidget): } def restore_state(self, state): - if self.restore_selected: + if self.restore_selection: self.select_dir(state["dir"]) self.select_file(state["file"]) self.splitter.restoreState(QtCore.QByteArray(state["splitter"])) diff --git a/artiq/frontend/artiq_browser.py b/artiq/frontend/artiq_browser.py index 069a23127..5cc0624dd 100755 --- a/artiq/frontend/artiq_browser.py +++ b/artiq/frontend/artiq_browser.py @@ -45,7 +45,7 @@ def get_argparser(): class Browser(QtWidgets.QMainWindow): - def __init__(self, smgr, datasets_sub, browse_root, select, + def __init__(self, smgr, datasets_sub, browse_root, restore_selection, master_host, master_port): QtWidgets.QMainWindow.__init__(self) smgr.register(self) @@ -70,7 +70,8 @@ class Browser(QtWidgets.QMainWindow): QtCore.Qt.ScrollBarAsNeeded) self.setCentralWidget(self.experiments) - self.files = files.FilesDock(datasets_sub, browse_root, select=select) + self.files = files.FilesDock(datasets_sub, browse_root, + restore_selection) smgr.register(self.files) self.files.dataset_activated.connect( @@ -85,6 +86,7 @@ class Browser(QtWidgets.QMainWindow): self.datasets = datasets.DatasetsDock( datasets_sub, master_host, master_port) smgr.register(self.datasets) + self.files.metadata_changed.connect(self.datasets.metadata_changed) self.log = log.LogDock(None, "log") smgr.register(self.log) @@ -145,20 +147,24 @@ def main(): smgr = state.StateManager(args.db_file) - main_window = Browser(smgr, datasets_sub, args.browse_root, - args.select, args.server, args.port) - widget_log_handler.callback = main_window.log.append_message + browser = Browser(smgr, datasets_sub, args.browse_root, + args.select is not None, args.server, + args.port) + widget_log_handler.callback = browser.log.append_message + + if args.select is not None: + browser.files.select(args.select) if os.name == "nt": # HACK: show the main window before creating applets. # Otherwise, the windows of those applets that are in detached # QDockWidgets fail to be embedded. - main_window.show() + browser.show() smgr.load() smgr.start() atexit_register_coroutine(smgr.stop) - main_window.show() - loop.run_until_complete(main_window.exit_request.wait()) + browser.show() + loop.run_until_complete(browser.exit_request.wait()) if __name__ == "__main__":