Source code for sdt.nbui.file_dialog
# SPDX-FileCopyrightText: 2020 Lukas Schrangl <lukas.schrangl@tuwien.ac.at>
#
# SPDX-License-Identifier: BSD-3-Clause
from pathlib import Path
import ipywidgets
import traitlets
[docs]class FileDialog(ipywidgets.VBox):
"""File selection dialog"""
cur_dir = traitlets.Any()
"""Current directory"""
selected = traitlets.List()
"""List of selected files"""
def __init__(self, cur_dir=Path(), *args, **kwargs):
"""Parameters
----------
cur_dir : Path
Current directory
*args, **kwargs
Passed to super class constructor
"""
self._start_button = ipywidgets.Button(description="Select files…")
self._start_button.on_click(self._show_dialog)
self._dir_button_box = ipywidgets.HBox()
self._dir_list = ipywidgets.Select()
self._file_list = ipywidgets.SelectMultiple()
self._ok_button = ipywidgets.Button(description="OK")
self._ok_button.on_click(self._ok_pressed)
self._cancel_button = ipywidgets.Button(description="Cancel")
self._cancel_button.on_click(self._cancel_pressed)
self._dialog_box = ipywidgets.VBox([
ipywidgets.Label(value="Current folder"),
self._dir_button_box,
ipywidgets.HBox([
ipywidgets.VBox([
ipywidgets.Label(value="Choose subfolder"),
self._dir_list
]),
ipywidgets.VBox([ipywidgets.Label(value="Select files"),
self._file_list])
]),
ipywidgets.HBox([self._ok_button, self._cancel_button])
], layout=ipywidgets.Layout(display="none"))
super().__init__([self._start_button, self._dialog_box],
*args, **kwargs)
self._ignore_dir_selected = False
self._dir_list.observe(self._dir_selected, "value")
self.cur_dir = cur_dir
@traitlets.validate("cur_dir")
def _validate_cur_dir(self, proposal):
return Path(proposal["value"]).resolve()
@traitlets.observe("cur_dir")
def _cur_dir_changed(self, change=None):
self._set_tmp_cwd(self.cur_dir)
def _set_tmp_cwd(self, tmp_cwd):
"""Set temporay cur dir and update widgets
Parameters
----------
tmp_cwd : Path
New temp directory
"""
self._tmp_cwd = tmp_cwd
files = []
dirs = []
for p in self._tmp_cwd.iterdir():
if p.name.startswith("."):
continue
if p.is_dir():
dirs.append(str(p.relative_to(self._tmp_cwd)))
else:
files.append(str(p.relative_to(self._tmp_cwd)))
self._file_list.options = sorted(files)
try:
self._ignore_dir_selected = True
self._dir_list.options = sorted(dirs)
self._dir_list.value = None
except Exception:
raise
finally:
self._ignore_dir_selected = False
btns = []
for p in self._tmp_cwd.parts:
b = ipywidgets.Button(description=p,
layout=ipywidgets.Layout(width="auto"))
b.on_click(self._dir_button_clicked)
btns.append(b)
self._dir_button_box.children = btns
def _dir_button_clicked(self, button):
"""Called when one of the "current folder" buttons is clicked"""
bbc = self._dir_button_box.children
idx = bbc.index(button)
if idx == len(bbc) - 1:
# Last button ==> current dir, do nothing
return
self._set_tmp_cwd(self._tmp_cwd.parents[len(bbc) - idx - 2])
def _show_dialog(self, button=None):
"""Show the dialog"""
self._start_button.layout = ipywidgets.Layout(display="none")
self._dialog_box.layout = ipywidgets.Layout(display="inline")
def _dir_selected(self, change=None):
"""Called when a subdir was selected from the list"""
if self._ignore_dir_selected:
return
self._set_tmp_cwd(self._tmp_cwd / self._dir_list.value)
def _ok_pressed(self, button=None):
"""OK button pressed after selection"""
self._start_button.layout = ipywidgets.Layout(display="inline")
self._dialog_box.layout = ipywidgets.Layout(display="none")
self.selected = [self._tmp_cwd / s for s in self._file_list.value]
self.cur_dir = self._tmp_cwd
def _cancel_pressed(self, button=None):
"""Cancel button pressed"""
self._start_button.layout = ipywidgets.Layout(display="inline")
self._dialog_box.layout = ipywidgets.Layout(display="none")
self._set_tmp_cwd(self.cur_dir)