Skip to content

Commit

Permalink
gui/explorer: file selector for experiments outside repos
Browse files Browse the repository at this point in the history
sbourdeauducq committed Dec 9, 2015
1 parent 7b25805 commit 93317d4
Showing 4 changed files with 119 additions and 27 deletions.
9 changes: 3 additions & 6 deletions artiq/frontend/artiq_client.py
Original file line number Diff line number Diff line change
@@ -98,7 +98,7 @@ def get_argparser():

parser_ls = subparsers.add_parser(
"ls", help="list a directory on the master")
parser_ls.add_argument("directory")
parser_ls.add_argument("directory", default="", nargs="?")

return parser

@@ -160,11 +160,8 @@ def _action_scan_repository(remote, args):

def _action_ls(remote, args):
contents = remote.list_directory(args.directory)
for name, is_dir in sorted(contents, key=lambda x: (-x[1], x[0])):
if is_dir:
print("<DIR> " + name)
else:
print(" " + name)
for name in sorted(contents, key=lambda x: (x[-1] not in "\\/", x)):
print(name)


def _show_schedule(schedule):
104 changes: 86 additions & 18 deletions artiq/gui/explorer.py
Original file line number Diff line number Diff line change
@@ -13,36 +13,102 @@


class _OpenFileDialog(QtGui.QDialog):
def __init__(self, parent, exp_manager):
QtGui.QDialog.__init__(self, parent=parent)
def __init__(self, explorer, exp_manager, experiment_db_ctl):
QtGui.QDialog.__init__(self, parent=explorer)
self.resize(710, 700)
self.setWindowTitle("Open file outside repository")

self.explorer = explorer
self.exp_manager = exp_manager
self.experiment_db_ctl = experiment_db_ctl

grid = QtGui.QGridLayout()
self.setLayout(grid)

grid.addWidget(QtGui.QLabel("Filename:"), 0, 0)
self.filename = QtGui.QLineEdit()
grid.addWidget(self.filename, 0, 1)
grid.addWidget(QtGui.QLabel("Location:"), 0, 0)
self.location_label = QtGui.QLabel("")
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(
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.rejected.connect(self.reject)

self.accepted.connect(self.open_file)

def open_file(self):
file = self.filename.text()
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())
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)

item = QtGui.QListWidgetItem()
item.setText("..")
item.setIcon(QtGui.QApplication.style().standardIcon(
QtGui.QStyle.SP_FileDialogToParent))
self.file_list.addItem(item)

try:
contents = await self.experiment_db_ctl.list_directory(
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):
@@ -127,10 +193,12 @@ def scan_repository():
scan_repository_action.triggered.connect(scan_repository)
self.el.addAction(scan_repository_action)

self.current_directory = ""
open_file_action = QtGui.QAction("Open file outside repository",
self.el)
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)

def set_model(self, model):
18 changes: 16 additions & 2 deletions artiq/master/experiments.py
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@

from artiq.protocols.sync_struct import Notifier
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__)
@@ -130,7 +130,21 @@ async def examine(self, filename, use_repository=True):
return description

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:
15 changes: 14 additions & 1 deletion artiq/tools.py
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
import collections
import os
import atexit
import string

import numpy as np

@@ -18,7 +19,7 @@
__all__ = ["artiq_dir", "parse_arguments", "elide", "short_format", "file_import",
"get_experiment", "verbosity_args", "simple_network_args", "init_logger",
"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__)
@@ -198,3 +199,15 @@ def notify(self):
@asyncio.coroutine
def workaround_asyncio263():
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

0 comments on commit 93317d4

Please sign in to comment.