gui/explorer: file selector for experiments outside repos

This commit is contained in:
Sebastien Bourdeauducq 2015-12-09 19:13:57 +08:00
parent 7b2580583a
commit 93317d48c9
4 changed files with 118 additions and 26 deletions

View File

@ -98,7 +98,7 @@ def get_argparser():
parser_ls = subparsers.add_parser( parser_ls = subparsers.add_parser(
"ls", help="list a directory on the master") "ls", help="list a directory on the master")
parser_ls.add_argument("directory") parser_ls.add_argument("directory", default="", nargs="?")
return parser return parser
@ -160,11 +160,8 @@ def _action_scan_repository(remote, args):
def _action_ls(remote, args): def _action_ls(remote, args):
contents = remote.list_directory(args.directory) contents = remote.list_directory(args.directory)
for name, is_dir in sorted(contents, key=lambda x: (-x[1], x[0])): for name in sorted(contents, key=lambda x: (x[-1] not in "\\/", x)):
if is_dir: print(name)
print("<DIR> " + name)
else:
print(" " + name)
def _show_schedule(schedule): def _show_schedule(schedule):

View File

@ -13,36 +13,102 @@ logger = logging.getLogger(__name__)
class _OpenFileDialog(QtGui.QDialog): class _OpenFileDialog(QtGui.QDialog):
def __init__(self, parent, exp_manager): def __init__(self, explorer, exp_manager, experiment_db_ctl):
QtGui.QDialog.__init__(self, parent=parent) QtGui.QDialog.__init__(self, parent=explorer)
self.resize(710, 700)
self.setWindowTitle("Open file outside repository") self.setWindowTitle("Open file outside repository")
self.explorer = explorer
self.exp_manager = exp_manager self.exp_manager = exp_manager
self.experiment_db_ctl = experiment_db_ctl
grid = QtGui.QGridLayout() grid = QtGui.QGridLayout()
self.setLayout(grid) self.setLayout(grid)
grid.addWidget(QtGui.QLabel("Filename:"), 0, 0) grid.addWidget(QtGui.QLabel("Location:"), 0, 0)
self.filename = QtGui.QLineEdit() self.location_label = QtGui.QLabel("")
grid.addWidget(self.filename, 0, 1) grid.addWidget(self.location_label, 0, 1)
grid.setColumnStretch(1, 1)
self.file_list = QtGui.QListWidget()
asyncio.ensure_future(self.refresh_view())
grid.addWidget(self.file_list, 1, 0, 1, 2)
self.file_list.doubleClicked.connect(self.accept)
buttons = QtGui.QDialogButtonBox( buttons = QtGui.QDialogButtonBox(
QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel) QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel)
grid.addWidget(buttons, 1, 0, 1, 2) grid.addWidget(buttons, 2, 0, 1, 2)
buttons.accepted.connect(self.accept) buttons.accepted.connect(self.accept)
buttons.rejected.connect(self.reject) buttons.rejected.connect(self.reject)
self.accepted.connect(self.open_file) async def refresh_view(self):
self.file_list.clear()
if not self.explorer.current_directory:
self.location_label.setText("<root>")
else:
self.location_label.setText(self.explorer.current_directory)
def open_file(self): item = QtGui.QListWidgetItem()
file = self.filename.text() item.setText("..")
async def open_task(): item.setIcon(QtGui.QApplication.style().standardIcon(
try: QtGui.QStyle.SP_FileDialogToParent))
await self.exp_manager.open_file(file) self.file_list.addItem(item)
except:
logger.error("Failed to open file '%s'", try:
file, exc_info=True) contents = await self.experiment_db_ctl.list_directory(
asyncio.ensure_future(open_task()) self.explorer.current_directory)
except:
logger.error("Failed to list directory '%s'",
self.explorer.current_directory, exc_info=True)
self.explorer.current_directory = ""
for name in sorted(contents, key=lambda x: (x[-1] not in "\\/", x)):
if name[-1] in "\\/":
icon = QtGui.QStyle.SP_DirIcon
else:
icon = QtGui.QStyle.SP_FileIcon
if name[-3:] != ".py":
continue
item = QtGui.QListWidgetItem()
item.setText(name)
item.setIcon(QtGui.QApplication.style().standardIcon(icon))
self.file_list.addItem(item)
def accept(self):
selected = self.file_list.selectedItems()
if selected:
selected = selected[0].text()
if selected == "..":
if (not self.explorer.current_directory
or self.explorer.current_directory[-1] not in "\\/"):
return
idx = None
for sep in "\\/":
try:
idx = self.explorer.current_directory[:-1].rindex(sep)
except ValueError:
pass
else:
break
if idx is None:
return
self.explorer.current_directory = \
self.explorer.current_directory[:idx+1]
if self.explorer.current_directory == "/":
self.explorer.current_directory = ""
asyncio.ensure_future(self.refresh_view())
elif selected[-1] in "\\/":
self.explorer.current_directory += selected
asyncio.ensure_future(self.refresh_view())
else:
file = self.explorer.current_directory + selected
async def open_task():
try:
await self.exp_manager.open_file(file)
except:
logger.error("Failed to open file '%s'",
file, exc_info=True)
asyncio.ensure_future(open_task())
QtGui.QDialog.accept(self)
class Model(DictSyncTreeSepModel): class Model(DictSyncTreeSepModel):
@ -127,10 +193,12 @@ 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)
self.current_directory = ""
open_file_action = QtGui.QAction("Open file outside repository", open_file_action = QtGui.QAction("Open file outside repository",
self.el) self.el)
open_file_action.triggered.connect( open_file_action.triggered.connect(
lambda: _OpenFileDialog(self, self.exp_manager).open()) lambda: _OpenFileDialog(self, self.exp_manager,
experiment_db_ctl).open())
self.el.addAction(open_file_action) self.el.addAction(open_file_action)
def set_model(self, model): def set_model(self, model):

View File

@ -7,7 +7,7 @@ from functools import partial
from artiq.protocols.sync_struct import Notifier from artiq.protocols.sync_struct import Notifier
from artiq.master.worker import Worker from artiq.master.worker import Worker
from artiq.tools import exc_to_warning from artiq.tools import get_windows_drives, exc_to_warning
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -130,7 +130,21 @@ class ExperimentDB:
return description return description
def list_directory(self, directory): def list_directory(self, directory):
return [(de.name, de.is_dir()) for de in os.scandir(directory)] r = []
prefix = ""
if not directory:
if os.name == "nt":
drives = get_windows_drives()
return [drive + ":\\" for drive in drives]
else:
directory = "/"
prefix = "/"
for de in os.scandir(directory):
if de.is_dir():
r.append(prefix + de.name + os.path.sep)
else:
r.append(prefix + de.name)
return r
class FilesystemBackend: class FilesystemBackend:

View File

@ -8,6 +8,7 @@ import time
import collections import collections
import os import os
import atexit import atexit
import string
import numpy as np import numpy as np
@ -18,7 +19,7 @@ from artiq.protocols import pyon
__all__ = ["artiq_dir", "parse_arguments", "elide", "short_format", "file_import", __all__ = ["artiq_dir", "parse_arguments", "elide", "short_format", "file_import",
"get_experiment", "verbosity_args", "simple_network_args", "init_logger", "get_experiment", "verbosity_args", "simple_network_args", "init_logger",
"atexit_register_coroutine", "exc_to_warning", "asyncio_wait_or_cancel", "atexit_register_coroutine", "exc_to_warning", "asyncio_wait_or_cancel",
"TaskObject", "Condition", "workaround_asyncio263"] "TaskObject", "Condition", "workaround_asyncio263", "get_windows_drives"]
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -198,3 +199,15 @@ class Condition:
@asyncio.coroutine @asyncio.coroutine
def workaround_asyncio263(): def workaround_asyncio263():
yield yield
def get_windows_drives():
from ctypes import windll
drives = []
bitmask = windll.kernel32.GetLogicalDrives()
for letter in string.ascii_uppercase:
if bitmask & 1:
drives.append(letter)
bitmask >>= 1
return drives